10 приемов Python Pandas, которые сделают вашу работу более эффективной
Pandas — это широко используемый пакет Python для структурированных данных. Существует много хороших учебных пособий на данную тематику, но здесь мы бы хотели раскрыть несколько интересных приемов, которые, вероятно, еще пока неизвестны читателю, но могут оказаться крайне полезными.
read_csv
Все знают эту команду. Но если данные, которые вы пытаетесь прочитать, слишком большие, попробуйте добавить команду nrows = 5 , чтобы прочитать сначала небольшую часть данных перед загрузкой всей таблицы. В этом случае вам удастся избежать ситуации выбора неверного разделителя (не всегда в данных есть разделение в виде запятой).
(Или вы можете использовать команду ‘head’ в linux для проверки первых 5 строк в любом текстовом файле: head -c 5 data.txt )
Затем вы можете извлечь список столбцов, используя df.columns.tolist() , а затем добавить команду usecols = [‘c1’, ‘c2’,…], чтобы извлечь только нужные вам столбцы. Кроме того, если вы знаете типы данных определенных столбцов, вы можете добавить dtype = для более быстрой загрузки. Еще одно преимущество этой команды в том, что если у вас есть столбец, который содержит как строки, так и числа, рекомендуется объявить его тип строковым, чтобы не возникало ошибок при попытке объединить таблицы, используя этот столбец в качестве ключа.
select_dtypes
Если предварительная обработка данных должна выполняться в Python, то эта команда сэкономит ваше время. После чтения из таблицы типами данных по умолчанию для каждого столбца могут быть bool, int64, float64, object, category, timedelta64 или datetime64. Вы можете сначала проверить распределение с помощью
df.dtypes.value_counts()
чтобы узнать все возможные типы данных вашего фрейма, затем используйте
df.select_dtypes(include=[‘float64’, ‘int64’])
чтобы выбрать субфрейм только с числовыми характеристиками.
сopy
Это важная команда. Если вы сделаете:
import pandas as pd
df1 = pd.DataFrame(< ‘a’:[0,0,0], ‘b’: [1,1,1]>)
df2 = df1
df2[‘a’] = df2[‘a’] + 1
df1.head()
Вы обнаружите, что df1 изменен. Это потому, что df2 = df1 не делает копию df1 и присваивает ее df2, а устанавливает указатель, указывающий на df1. Таким образом, любые изменения в df2 приведут к изменениям в df1. Чтобы это исправить, вы можете сделать либо:
df2 = df1.copy ()
from copy import deepcopy
df2 = deepcopy(df1)
map
Это классная команда для простого преобразования данных. Сначала вы определяете словарь, в котором «ключами» являются старые значения, а «значениями» являются новые значения.
level_map =
df[‘c_level’] = df[‘c’].map(level_map)
Например: True, False до 1, 0 (для моделирования); определение уровней; определяемые пользователем лексические кодировки.
apply or not apply?
Если нужно создать новый столбец с несколькими другими столбцами в качестве входных данных, функция apply была бы весьма полезна.
def rule(x, y):
if x == ‘high’ and y > 10:
return 1
else:
return 0
df = pd.DataFrame(< 'c1':[ 'high' ,'high', 'low', 'low'], 'c2': [0, 23, 17, 4]>)
df['new'] = df.apply(lambda x: rule(x['c1'], x['c2']), axis = 1)
df.head()
В приведенных выше кодах мы определяем функцию с двумя входными переменными и используем функцию apply, чтобы применить ее к столбцам ‘c1’ и ‘c2’.
но проблема «apply» заключается в том, что иногда она занимает очень много времени.
Скажем, если вы хотите рассчитать максимум из двух столбцов «c1» и «c2», конечно, вы можете применить данную команду
df[‘maximum’] = df.apply(lambda x: max(x[‘c1’], x[‘c2’]), axis = 1)
но это будет медленнее, нежели:
df[‘maximum’] = df[[‘c1’,’c2']].max(axis =1)
Вывод: не используйте команду apply, если вы можете выполнить ту же работу используя другие функции (они часто быстрее). Например, если вы хотите округлить столбец ‘c’ до целых чисел, выполните округление (df [‘c’], 0) вместо использования функции apply.
value counts
Это команда для проверки распределения значений. Например, если вы хотите проверить возможные значения и частоту для каждого отдельного значения в столбце «c», вы можете применить
df[‘c’].value_counts()
Есть несколько полезных приемов / функций:
A. normalize = True : если вы хотите проверить частоту вместо подсчетов.
B. dropna = False : если вы хотите включить пропущенные значения в статистику.
C. sort = False : показать статистику, отсортированную по значениям, а не по количеству.
D. df[‘c].value_counts().reset_index().: если вы хотите преобразовать таблицу статистики в датафрейм Pandas и управлять ими.
количество пропущенных значений
При построении моделей может потребоваться исключить строку со слишком большим количеством пропущенных значений / строки со всеми пропущенными значениями. Вы можете использовать .isnull () и .sum () для подсчета количества пропущенных значений в указанных столбцах.
import pandas as pd
import numpy as np
df = pd.DataFrame(< ‘id’: [1,2,3], ‘c1’:[0,0,np.nan], ‘c2’: [np.nan,1,1]>)
df = df[[‘id’, ‘c1’, ‘c2’]]
df[‘num_nulls’] = df[[‘c1’, ‘c2’]].isnull().sum(axis=1)
df.head()
выбрать строки с конкретными идентификаторами
В SQL мы можем сделать это, используя SELECT * FROM… WHERE ID в («A001», «C022»,…), чтобы получить записи с конкретными идентификаторами. Если вы хотите сделать то же самое с pandas, вы можете использовать:
df_filter = df ['ID']. isin (['A001', 'C022', . ])
df [df_filter]
Percentile groups
Допустим, у вас есть столбец с числовыми значениями, и вы хотите классифицировать значения в этом столбце по группам, скажем, топ 5% в группу 1, 5–20% в группу 2, 20–50% в группу 3, нижние 50% в группу 4. Конечно, вы можете сделать это с помощью pandas.cut, но мы бы хотели представить другую функцию:
import numpy as np
cut_points = [np.percentile(df[‘c’], i) for i in [50, 80, 95]]
df[‘group’] = 1
for i in range(3):
df[‘group’] = df[‘group’] + (df[‘c’] < cut_points[i])
# or Которая быстро запускается (не применяется функция apply).to_csv
Опять-таки, это команда, которую используют все. Отметим пару полезных приемов. Первый:print(df[:5].to_csv())Вы можете использовать эту команду, чтобы напечатать первые пять строк того, что будет записано непосредственно в файл.
Еще один прием касается смешанных вместе целых чисел и пропущенных значений. Если столбец содержит как пропущенные значения, так и целые числа, тип данных по-прежнему будет float, а не int. Когда вы экспортируете таблицу, вы можете добавить float_format = '%. 0f', чтобы округлить все числа типа float до целых чисел. Используйте этот прием, если вам нужны только целочисленные выходные данные для всех столбцов – так вы избавитесь от всех назойливых нулей ‘.0’ .
Pandas: как проверить dtype для всех столбцов в DataFrame
Вы можете использовать следующие методы для проверки типа данных ( dtype ) для столбцов в кадре данных pandas:
Способ 1: проверить dtype одного столбца
df.column_name.dtypeСпособ 2: проверить dtype всех столбцов
df.dtypesСпособ 3: проверьте, какие столбцы имеют определенный тип dtype
df.dtypes [df.dtypes == 'int64']В следующих примерах показано, как использовать каждый метод со следующими пандами DataFrame:
import pandas as pd #create DataFrame df = pd.DataFrame() #view DataFrame print(df) team points assists all_star 0 A 18 5 True 1 B 22 7 False 2 C 19 7 False 3 D 14 9 True 4 E 14 12 True 5 F 11 9 TrueПример 1: проверка dtype одного столбца
Мы можем использовать следующий синтаксис, чтобы проверить тип данных только столбца точек в DataFrame:
#check dtype of points column df.points.dtype dtype('int64')Из вывода мы видим, что столбец точек имеет целочисленный тип данных.
Пример 2: Проверка dtype всех столбцов
Мы можем использовать следующий синтаксис для проверки типа данных всех столбцов в DataFrame:
#check dtype of all columns df.dtypes team object points int64 assists int64 all_star bool dtype: objectИз вывода мы видим:
- Столбец команды : объект (это то же самое, что и строка)
- столбец очков : целое число
- столбец помогает : целое число
- столбец all_star : логическое значение
Используя эту одну строку кода, мы можем увидеть тип данных каждого столбца в DataFrame.
Пример 3: проверьте, какие столбцы имеют определенный тип dtype
Мы можем использовать следующий синтаксис, чтобы проверить, какие столбцы в DataFrame имеют тип данных int64:
#show all columns that have a class of int64 df.dtypes [df.dtypes == 'int64'] points int64 assists int64 dtype: object
Из вывода мы видим, что столбцы очков и помощи имеют тип данных int64.
Мы можем использовать аналогичный синтаксис, чтобы проверить, какие столбцы имеют другие типы данных.
Например, мы можем использовать следующий синтаксис, чтобы проверить, какие столбцы в DataFrame имеют тип данных объекта:
#show all columns that have a class of object (i.e. string) df.dtypes [df.dtypes == 'O'] team object dtype: object
Мы видим, что только столбец team имеет тип данных «O», что означает объект.
Дополнительные ресурсы
В следующих руководствах объясняется, как выполнять другие распространенные операции с пандами DataFrames:
Структуры данных в pandas / pd 2
Ядром pandas являются две структуры данных, в которых происходят все операции:
Series — это структура, используемая для работы с последовательностью одномерных данных, а Dataframe — более сложная и подходит для нескольких измерений.
Пусть они и не являются универсальными для решения всех проблем, предоставляют отличный инструмент для большинства приложений. При этом их легко использовать, а множество более сложных структур можно упросить до одной из этих двух.
Однако особенности этих структур основаны на одной черте — интеграции в их структуру объектов index и labels (метки). С их помощью структурами становится очень легко манипулировать.
Series (серии)
Series — это объект библиотеки pandas, спроектированный для представления одномерных структур данных, похожих на массивы, но с дополнительными возможностями. Его структура проста, ведь он состоит из двух связанных между собой массивов. Основной содержит данные (данные любого типа NumPy), а в дополнительном, index , хранятся метки.

Создание объекта Series
Для создания объекта Series с предыдущего изображения необходимо вызвать конструктор Series() и передать в качестве аргумента массив, содержащий значения, которые необходимо включить.
>>> s = pd.Series([12,-4,7,9]) >>> s 0 12 1 -4 2 7 3 9 dtype: int64
Как можно увидеть по выводу, слева отображаются значения индексов, а справа — сами значения (данные).
Если не определить индекс при объявлении объекта, метки будут соответствовать индексам (положению в массиве) элементов объекта Series .
Однако лучше создавать Series , используя метки с неким смыслом, чтобы в будущем отделять и идентифицировать данные вне зависимости от того, в каком порядке они хранятся.
В таком случае необходимо будет при вызове конструктора включить параметр index и присвоить ему массив строк с метками.
>>> s = pd.Series([12,-4,7,9], index=['a','b','c','d']) >>> s a 12 b -4 c 7 d 9 dtype: int64
Если необходимо увидеть оба массива, из которых состоит структура, можно вызвать два атрибута: index и values .
>>> s.values array([12, -4, 7, 9], dtype=int64) >>> s.index Index(['a', 'b', 'c', 'd'], dtype='object')
Выбор элементов по индексу или метке
Выбирать отдельные элементы можно по принципу обычных массивов numpy, используя для этого индекс.
>>> s[2] 7
Или же можно выбрать метку, соответствующую положению индекса.
>>> s['b'] -4
Таким же образом можно выбрать несколько элементов массива numpy с помощью следующей команды:
>>> s[0:2] a 12 b -4 dtype: int64
В этом случае можно использовать соответствующие метки, но указать их список в массиве.
>>> s[['b','c']] b -4 c 7 dtype: int64
Присваивание значений элементам
Понимая как выбирать отдельные элементы, важно знать и то, как присваивать им новые значения. Можно делать это по индексу или по метке.
>>> s[1] = 0 >>> s a 12 b 0 c 7 d 9 dtype: int64
>>> s['b'] = 1 >>> s a 12 b 1 c 7 d 9 dtype: int64
Создание Series из массивов NumPy
Новый объект Series можно создать из массивов NumPy и уже существующих Series .
>>> arr = np.array([1,2,3,4]) >>> s3 = pd.Series(arr) >>> s3 0 1 1 2 2 3 3 4 dtype: int32
>>> s4 = pd.Series(s) >>> s4 a 12 b 1 c 7 d 9 dtype: int64
Важно запомнить, что значения в массиве NumPy или оригинальном объекте Series не копируются, а передаются по ссылке. Это значит, что элементы объекта вставляются динамически в новый Series . Если меняется оригинальный объект, то меняются и его значения в новом.
>>> s3 0 1 1 2 2 3 3 4 dtype: int32
>>> arr[2] = -2 >>> s3 0 1 1 2 2 -2 3 4 dtype: int32
На этом примере можно увидеть, что при изменении третьего элемента массива arr , меняется соответствующий элемент и в s3 .
Фильтрация значений
Благодаря тому что основной библиотекой в pandas является NumPy, многие операции, применяемые к массивам NumPy, могут быть использованы и в случае с Series . Одна из таких — фильтрация значений в структуре данных с помощью условий.
Например, если нужно узнать, какие элементы в Series больше 8, то можно написать следующее:
>>> s[s > 8] a 12 d 9 dtype: int64
Операции и математические функции
Другие операции, такие как операторы ( +, -, * и / ), а также математические функции, работающие с массивами NumPy, могут использоваться и для Series .
Для операторов можно написать простое арифметическое уравнение.
>>> s / 2 a 6.0 b 0.5 c 3.5 d 4.5 dtype: float64
Но в случае с математическими функциями NumPy необходимо указать функцию через np , а Series передать в качестве аргумента.
>>> np.log(s) a 2.484907 b 0.000000 c 1.945910 d 2.197225 dtype: float64
Количество значений
В Series часто встречаются повторения значений. Поэтому важно иметь информацию, которая бы указывала на то, есть ли дубликаты или конкретное значение в объекте.
Так, можно объявить Series , в котором будут повторяющиеся значения.
>>> serd = pd.Series([1,0,2,1,2,3], index=['white','white','blue','green',' green','yellow']) >>> serd white 1 white 0 blue 2 green 1 green 2 yellow 3 dtype: int64
Чтобы узнать обо всех значениях в Series , не включая дубли, можно использовать функцию unique() . Возвращаемое значение — массив с уникальными значениями, необязательно в том же порядке.
>>> serd.unique() array([1, 0, 2, 3], dtype=int64)
На unique() похожа функция value_counts() , которая возвращает не только уникальное значение, но и показывает, как часто элементы встречаются в Series .
>>> serd.value_counts() 2 2 1 2 3 1 0 1 dtype: int64
Наконец, isin() показывает, есть ли элементы на основе списка значений. Она возвращает булевые значения, которые очень полезны при фильтрации данных в Series или в колонке Dataframe .
>>> serd.isin([0,3]) white False white True blue False green False green False yellow True dtype: bool
>>> serd[serd.isin([0,3])] white 0 yellow 3 dtype: int64
Значения NaN
В предыдущем примере мы попробовали получить логарифм отрицательного числа и результатом стало значение NaN . Это значение (Not a Number) используется в структурах данных pandas для обозначения наличия пустого поля или чего-то, что невозможно обозначить в числовой форме.
Как правило, NaN — это проблема, для которой нужно найти определенное решение, особенно при работе с анализом данных. Эти данные часто появляются при извлечении информации из непроверенных источников или когда в самом источнике недостает данных. Также значения NaN могут генерироваться в специальных случаях, например, при вычислении логарифмов для отрицательных значений, в случае исключений при вычислениях или при использовании функций. Есть разные стратегии работы со значениями NaN .
Несмотря на свою «проблемность» pandas позволяет явно определять NaN и добавлять это значение в структуры, например, в Series . Для этого внутри массива достаточно ввести np.NaN в том месте, где требуется определить недостающее значение.
>>> s2 = pd.Series([5,-3,np.NaN,14]) >>> s2 0 5.0 1 -3.0 2 NaN 3 14.0 dtype: float64
Функции isnull() и notnull() очень полезны для определения индексов без значения.
>>> s2.isnull() 0 False 1 False 2 True 3 False dtype: bool
>>> s2.notnull() 0 True 1 True 2 False 3 True dtype: bool
Они возвращают два объекта Series с булевыми значениями, где True указывает на наличие значение, а NaN — на его отсутствие. Функция isnull() возвращает True для значений NaN в Series , а notnull() — True в тех местах, где значение не равно NaN . Эти функции часто используются в фильтрах для создания условий.
>>> s2[s2.notnull()] 0 5.0 1 -3.0 3 14.0 dtype: float64
s2[s2.isnull()] 2 NaN dtype: float64
Series из словарей
Series можно воспринимать как объект dict (словарь). Эта схожесть может быть использована на этапе объявления объекта. Даже создавать Series можно на основе существующего dict .
>>> mydict = 'red': 2000, 'blue': 1000, 'yellow': 500, 'orange': 1000> >>> myseries = pd.Series(mydict) >>> myseries blue 1000 orange 1000 red 2000 yellow 500 dtype: int64
На этом примере можно увидеть, что массив индексов заполнен ключами, а данные — соответствующими значениями. В таком случае соотношение будет установлено между ключами dict и метками массива индексов. Если есть несоответствие, pandas заменит его на NaN .
>>> colors = ['red','yellow','orange','blue','green'] >>> myseries = pd.Series(mydict, index=colors) >>> myseries red 2000.0 yellow 500.0 orange 1000.0 blue 1000.0 green NaN dtype: float64
Операции с сериями
Вы уже видели, как выполнить арифметические операции на объектах Series и скалярных величинах. То же возможно и для двух объектов Series , но в таком случае в дело вступают и метки.
Одно из главных достоинств этого типа структур данных в том, что он может выравнивать данные, определяя соответствующие метки.
В следующем примере добавляются два объекта Series , у которых только некоторые метки совпадают.
>>> mydict2 = 'red':400,'yellow':1000,'black':700> >>> myseries2 = pd.Series(mydict2) >>> myseries + myseries2 black NaN blue NaN green NaN orange NaN red 2400.0 yellow 1500.0 dtype: float64
Новый объект получает только те элементы, где метки совпали. Все остальные тоже присутствуют, но со значением NaN.
DataFrame (датафрейм)
Dataframe — это табличная структура данных, напоминающая таблицы из Microsoft Excel. Ее главная задача — позволить использовать многомерные Series . Dataframe состоит из упорядоченной коллекции колонок, каждая из которых содержит значение разных типов (числовое, строковое, булевое и так далее).

В отличие от Series у которого есть массив индексов с метками, ассоциированных с каждым из элементов, Dataframe имеет сразу два таких. Первый ассоциирован со строками (рядами) и напоминает таковой из Series . Каждая метка ассоциирована со всеми значениями в ряду. Второй содержит метки для каждой из колонок.
Dataframe можно воспринимать как dict , состоящий из Series , где ключи — названия колонок, а значения — объекты Series , которые формируют колонки самого объекта Dataframe . Наконец, все элементы в каждом объекте Series связаны в соответствии с массивом меток, называемым index .
Создание Dataframe
Простейший способ создания Dataframe — передать объект dict в конструктор DataFrame() . Объект dict содержит ключ для каждой колонки, которую требуется определить, а также массив значений для них.
Если объект dict содержит больше данных, чем требуется, можно сделать выборку. Для этого в конструкторе Dataframe нужно определить последовательность колонок с помощью параметра column . Колонки будут созданы в заданном порядке вне зависимости от того, как они расположены в объекте dict .
>> data = 'color' : ['blue', 'green', 'yellow', 'red', 'white'], 'object' : ['ball', 'pen', 'pencil', 'paper', 'mug'], 'price' : [1.2, 1.0, 0.6, 0.9, 1.7]> >>> frame = pd.DataFrame(data) >>> frame
| color | object | price | |
|---|---|---|---|
| 0 | blue | ball | 1.2 |
| 1 | green | pen | 1.0 |
| 2 | yellow | pencil | 0.6 |
| 3 | red | paper | 0.9 |
| 4 | white | mug | 1.7 |
Даже для объектов Dataframe если метки явно не заданы в массиве index , pandas автоматически присваивает числовую последовательность, начиная с нуля. Если же индексам Dataframe нужно присвоить метки, необходимо использовать параметр index и присвоить ему массив с метками.
>>> frame2 = pd.DataFrame(data, columns=['object', 'price']) >>> frame2
| object | price | |
|---|---|---|
| 0 | ball | 1.2 |
| 1 | pen | 1.0 |
| 2 | pencil | 0.6 |
| 3 | paper | 0.9 |
| 4 | mug | 1.7 |
Теперь, зная о параметрах index и columns , проще использовать другой способ определения Dataframe . Вместо использования объекта dict можно определить три аргумента в конструкторе в следующем порядке: матрицу данных, массив значений для параметра index и массив с названиями колонок для параметра columns .
В большинстве случаев простейший способ создать матрицу значений — использовать np.arrange(16).reshape((4,4)) . Это формирует матрицу размером 4х4 из чисел от 0 до 15.
>>> frame3 = pd.DataFrame(np.arange(16).reshape((4,4)), ... index=['red', 'blue', 'yellow', 'white'], ... columns=['ball', 'pen', 'pencil', 'paper']) >>> frame3
Выбор элементов
Если нужно узнать названия всех колонок Dataframe , можно вызвать атрибут columns для экземпляра объекта.
>>> frame.columns Index(['color', 'object', 'price'], dtype='object')
То же можно проделать и для получения списка индексов.
>>> frame.index RangeIndex(start=0, stop=5, step=1)
Весь же набор данных можно получить с помощью атрибута values .
>>> frame.values array([['blue', 'ball', 1.2], ['green', 'pen', 1.0], ['yellow', 'pencil', 0.6], ['red', 'paper', 0.9], ['white', 'mug', 1.7]], dtype=object)
Указав в квадратных скобках название колонки, можно получить значений в ней.
>>> frame['price'] 0 1.2 1 1.0 2 0.6 3 0.9 4 1.7 Name: price, dtype: float64
Возвращаемое значение — объект Series . Название колонки можно использовать и в качестве атрибута.
>>> frame.price 0 1.2 1 1.0 2 0.6 3 0.9 4 1.7 Name: price, dtype: float64
Для строк внутри Dataframe используется атрибут loc со значением индекса нужной строки.
>>> frame.loc[2] color yellow object pencil price 0.6 Name: 2, dtype: object
Возвращаемый объект — это снова Series , где названия колонок — это уже метки массива индексов, а значения — данные Series .
Для выбора нескольких строк можно указать массив с их последовательностью.
>>> frame.loc[[2,4]]
| color | object | price | |
|---|---|---|---|
| 2 | yellow | pencil | 0.6 |
| 4 | white | mug | 1.7 |
Если необходимо извлечь часть Dataframe с конкретными строками, для этого можно использовать номера индексов. Она выведет данные из соответствующей строки и названия колонок.
>>> frame[0:1]
| color | object | price | |
|---|---|---|---|
| 2 | yellow | pencil | 0.6 |
| 4 | white | mug | 1.7 |
Возвращаемое значение — объект Dataframe с одной строкой. Если нужно больше одной строки, необходимо просто указать диапазон.
>>> frame[1:3]
| color | object | price | |
|---|---|---|---|
| 0 | blue | ball | 1.2 |
Наконец, если необходимо получить одно значение из объекта, сперва нужно указать название колонки, а потом — индекс или метку строки.
>>> frame['object'][3] 'paper'
Присваивание и замена значений
Разобравшись с логикой получения доступа к разным элементам Dataframe , можно следовать ей же для добавления новых или изменения уже существующих значений.
Например, в структуре Dataframe массив индексов определен атрибутом index , а строка с названиями колонок — columns . Можно присвоить метку с помощью атрибута name для этих двух подструктур, чтобы идентифицировать их.
>>> frame.index.name = 'id' >>> frame.columns.name = 'item' >>> frame
| item | color | object | price |
|---|---|---|---|
| id | |||
| 0 | blue | ball | 1.2 |
| 1 | green | pen | 1.0 |
| 2 | yellow | pencil | 0.6 |
| 3 | red | paper | 0.9 |
| 4 | white | mug | 1.7 |
Одна из главных особенностей структур данных pandas — их гибкость. Можно вмешаться на любом уровне для изменения внутренней структуры данных. Например, добавление новой колонки — крайне распространенная операция.
Ее можно выполнить, присвоив значение экземпляру Dataframe и определив новое имя колонки.
>>> frame['new'] = 12 >>> frame
| item | color | object | price | new |
|---|---|---|---|---|
| id | ||||
| 0 | blue | ball | 1.2 | 12 |
| 1 | green | pen | 1.0 | 12 |
| 2 | yellow | pencil | 0.6 | 12 |
| 3 | red | paper | 0.9 | 12 |
| 4 | white | mug | 1.7 | 12 |
Здесь видно, что появилась новая колонка new со значениями 12 для каждого элемента.
Для обновления значений можно использовать массив.
frame['new'] = [3.0, 1.3, 2.2, 0.8, 1.1] frame
| item | color | object | price | new |
|---|---|---|---|---|
| id | ||||
| 0 | blue | ball | 1.2 | 3.0 |
| 1 | green | pen | 1.0 | 1.3 |
| 2 | yellow | pencil | 0.6 | 2.2 |
| 3 | red | paper | 0.9 | 0.8 |
| 4 | white | mug | 1.7 | 1.1 |
Тот же подход используется для обновления целой колонки. Например, можно применить функцию np.arrange() для обновления значений колонки с помощью заранее заданной последовательности.
Колонки Dataframe также могут быть созданы с помощью присваивания объекта Series одной из них, например, определив объект Series , содержащий набор увеличивающихся значений с помощью np.arrange() .
>>> ser = pd.Series(np.arange(5)) >>> ser 0 0 1 1 2 2 3 3 4 4 dtype: int32
frame['new'] = ser frame
| item | color | object | price | new |
|---|---|---|---|---|
| id | ||||
| 0 | blue | ball | 1.2 | 0 |
| 1 | green | pen | 1.0 | 1 |
| 2 | yellow | pencil | 0.6 | 2 |
| 3 | red | paper | 0.9 | 3 |
| 4 | white | mug | 1.7 | 4 |
Наконец, для изменения одного значения нужно лишь выбрать элемент и присвоить ему новое значение.
>>> frame['price'][2] = 3.3
Вхождение значений
Функция isin() используется с объектами Series для определения вхождения значений в колонку. Она же подходит и для объектов Dataframe .
>>> frame.isin([1.0,'pen'])
| item | color | object | price | new |
|---|---|---|---|---|
| id | ||||
| 0 | False | False | False | False |
| 1 | False | True | True | True |
| 2 | False | False | False | False |
| 3 | False | False | False | False |
| 4 | False | False | False | False |
Возвращается Dataframe с булевыми значениями, где True указывает на те значения, где членство подтверждено. Если передать это значение в виде условия, тогда вернется Dataframe , где будут только значения, удовлетворяющие условию.
>>> frame[frame.isin([1.0,'pen'])]
| item | color | object | price | new |
|---|---|---|---|---|
| id | ||||
| 0 | NaN | NaN | NaN | NaN |
| 1 | NaN | pen | 1.0 | 1.0 |
| 2 | NaN | NaN | NaN | NaN |
| 3 | NaN | NaN | NaN | NaN |
| 4 | NaN | NaN | NaN | NaN |
Удаление колонки
Для удаления целой колонки и всего ее содержимого используется команда del .
>>> del frame['new'] >>> frame
| item | color | object | price |
|---|---|---|---|
| id | |||
| 0 | blue | ball | 1.2 |
| 1 | green | pen | 1.0 |
| 2 | yellow | pencil | 3.3 |
| 3 | red | paper | 0.9 |
| 4 | white | mug | 1.7 |
Фильтрация
Даже для Dataframe можно применять фильтры, используя определенные условия. Например, вам нужно получить все значения меньше определенного числа (допустим, 1,2).
>>> frame[frame 1.2]
| item | color | object | price |
|---|---|---|---|
| id | |||
| 0 | blue | ball | NaN |
| 1 | green | pen | 1.0 |
| 2 | yellow | pencil | NaN |
| 3 | red | paper | 0.9 |
| 4 | white | mug | NaN |
Результатом будет Dataframe со значениями меньше 1,2 на своих местах. На месте остальных будет NaN .
Dataframe из вложенного словаря
В Python часто используется вложенный dict :
>>> nestdict = 'red': 2012: 22, 2013: 33>, ... 'white': 2011: 13, 2012: 22, 2013: 16>, ... 'blue': 2011: 17, 2012: 27, 2013: 18>>
Эта структура данных, будучи переданной в качестве аргумента в DataFrame() , интерпретируется pandas так, что внешние ключи становятся названиями колонок, а внутренние — метками индексов.
При интерпретации вложенный структуры возможно такое, что не все поля будут совпадать. pandas компенсирует это несоответствие, добавляя NaN на место недостающих значений.
>>> nestdict = 'red': 2012: 22, 2013: 33>, ... 'white': 2011: 13, 2012: 22, 2013: 16>, ... 'blue': 2011: 17, 2012: 27, 2013: 18>> >>> frame2 = pd.DataFrame(nestdict) >>> frame2
| blue | red | white | |
|---|---|---|---|
| 2011 | 17 | NaN | 13 |
| 2012 | 27 | 22.0 | 22 |
| 2013 | 18 | 33.0 | 16 |
Транспонирование Dataframe
При работе с табличным структурами данных иногда появляется необходимость выполнить операцию перестановки (сделать так, чтобы колонки стали рядами и наоборот). pandas позволяет добиться этого очень просто. Достаточно добавить атрибут T .
>>> frame2.T
| 2011 | 2012 | 2013 | |
|---|---|---|---|
| blue | 17.0 | 27.0 | 18.0 |
| red | NaN | 22.0 | 33.0 |
| white | 13.0 | 22.0 | 16.0 |
Объекты Index
Зная, что такое Series и Dataframes , и понимая как они устроены, проще разобраться со всеми их достоинствами. Главная особенность этих структур — наличие объекта Index , который в них интегрирован.
Объекты Index являются метками осей и содержат другие метаданные. Вы уже знаете, как массив с метками превращается в объект Index , и что для него нужно определить параметр index в конструкторе.
>>> ser = pd.Series([5,0,3,8,4], index=['red','blue','yellow','white','green']) >>> ser.index Index(['red', 'blue', 'yellow', 'white', 'green'], dtype='object')
В отличие от других элементов в структурах данных pandas ( Series и Dataframe ) объекты index — неизменяемые. Это обеспечивает безопасность, когда нужно передавать данные между разными структурами.
У каждого объекта Index есть методы и свойства, которые нужны, чтобы узнавать значения.
Методы Index
Есть методы для получения информации об индексах из структуры данных. Например, idmin() и idmax() — структуры, возвращающие индексы с самым маленьким и большим значениями.
>>> ser.idxmin() 'blue' >>> ser.idxmax() 'white'
Индекс с повторяющимися метками
Пока что были только те случаи, когда у индексов одной структуры лишь одна, уникальная метка. Для большинства функций это обязательное условие, но не для структур данных pandas.
Определим, например, Series с повторяющимися метками.
>>> serd = pd.Series(range(6), index=['white','white','blue','green', 'green','yellow']) >>> serd white 0 white 1 blue 2 green 3 green 4 yellow 5 dtype: int64
Если метке соответствует несколько значений, то она вернет не один элемент, а объект Series .
>>> serd['white'] white 0 white 1 dtype: int64
То же применимо и к Dataframe . При повторяющихся индексах он возвращает Dataframe .
В случае с маленькими структурами легко определять любые повторяющиеся индексы, но если структура большая, то растет и сложность этой операции. Для этого в pandas у объектов Index есть атрибут is_unique . Он сообщает, есть ли индексы с повторяющимися метками в структуре ( Series или Dataframe ).
>>> serd.index.is_unique False >>> frame.index.is_unique True
Операции между структурами данных
Теперь когда вы знакомы со структурами данных, Series и Dataframe , а также базовыми операциями для работы с ними, стоит рассмотреть операции, включающие две или более структур.
Гибкие арифметические методы
Уже рассмотренные операции можно выполнять с помощью гибких арифметических методов:
Для их вызова нужно использовать другую спецификацию. Например, вместо того чтобы выполнять операцию для двух объектов Dataframe по примеру frame1 + frame2 , потребуется следующий формат:
>>> frame1.add(frame2)
| ball | mug | paper | pen | pencil | |
|---|---|---|---|---|---|
| blue | 6.0 | NaN | NaN | 6.0 | NaN |
| green | NaN | NaN | NaN | NaN | NaN |
| red | NaN | NaN | NaN | NaN | NaN |
| white | 20.0 | NaN | NaN | 20.0 | NaN |
| yellow | 19.0 | NaN | NaN | 19.0 | NaN |
Результат такой же, как при использовании оператора сложения + . Также стоит обратить внимание, что если названия индексов и колонок сильно отличаются, то результатом станет новый объект Dataframe , состоящий только из значений NaN .
Операции между Dataframe и Series
Pandas позволяет выполнять переносы между разными структурами, например, между Dataframe и Series . Определить две структуры можно следующим образом.
>>> frame = pd.DataFrame(np.arange(16).reshape((4,4)), ... index=['red', 'blue', 'yellow', 'white'], ... columns=['ball','pen','pencil','paper']) >>> frame
| ball | pen | pencil | paper | |
|---|---|---|---|---|
| red | 0 | 1 | 2 | 3 |
| blue | 4 | 5 | 6 | 7 |
| yellow | 8 | 9 | 10 | 11 |
| white | 12 | 13 | 14 | 15 |
>>> ser = pd.Series(np.arange(4), index=['ball','pen','pencil','paper']) >>> ser ball 0 pen 1 pencil 2 paper 3 dtype: int32
Они были специально созданы так, чтобы индексы в Series совпадали с названиями колонок в Dataframe . В таком случае можно выполнить прямую операцию.
>>> frame - ser
| ball | pen | pencil | paper | |
|---|---|---|---|---|
| red | 0 | 0 | 0 | 0 |
| blue | 4 | 4 | 4 | 4 |
| yellow | 8 | 8 | 8 | 8 |
| white | 12 | 12 | 12 | 12 |
По результату видно, что элементы Series были вычтены из соответствующих тому же индексу в колонках значений Dataframe .
Если индекс не представлен ни в одной из структур, то появится новая колонка с этим индексом и значениями NaN .
>>> ser['mug'] = 9 >>> ser ball 0 pen 1 pencil 2 paper 3 mug 9 dtype: int64
>>> frame - ser
| ball | mug | paper | pen | pencil | |
|---|---|---|---|---|---|
| red | 0 | NaN | 0 | 0 | 0 |
| blue | 4 | NaN | 4 | 4 | 4 |
| yellow | 8 | NaN | 8 | 8 | 8 |
| white | 12 | NaN | 12 | 12 | 12 |
Изменение типа столбца в pandas
Часто возникает необходимость изменить тип данных столбцов в DataFrame. Например, при создании DataFrame из списка списков, типы данных столбцов определяются автоматически, что может не всегда соответствовать ожидаемому.
table = [ ['a', '1.2', '4.2' ], ['b', '70', '0.03'], ['x', '5', '0' ], ] df = pd.DataFrame(table)
В этом примере, все столбцы будут иметь тип данных object, хотя второй и третий столбцы содержат числовые значения, которые мы хотели бы иметь в виде чисел с плавающей точкой.
Изменение типа данных столбцов после создания DataFrame
Если DataFrame уже создан, то для изменения типа данных столбцов можно использовать метод astype() .
df[1] = df[1].astype(float) df[2] = df[2].astype(float)
Здесь мы преобразовали второй и третий столбцы в числа с плавающей точкой.
Задание типа данных столбцов при создании DataFrame
Также типы данных столбцов можно задать сразу при создании DataFrame, используя параметр dtype в функции pd.DataFrame() .
df = pd.DataFrame(table, dtype=float)
Однако, в этом случае все столбцы будут иметь заданный тип данных, что может вызвать ошибки, если в некоторых столбцах содержатся нечисловые данные.
Динамическое изменение типа данных столбцов
Если в DataFrame много столбцов и неизвестно, какие из них нужно преобразовать, можно использовать метод apply() , который применяет указанную функцию к каждому столбцу.
df = df.apply(lambda col: col.astype(float) if col.str.replace('.','').str.isdigit().all() else col)
В этом примере мы применяем функцию, которая проверяет, содержат ли все строки в столбце только числовые символы, и если это так, преобразует столбец в числа с плавающей точкой.
Таким образом, есть несколько способов изменить тип данных столбцов в pandas DataFrame, и выбор конкретного метода зависит от конкретной ситуации.