import pandas as pd df = pd.DataFrame(data=None, index=None, columns=None, dtype=None, copy=None)
data=None
- принимает numpy.ndarray
(структурированный или однородный), Iterable
, dict
или DataFrame
. Словарь dict
может содержать серии, массивы, константы, классы данных или объекты, подобные спискам. Если данные представляют собой словарь, то порядок столбцов соответствует порядку вставки. Если словарь содержит серии, то для которых определен индекс, он выравнивается по индексу. Это выравнивание также происходит, если данные представляют собой серию или сам DataFrame
. Выравнивание выполняется для входных данных Series
/DataFrame
.index=None
- принимает pandas.Index()
или массив. Метки строк, которые будут использоваться для результирующего DataFrame
. По умолчанию будет RangeIndex(0, 1, 2, …, n)
, если во входных данных отсутствует информация об индексировании (не указан индекс).columns=None
- принимает pandas.Index()
или массив. Метки столбцов, которые будут использоваться для результирующего DataFrame
, когда данные их не содержат. По умолчанию используется RangeIndex(0, 1, 2, …, n)
. Если данные содержат метки столбцов, то будет выполнен выбор этих меток.dtype=None
- принимает dtype
из numpy
. Тип данных для принудительного использования во всем DataFrame
. Допускается только один тип dtype
. Если это неприемлемо, то лучше оставить None
.copy=None
- принимает bool
. Копирует входные данные. Для данных из dict
, при значении по умолчанию None
ведет себя как copy=True
. Для данных DataFrame
или 2d numpy.ndarray
при значении по умолчанию None
ведет себя как copy=False
. Если данные представляют собой словарь, содержащий одну или несколько серий (возможно, разных типов), copy=False
гарантирует, что эти входные данные не будут скопированы.
Аргумент
copy
изменит поведение в pandas 3.0. Копирование при записи будет включено по умолчанию, а это означает, что все методы с аргументомcopy
будут использовать механизм отложенного копирования и игнорировать аргументcopy
. Ключевой аргументcopy
будет удален в будущей версииpandas
. Можно уже сейчас получить будущее поведение и улучшения, включив копирование при записиpd.options.mode.copy_on_write = True
DataFrame
Объект pandas.DataFrame()
представляет собой первичную двумерную структуру данных pandas
, изменяемую по размеру, содержащую потенциально разнородные табличные данные.
Структура DataFrame
также содержит помеченные оси (строки и столбцы). Арифметические операции выравниваются как по меткам строк, так и по столбцам. DataFrame
можно рассматривать как dict
-подобный контейнер для объектов pandas.Series
.
DataFrame
DataFrame
- это двумерная помеченная структура данных со столбцами потенциально разных типов. О ней можно думать как об электронной таблице, таблице SQL или наборе объектов Series
. Как правило, это наиболее часто используемый объект библиотеки panda
. Как и Series
, DataFrame
принимает множество различных типов входных данных:
numpy.ndarray
;Series
;numpy.ndarray
;numpy.ndarray
- это массив, тип данных которых представляет собой композицию более простых типов данных, организованных в виде последовательности;pandas.Series
;pandas.DataFrame
.Вместе с данными можно дополнительно передать индексы (метки строк) и столбца (метки столбца) при помощи соответствующих аргументов index
и columns
. Если передать индексы, то гарантируется установка переданных меток строк и столбцов результирующего DataFrame
. Таким образом, сочетание Series
с определенным индексом отбросит все данные, не соответствующие переданному индексу. Результирующий индекс будет объединением индексов различных серий. Смотрим о чем идет речь:
>>> import pandas as pd >>> import numpy as np # допусти есть словарь, содержащий серии # с различным количеством элементов d = { "one": pd.Series([1.0, 2.0, 3.0], index=["a", "b", "c"]), "two": pd.Series([1.0, 2.0, 3.0, 4.0], index=["a", "b", "c", "d"]), } # создаем `DataFrame` >>> df = pd.DataFrame(d) # обратите внимание как объединились серии >>> df # one two # a 1.0 1.0 # b 2.0 2.0 # c 3.0 3.0 # d NaN 4.0 # при создании `DataFrame` передадим `index` # произойдет выравнивание данных по меткам строк >>> pd.DataFrame(d, index=["d", "b", "a"]) # one two # d NaN 4.0 # b 2.0 2.0 # a 1.0 1.0 # теперь дополнительно передадим метки столбцов, # произойдет выравнивание данных по меткам строк и столбцов >>> pd.DataFrame(d, index=["d", "b", "a"], columns=["two", "three"]) # two three # d 4.0 NaN # b 2.0 NaN # a 1.0 NaN
Если метки осей не переданы, то они будут созданы из входных данных на основе правил здравого смысла.
Доступ к меткам строк и столбцов можно получить соответственно, обратившись к атрибутам индекса df.index
и столбца df.columns
:
Когда вместе с набором данных передается определенный набор столбцов, то переданные столбцы переопределяют ключи в словаре.
>>> df.index # Index(['a', 'b', 'c', 'd'], dtype='object') >>> df.columns # Index(['one', 'two'], dtype='object')
DataFrame
из разных структур данныхDataFrame
из словаря содержащего numpy.ndarray
или спискиВсе numpy.ndarray
должны быть одинаковой длины. Если передается индекс, то он также должен быть той же длины, что и массивы. Если индекс не передается, то результатом будет диапазон (n
), где n
- длина массива.
>>> d = {"one": [1.0, 2.0, 3.0, 4.0], "two": [4.0, 3.0, 2.0, 1.0]} # метки строк создаются автоматически >>> pd.DataFrame(d) # one two # 0 1.0 4.0 # 1 2.0 3.0 # 2 3.0 2.0 # 3 4.0 1.0 # метки строк передаются при создании >>> pd.DataFrame(d, index=["a", "b", "c", "d"]) # one two # a 1.0 4.0 # b 2.0 3.0 # c 3.0 2.0 # d 4.0 1.0
В качестве альтернативы можно использовать метод DataFrame.from_dict()
, который принимает принимает словарь, состоящий из словарей или состоящий из массивоподобных последовательностей. Он работает как конструктор DataFrame
, за исключением аргумента orient
, который по умолчанию имеет значение 'columns'
, но для которого можно установить значение 'index'
, с целью использования ключей словаря в качестве меток строк.
pd.DataFrame.from_dict(dict([("A", [1, 2, 3]), ("B", [4, 5, 6])])) # A B # 0 1 4 # 1 2 5 # 2 3 6
Если передать orient='index'
, то ключи будут метками строк. В этом случае еще можно передать нужные имена столбцов:
>>> pd.DataFrame.from_dict( ... dict([("A", [1, 2, 3]), ("B", [4, 5, 6])]), ... orient="index", ... columns=["one", "two", "three"], ... ) # one two three # A 1 2 3 # B 4 5 6
DataFrame
из структурированного массива или массива записей>>> import numpy as np >>> data = np.zeros((2,), dtype=[("A", "i4"), ("B", "f4"), ("C", "a10")]) >>> data[:] = [(1, 2.0, "Hello"), (2, 3.0, "World")] >>> pd.DataFrame(data) # A B C # 0 1 2.0 b'Hello' # 1 2 3.0 b'World' >>> pd.DataFrame(data, index=["first", "second"]) # A B C # first 1 2.0 b'Hello' # second 2 3.0 b'World' >>> pd.DataFrame(data, columns=["C", "A", "B"]) # C A B # 0 b'Hello' 1 2.0 # 1 b'World' 2 3.0
Замечание.
DataFrame
не предназначен для работы точно так же, как двумерныйnumpy.ndarray
.
В качестве альтернативы можно использовать метод DataFrame.from_records()
, который принимает список кортежей или numpy.ndarray
со структурированным типом dtype
. Он работает аналогично обычному конструктору DataFrame
, за исключением того, что результирующий индекс DataFrame
может быть конкретным полем структурированного типа dtype
.
>>> data # array([(1, 2., b'Hello'), (2, 3., b'World')], # dtype=[('A', '<i4'), ('B', '<f4'), ('C', 'S10')]) >>> pd.DataFrame.from_records(data, index="C") # A B # C # b'Hello' 1 2.0 # b'World' 2 3.0
DataFrame
из списка словарей>>> data2 = [{"a": 1, "b": 2}, {"a": 5, "b": 10, "c": 20}] # При создании `DataFrame` данные выравниваются >>> pd.DataFrame(data2) # a b c # 0 1 2 NaN # 1 5 10 20.0 # создаем метки строк согласно аргументу `index` >>> pd.DataFrame(data2, index=["first", "second"]) # a b c # first 1 2 NaN # second 5 10 20.0 # данные в `DataFrame` попадут согласно # меткам запрашиваемых в `columns` >>> pd.DataFrame(data2, columns=["a", "b"]) # a b # 0 1 2 # 1 5 10
DataFrame
из словаря кортежейМожно автоматически создать многоиндексный фрейм, передав словарь кортежей.
>>> pd.DataFrame( ... { ... ("a", "b"): {("A", "B"): 1, ("A", "C"): 2}, ... ("a", "a"): {("A", "C"): 3, ("A", "B"): 4}, ... ("a", "c"): {("A", "B"): 5, ("A", "C"): 6}, ... ("b", "a"): {("A", "C"): 7, ("A", "B"): 8}, ... ("b", "b"): {("A", "D"): 9, ("A", "B"): 10}, ... } ... ) # a b # b a c a b # A B 1.0 4.0 5.0 8.0 10.0 # C 2.0 3.0 6.0 7.0 NaN # D NaN NaN NaN NaN 9.0
DataFrame
из Series
Результатом будет DataFrame
с тем же индексом, что и входная серия, и с одним столбцом, имя которого является исходным именем серии (только если не указано другое имя столбца).
>>> ser = pd.Series(range(3), index=list("abc"), name="ser") >>> ser # a 0 # b 1 # c 2 # Name: ser, dtype: int64 >>> pd.DataFrame(ser) # ser # a 0 # b 1 # c 2
DataFrame
из списка именованных кортежейИмена полей первого именованного кортежа в списке определяют столбцы DataFrame
. Остальные именованные кортежи (или кортежи) просто распаковываются, и их значения передаются в строки DataFrame
. Если какой-либо из этих кортежей короче первого именованного кортежа, то последующие столбцы в соответствующей строке помечаются как пропущенные значения NaN
. Если какой-либо из них длиннее первого именованного кортежа, возникает ошибка ValueError
.
>>> from collections import namedtuple >>> Point = namedtuple("Point", "x y") >>> pd.DataFrame([Point(0, 0), Point(0, 3), (2, 3)]) # x y # 0 0 0 # 1 0 3 # 2 2 3 >>> Point3D = namedtuple("Point3D", "x y z") >>> pd.DataFrame([Point3D(0, 0, 0), Point3D(0, 3, 5), Point(2, 3)]) # x y z # 0 0 0 0.0 # 1 0 3 5.0 # 2 2 3 NaN
DataFrame
из списка классов данныхКлассы данных можно передавать в конструктор DataFrame
. Передача списка классов данных эквивалентна передаче списка словарей.
Необходимо иметь в виду, что все значения в списке должны быть классами данных, смешивание типов в списке приведет к ошибке
TypeError
.
>>> from dataclasses import make_dataclass >>> Point = make_dataclass("Point", [("x", int), ("y", int)]) >>> pd.DataFrame([Point(0, 0), Point(0, 3), Point(2, 3)]) # x y # 0 0 0 # 1 0 3 # 2 2 3
Можно относиться к DataFrame
как к набору объектов Series
с одинаковым индексом строк. Получение, установка и удаление столбцов работает с тем же синтаксисом, что и аналогичные операции словарей dict
:
>>> df["one"] # a 1.0 # b 2.0 # c 3.0 # d NaN # Name: one, dtype: float64 # создание столбца "three", значение которого будут # результатом векторного умножения df["one"] * df["two"] >>> df["three"] = df["one"] * df["two"] # создание столбца "flag", значение которого логическими # т.е. результат векторного сравнения df["one"] > 2 >>> df["flag"] = df["one"] > 2 # смотрим >>> df # one two three flag # a 1.0 1.0 1.0 False # b 2.0 2.0 4.0 False # c 3.0 3.0 9.0 True # d NaN 4.0 NaN False
Столбцы можно удалять или выталкивать, как с помощью операций dict
:
# удаление столбца "two" >>> del df["two"] # удаление столбца "three" с # сохранением в переменную >>> three = df.pop("three") >>> df # one flag # a 1.0 False # b 2.0 False # c 3.0 True # d NaN False
При вставке скалярного значения оно естественным образом будет распространяться на все строки, заполняя столбец:
>>> df["foo"] = "bar" >>> df one flag foo a 1.0 False bar b 2.0 False bar c 3.0 True bar d NaN False bar
При вставке серии pandas.Series
, которая не имеет того же индекса, что и DataFrame
, она Series
будет приведена в соответствие с индексом DataFrame
:
# добавим столбец "one_trunc", значения которому # присваиваются из среза строк столбца "one" >>> df["one_trunc"] = df["one"][:2] # видим пропущенные значения >>> df one flag foo one_trunc a 1.0 False bar 1.0 b 2.0 False bar 2.0 c 3.0 True bar NaN d NaN False bar NaN
Можно вставлять необработанные массивы ndarray
, но их длина должна соответствовать длине индекса DataFrame
. По умолчанию столбцы вставляются в конец. Метод DataFrame.insert(loc, column, value)
вставляет столбцы в определенное место. Метод принимает loc
- индекс местоположения (0 <= loc <= len(column)
); column
- индексную метку нового столбца; value
- массив значений или скаляр.
Смотрим:
>>> df.insert(1, "bar", df["one"]) >>> df # one bar flag foo one_trunc # a 1.0 1.0 False bar 1.0 # b 2.0 2.0 False bar 2.0 # c 3.0 3.0 True bar NaN # d NaN NaN False bar NaN
DataFrame.assign()
добавление новых столбцов в цепочках методовPandas
имеет метод DataFrame.assign()
, который позволяет легко создавать новые столбцы, которые потенциально могут быть производными от существующих столбцов. DataFrame.assign()
всегда возвращает КОПИЮ ДАННЫХ, оставляя исходный DataFrame
нетронутым.
# загрузим данные по URL url = ( "https://raw.githubusercontent.com/pandas-dev" "/pandas/main/pandas/tests/io/data/csv/tips.csv" ) >>> tips = pd.read_csv(url) >>> tips.head() # total_bill tip sex smoker day time size # 0 16.99 1.01 Female No Sun Dinner 2 # 1 10.34 1.66 Male No Sun Dinner 3 # 2 21.01 3.50 Male No Sun Dinner 3 # 3 23.68 3.31 Male No Sun Dinner 2 # 4 24.59 3.61 Female No Sun Dinner 4 >>> tips.assign(sepal_ratio=tips["total_bill"] / tips["size"]).head() # total_bill tip sex smoker day time size sepal_ratio # 0 16.99 1.01 Female No Sun Dinner 2 8.495000 # 1 10.34 1.66 Male No Sun Dinner 3 3.446667 # 2 21.01 3.50 Male No Sun Dinner 3 7.003333 # 3 23.68 3.31 Male No Sun Dinner 2 11.840000 # 4 24.59 3.61 Female No Sun Dinner 4 6.147500
В приведенном выше примере было вставлено предварительно вычисленное значение. Также можно передать функцию с одним аргументом, который будет вычислен для назначаемого фрейма данных.
>>> tips.assign(sepal_ratio=lambda x: (x["total_bill"] / x["size"])).head() # total_bill tip sex smoker day time size sepal_ratio # 0 16.99 1.01 Female No Sun Dinner 2 8.495000 # 1 10.34 1.66 Male No Sun Dinner 3 3.446667 # 2 21.01 3.50 Male No Sun Dinner 3 7.003333 # 3 23.68 3.31 Male No Sun Dinner 2 11.840000 # 4 24.59 3.61 Female No Sun Dinner 4 6.147500
Передача вызываемого объекта, в отличие от фактического значения, которое нужно вставить, полезна, например, когда нет ссылки на фрейм данных. Это часто встречается при использовании метода DataFrame.assign()
в цепочке операций. Например, можно ограничить DataFrame
только теми наблюдениями, длина которых превышает 5, вычислить соотношение и сразу построить график:
# Внимание! абстрактный код. iris = pd.read_csv(iris_data) ( iris.query("SepalLength > 5") .assign( SepalRatio=lambda x: x.SepalWidth / x.SepalLength, PetalRatio=lambda x: x.PetalWidth / x.PetalLength, ).plot(kind="scatter", x="SepalRatio", y="PetalRatio") )
Так как передается функция, она вычисляется в назначенном DataFrame
. Важно отметить, что это DataFrame
, который был отфильтрован по строкам с длиной более 5. Сначала происходит фильтрация, а затем расчеты соотношения. Это пример, когда не было доступной ссылки на отфильтрованный DataFrame
.
Сигнатура функции для DataFrame.assign()
- это просто **kwargs
. Ключи - это имена столбцов для новых полей, а значения - это либо значение, которое нужно вставить (например, массив Series
или NumPy
), либо функция с одним аргументом, которая вызывается во фрейме данных. Возвращается копия исходного фрейма данных со вставленными новыми значениями.
Порядок **kwargs
сохраняется. Это допускает зависимое присваивание, когда выражение, указанное позже в **kwargs
, может ссылаться на столбец, созданный ранее в том же DataFrame.assign()
.
>>> dfa = pd.DataFrame({"A": [1, 2, 3], "B": [4, 5, 6]}) # круто, не правда ли >>> dfa.assign(C=lambda x: x["A"] + x["B"], D=lambda x: x["A"] + x["C"]) # A B C D # 0 1 4 5 6 # 1 2 5 7 9 # 2 3 6 9 12
Во втором выражении x['C']
будет ссылаться на вновь созданный столбец, который равен dfa['A'] + dfa['B']
.
DataFrame
Основы индексации заключаются в следующем:
Операция | Синтаксис | Результат |
Выбор столбцов | df[`col`] | Series |
Выбор строк по индексным меткам | df.loc[label] | Series |
Выбор строки по позиции | df.iloc[loc] | Series |
Срез строк по позиции | df[5:10] | DataFrame |
Выбор строк по логическому вектору | df[bool_vec] | DataFrame |
Например, выбор строки возвращает Series
, индексом которой являются столбцы DataFrame
:
>>> df # one bar flag foo one_trunc # a 1.0 1.0 False bar 1.0 # b 2.0 2.0 False bar 2.0 # c 3.0 3.0 True bar NaN # d NaN NaN False bar NaN >>> df.loc["b"] # one 2.0 # bar 2.0 # flag False # foo bar # one_trunc 2.0 # Name: b, dtype: object >>> df.iloc[2] # one 3.0 # bar 3.0 # flag True # foo bar # one_trunc NaN # Name: c, dtype: object
Данные между объектами DataFrame
автоматически выравнивается как по столбцам, так и по индексу (меткам строк). Опять же, результирующий объект будет иметь объединение меток столбца и строки.
>>> df = pd.DataFrame(np.random.randn(10, 4), columns=["A", "B", "C", "D"]) >>> df2 = pd.DataFrame(np.random.randn(7, 3), columns=["A", "B", "C"]) >>> df + df2 # A B C D # 0 -0.328227 1.804025 0.125411 NaN # 1 -0.670840 2.067624 -1.108924 NaN # 2 0.831945 -0.426104 -0.575880 NaN # 3 -2.709065 1.140954 2.316253 NaN # 4 0.433693 0.745088 0.804108 NaN # 5 -1.205184 -0.616827 -1.709180 NaN # 6 -0.021662 1.724195 0.893563 NaN # 7 NaN NaN NaN NaN # 8 NaN NaN NaN NaN # 9 NaN NaN NaN NaN
При выполнении операции между DataFrame
и Series
поведение по умолчанию заключается в выравнивании индекса Series
по столбцам DataFrame
, таким образом передавая данные по строкам. Например:
>>> df - df.iloc[0] # A B C D # 0 0.000000 0.000000 0.000000 0.000000 # 1 0.508564 0.662213 -1.113077 2.258814 # 2 0.963024 -0.474567 -0.292452 1.672575 # 3 -0.609690 -0.416193 0.516814 0.072799 # 4 2.090974 1.114655 0.564536 2.688766 # 5 -0.271611 0.655948 -1.346594 1.657681 # 6 1.227515 0.933819 -0.191704 2.524008 # 7 1.250461 -0.798301 -0.467560 2.218241 # 8 -0.199686 -1.912055 -0.020415 1.306960 # 9 0.814666 -0.254829 -0.154157 3.829802
Арифметические операции со скалярами выполняются поэлементно:
>>> df * 5 + 2 # A B C D # 0 -2.188748 2.875122 1.913159 -6.576318 # 1 0.354075 6.186185 -3.652227 4.717752 # 2 2.626371 0.502287 0.450899 1.786558 # 3 -5.237199 0.794154 4.497227 -6.212324 # 4 8.266122 8.448398 4.735839 6.867513 # 5 -3.546803 6.154862 -4.819811 1.712087 # 6 3.948828 7.544215 0.954639 6.043723 # 7 4.063558 -1.116385 -0.424642 4.514885 # 8 -3.187178 -6.685155 1.811085 -0.041519 # 9 1.884584 1.600975 1.142376 12.572693 >>> 1 / df # A B C D # 0 -1.193674 5.713491 -57.576821 -0.583001 # 1 -3.037805 1.194405 -0.884607 1.839756 # 2 7.982486 -3.338424 -3.227678 -23.425568 # 3 -0.690875 -4.146468 2.002221 -0.608841 # 4 0.797942 0.775386 1.827593 1.027219 # 5 -0.901420 1.203410 -0.733158 -17.366332 # 6 2.565645 0.901841 -4.783037 1.236484 # 7 2.423000 -1.604423 -2.062160 1.988162 # 8 -0.963915 -0.575695 -26.466883 -2.449157 # 9 -43.321462 -12.530547 -5.830058 0.472916 >>> df ** 4 # A B C D # 0 4.925573e-01 0.000938 9.099327e-08 8.656125 # 1 1.174250e-02 0.491353 1.633045e+00 0.087289 # 2 2.462903e-04 0.008051 9.213805e-03 0.000003 # 3 4.389368e+00 0.003383 6.222317e-02 7.277536 # 4 2.466694e+00 2.766478 8.963598e-02 0.898149 # 5 1.514576e+00 0.476811 3.461062e+00 0.000011 # 6 2.307882e-02 1.511750 1.910667e-03 0.427805 # 7 2.901259e-02 0.150912 5.529816e-02 0.064002 # 8 1.158363e+00 9.103960 2.037928e-06 0.027793 # 9 2.839145e-07 0.000041 8.655825e-04 19.992290
Логические операторы также работают поэлементно:
>>> df1 = pd.DataFrame({"a": [1, 0, 1], "b": [0, 1, 1]}, dtype=bool) >>> df2 = pd.DataFrame({"a": [0, 1, 1], "b": [1, 1, 0]}, dtype=bool) >>> df1 & df2 # a b # 0 False False # 1 False True # 2 True False >>> df1 | df2 # a b # 0 True True # 1 True True # 2 True True >>> df1 ^ df2 # a b # 0 True True # 1 True False # 2 False True >>> -df1 # a b # 0 False True # 1 True False # 2 False False
DataFrame
Чтобы транспонировать данные DataFrame
, необходимо обратится к атрибуту DataFrame.T
или методу DataFrame.transpose()
, аналогичному numpy.ndarray
:
# покажем только первые 5 строк >>> df[:5].T # 0 1 2 3 4 # A -0.837750 -0.329185 0.125274 -1.447440 1.253224 # B 0.175024 0.837237 -0.299543 -0.241169 1.289680 # C -0.017368 -1.130445 -0.309820 0.499445 0.547168 # D -1.715264 0.543550 -0.042688 -1.642465 0.973503
DataFrame
с функциями NumPyБольшинство функций NumPy
можно вызывать непосредственно в Series
и DataFrame
.
>>> np.exp(df).head() # A B C D # 0 0.432683 1.191275 0.982782 0.179916 # 1 0.719510 2.309976 0.322889 1.722110 # 2 1.133459 0.741157 0.733579 0.958210 # 3 0.235172 0.785709 1.647807 0.193502 # 4 3.501615 3.631623 1.728351 2.647201 # >>> np.asarray(df) # array([[-0.83774952, 0.17502433, -0.0173681 , -1.71526364], # [-0.3291851 , 0.837237 , -1.13044531, 0.54355038], # [ 0.12527426, -0.29954257, -0.30982022, -0.0426884 ], # [-1.44743974, -0.24116912, 0.49944541, -1.64246485], # [ 1.25322432, 1.28967954, 0.54716788, 0.97350267], # [-1.10936066, 0.83097233, -1.36396227, -0.05758268], # [ 0.38976552, 1.1088429 , -0.20907218, 0.80874457], # [ 0.41271156, -0.62327699, -0.48492845, 0.50297708], # [-1.03743561, -1.73703107, -0.03778307, -0.40830374], # [-0.02308325, -0.07980498, -0.17152488, 2.11453869]])
DataFrame
не предназначен для замены numpy.ndarray
, т.к. его семантика индексации и модель данных местами сильно отличаются от n-мерного массива.
В свою очередь Series
реализует __array_ufunc__
, что позволяет ему работать с универсальными функциями NumPy
.
Ufunc
применяется к базовому массиву последовательно.
>>> ser = pd.Series([1, 2, 3, 4]) >>> np.exp(ser) 0 2.718282 1 7.389056 2 20.085537 3 54.598150 dtype: float64
Когда в ufunc
передается несколько рядов, то они выравниваются перед выполнением операции.
Pandas
автоматически выравнивает помеченные входные данные как часть ufunc
с несколькими входными данными. Например, использование numpy.remain()
для двух рядов с по-разному упорядоченными метками приведет к выравниванию перед операцией.
>>> ser1 = pd.Series([1, 2, 3], index=["a", "b", "c"]) >>> ser2 = pd.Series([1, 3, 5], index=["b", "a", "c"]) >>> np.remainder(ser1, ser2) # a 1 # b 0 # c 3 # dtype: int64
Берется объединение двух индексов, и непересекающиеся значения заполняются пропущенными значениями NaN
.
>>> ser3 = pd.Series([2, 4, 6], index=["b", "c", "d"]) >>> np.remainder(ser1, ser3) # a NaN # b 0.0 # c 3.0 # d NaN # dtype: float64
Когда двоичный ufunc
применяется к pandas.Series
и pandas.Index
, реализация Series
имеет приоритет, и возвращается pandas.Series
.
>>> ser = pd.Series([1, 2, 3]) >>> idx = pd.Index([4, 5, 6]) >>> np.maximum(ser, idx) # 0 4 # 1 5 # 2 6 # dtype: int64
DataFrame
на консольПо умолчанию pandas
обрезает вывод больших фреймов данных и показывает несколько первых и последних строк. Такое поведение можно переопределить, используя метод DataFrame.head(n)
для вывода на экран n
первых строк или DataFrame.tail(n)
последних строк. Для отрицательных значений n
эти методы покажут строки, кроме первых/последних n
строк в зависимости от метода.
# данные `tips` были загружены ранее # Отобразим первые 7 строк данных >>> tips.head(7) # total_bill tip sex smoker day time size # 0 16.99 1.01 Female No Sun Dinner 2 # 1 10.34 1.66 Male No Sun Dinner 3 # 2 21.01 3.50 Male No Sun Dinner 3 # 3 23.68 3.31 Male No Sun Dinner 2 # 4 24.59 3.61 Female No Sun Dinner 4 # 5 25.29 4.71 Male No Sun Dinner 4 # 6 8.77 2.00 Male No Sun Dinner 2
Использование DataFrame.to_string()
вернет строковое представление DataFrame
в табличной форме, хотя оно не всегда будет соответствовать ширине консоли.
Можно получить сводку по данным, используя метод DataFrame.info()
.
>>> tips.info() # <class 'pandas.core.frame.DataFrame'> # RangeIndex: 244 entries, 0 to 243 # Data columns (total 8 columns): # # Column Non-Null Count Dtype # --- ------ -------------- ----- # 0 Unnamed: 0 244 non-null int64 # 1 total_bill 244 non-null float64 # 2 tip 244 non-null float64 # 3 sex 244 non-null object # 4 smoker 244 non-null object # 5 day 244 non-null object # 6 time 244 non-null object # 7 size 244 non-null int64 # dtypes: float64(2), int64(2), object(4) # memory usage: 15.4+ KB
Метод DataFrame.describe()
показывает краткую статистическую сводку данных:
>>> tips.describe() # total_bill tip size # count 244.000000 244.000000 244.000000 # mean 19.785943 2.998279 2.569672 # std 8.902412 1.383638 0.951100 # min 3.070000 1.000000 1.000000 # 25% 13.347500 2.000000 2.000000 # 50% 17.795000 2.900000 2.000000 # 75% 24.127500 3.562500 3.000000 # max 50.810000 10.000000 6.000000
Метод DataFrame.mean()
рассчитает среднее значение для столбцов только с числовым значением:
>>> tips[['total_bill', 'tip', 'size']].mean() # total_bill 19.785943 # tip 2.998279 # size 2.569672 # dtype: float64
pandas.DataFrame
и лежащие в их основе данныеDataFrame.T
: транспонирование DataFrame.
>>> df = pd.DataFrame({'col1': [1, 2], 'col2': [3, 4]}) >>> df # col1 col2 # 0 1 3 # 1 2 4 >>> df.T # 0 1 # col1 1 2 # col2 3 4
DataFrame.index
: индекс (индексные метки строк) DataFrame
;
DataFrame.columns
: метки столбцов DataFrame
.
DataFrame.dtypes
: возвращает dtypes
в DataFrame
.
DataFrame.values
: возвращает представление Numpy
.
DataFrame.axes
: возвращает список, представляющий оси DataFrame
.
DataFrame.ndim
: возвращает целое число, представляющее количество осей/измерений массива.
DataFrame.size
: возвращает целое число, представляющее количество элементов в этом объекте.
DataFrame.shape
: возвращает кортеж, представляющий размерность DataFrame
.
DataFrame.empty
: проверяет, пуст ли DataFrame
.
DataFrame.info(verbose=None, max_cols=None, memory_usage=None, show_counts=None)
: печатает краткую сводку DataFrame
.
Принимаемые аргументы:
verbose=None
- следует ли распечатывать полную сводку. Принимает bool
;
max_cols=None
- целое число, когда следует переключаться с подробного вывода на усеченный. Если DataFrame
содержит более max_cols
столбцов, используются усеченные выходные данные. По умолчанию соответствует параметру pandas.options.display.max_info_columns
;
memory_usage=None
- определяет, следует ли отображать общее использование памяти элементами DataFrame
(включая индекс). По умолчанию соответствует параметру pandas.options.display.memory_usage
;
True
всегда показывает использование памяти. False
никогда не показывает использование памяти. 'deep'
- эквивалентно высказыванию "True
с глубоким самоанализом".Использование памяти отображается в удобочитаемых единицах (представление по основанию 2). Без глубокого самоанализа оценка памяти производится на основе столбца dtype
и количества строк, предполагая, что значения потребляют одинаковый объем памяти для соответствующих dtypes
. При глубокой интроспекции памяти выполняется расчет реального использования памяти за счет вычислительных ресурсов.
show_counts=None
- следует ли отображать числа, отличные от NULL
. По умолчанию это отображается только в том случае, если DataFrame
меньше, чем pandas.options.display.max_info_rows
и pandas.options.display.max_info_columns
. Значение True
всегда показывает счетчики, а False
никогда не показывает счетчики.
>>> import pandas as pd >>> int_values = [1, 2, 3, 4, 5] >>> text_values = ['alpha', 'beta', 'gamma', 'delta', 'epsilon'] >>> float_values = [0.0, 0.25, 0.5, 0.75, 1.0] >>> df = pd.DataFrame({"int_col": int_values, "text_col": text_values, "float_col": float_values}) >>> df # int_col text_col float_col # 0 1 alpha 0.00 # 1 2 beta 0.25 # 2 3 gamma 0.50 # 3 4 delta 0.75 # 4 5 epsilon 1.00
Печатает информацию по всем столбцам:
>>> df.info(verbose=True) # <class 'pandas.core.frame.DataFrame'> # RangeIndex: 5 entries, 0 to 4 # Data columns (total 3 columns): # # Column Non-Null Count Dtype # --- ------ -------------- ----- # 0 int_col 5 non-null int64 # 1 text_col 5 non-null object # 2 float_col 5 non-null float64 # dtypes: float64(1), int64(1), object(1) # memory usage: 248.0+ bytes
Выводит сводку о количестве столбцов и их dtypes, но не сведения о каждом столбце:
>>> df.info(verbose=False) # <class 'pandas.core.frame.DataFrame'> # RangeIndex: 5 entries, 0 to 4 # Columns: 3 entries, int_col to float_col # dtypes: float64(1), int64(1), object(1) # memory usage: 248.0+ bytes
Параметр memory_usage
позволяет использовать режим глубокой интроспекции, что особенно полезно для больших кадров данных и тонкой настройки оптимизации памяти:
>>> import numpy as np df = pd.DataFrame({ 'column_1': np.random.choice(['a', 'b', 'c'], 10 ** 6), 'column_2': np.random.choice(['a', 'b', 'c'], 10 ** 6), 'column_3': np.random.choice(['a', 'b', 'c'], 10 ** 6) }) >>> df.info() # <class 'pandas.core.frame.DataFrame'> # RangeIndex: 1000000 entries, 0 to 999999 # Data columns (total 3 columns): # # Column Non-Null Count Dtype # --- ------ -------------- ----- # 0 column_1 1000000 non-null object # 1 column_2 1000000 non-null object # 2 column_3 1000000 non-null object # dtypes: object(3) # memory usage: 22.9+ MB >>> df.info(memory_usage='deep') # <class 'pandas.core.frame.DataFrame'> # RangeIndex: 1000000 entries, 0 to 999999 # Data columns (total 3 columns): # # Column Non-Null Count Dtype # --- ------ -------------- ----- # 0 column_1 1000000 non-null object # 1 column_2 1000000 non-null object # 2 column_3 1000000 non-null object # dtypes: object(3) # memory usage: 165.9 MB
DataFrame.select_dtypes(include=None, exclude=None)
: возвращает подмножество столбцов DataFrame
на основе dtypes
. Должен быть указан хотя бы один из аргументов.
np.number
или 'number'
.object
, при этом будут возвращены все столбцы dtype: object
.np.datetime64
, 'datetime'
или 'datetime64'
.np.timedelta64
, 'timedelta'
или 'timedelta64'
.'category'
.datetimetz
Pandas, используйте 'datetimetz'
или 'datetime64[ns, tz]'
.df = pd.DataFrame({'a': [1, 2] * 3, 'b': [True, False] * 3, 'c': [1.0, 2.0] * 3}) >>> df # a b c # 0 1 True 1.0 # 1 2 False 2.0 # 2 1 True 1.0 # 3 2 False 2.0 # 4 1 True 1.0 # 5 2 False 2.0 >>> df.select_dtypes(include='bool') # b # 0 True # 1 False # 2 True # 3 False # 4 True # 5 False >>> df.select_dtypes(include=['float64']) # c # 0 1.0 # 1 2.0 # 2 1.0 # 3 2.0 # 4 1.0 # 5 2.0 >>> df.select_dtypes(exclude=['int64']) # b c # 0 True 1.0 # 1 False 2.0 # 2 True 1.0 # 3 False 2.0 # 4 True 1.0 # 5 False 2.0
DataFrame.memory_usage([index, deep])
: возвращает использование памяти каждым столбцом в байтах. Это значение отображается в DataFrame.info()
по умолчанию. Его можно подавить, установив для pandas.options.display.memory_usage=False
.
>>> dtypes = ['int64', 'float64', 'complex128', 'object', 'bool'] >>> data = dict([(t, np.ones(shape=5000, dtype=int).astype(t)) for t in dtypes]) >>> df = pd.DataFrame(data) >>> df.head() # int64 float64 complex128 object bool # 0 1 1.0 1.0+0.0j 1 True # 1 1 1.0 1.0+0.0j 1 True # 2 1 1.0 1.0+0.0j 1 True # 3 1 1.0 1.0+0.0j 1 True # 4 1 1.0 1.0+0.0j 1 True >>> df.memory_usage() # Index 128 # int64 40000 # float64 40000 # complex128 80000 # object 40000 # bool 5000 # dtype: int64 # без учета индекса >>> df.memory_usage(index=False) # int64 40000 # float64 40000 # complex128 80000 # object 40000 # bool 5000 # dtype: int64
Объем памяти, занимаемый столбцами dtype: object
, по умолчанию игнорируется:
>>> df.memory_usage(deep=True) # Index 128 # int64 40000 # float64 40000 # complex128 80000 # object 180000 # bool 5000 # dtype: int64
Используйте категориальный тип для эффективного хранения столбца c типом dtype: object
с множеством повторяющихся значений.
>>> df['object'].astype('category').memory_usage(deep=True) # 5244
DataFrame.flags
: получает свойства, связанные с этим объектом pandas
.
Доступные флаги: pandas.Flags.allows_duplicate_labels
. Установка pandas.Flags.allows_duplicate_labels=False
гарантирует, что индекс (и столбцы DataFrame
) будут уникальными. Большинство методов, принимающих и возвращающих DataFrame
, распространяют значение allows_duplicate_labels
.
>>> df = pd.DataFrame({"A": [1, 2]}, index=['a', 'a']) >>> df.flags.allows_duplicate_labels # True >>> df.flags.allows_duplicate_labels = False # Traceback (most recent call last): # ... # pandas.errors.DuplicateLabelError: Index has duplicates. # positions # label # a [0, 1]