Источник: Nuances of Programming
Абстракция датафрейма является одной из наиболее полезных концепций в современной экосистеме управления данными. Вращается она главным образом вокруг табличных структур, которые имеют повышенную производительность при обновлении и запросе данных различными способами. Сериализация/десериализация этих структур из/в различные форматы файлов упрощает работу с данными. Более того, возможность производить различные SQL-подобные операции, такие как объединение, наряду с выполнением математических вычислений в самом датафрейме существенно расширяет возможности программиста.
Эта статья подчеркивает некоторые наиболее полезные операции, которые можно выполнять с помощью абстракции датафрейма. Реализовывать мы их будем через библиотеку Pandas. Постараюсь представить материал в интуитивно понятной форме, чтобы в дальнейшем вы могли применить эти знания в других случаях или при работе с другими фреймворками.
1. Конкатенация DataFrame
Есть два способа конкатенировать датафрейм A и B. Представьте их как проиндексированные таблицы. Эти две таблицы можно объединить либо по оси y, либо по оси x.
Если требуется конкатенировать их вдоль x, то вызов API будет таким:
import pandas as pdpd.concat([A, B], axis=1)
Если же вдоль y, то таким:
import pandas as pdpd.concat([A, B]) # по умолчанию axis = 0
Применение
Предположим, у вас есть большое количество CSV-файлов или XLSX-данных, которые нужно присоединить друг к другу. Одним из способов сделать это будет считать данные файлов в датафреймы и использовать инструкцию pd.concat([file_1, file_2]). Программно можно перебрать имена файлов (используя модуль glob для чтения набора имен файлов с помощью техники сопоставления шаблонов, например regex), считать их в датафрейм, соединить в памяти и сериализовать конкатенированные датафреймы в нужный формат файлов.
Вариант с axis = 0 используется нечасто, но его можно применять в сценариях, когда нужно обработать массивы данных, собранных с упорядочиванием. То есть, когда последовательность данных соответствует последовательности других массивов данных. В таком случае эти массивы можно объединить вдоль оси x, получив более объемное и значительное представление в табличном формате. Затем к полученной структуре можно применять операции, использующие все типы данных в ее столбцах.
2. Разделение DataFrame
Датафрейм можно разделить множеством способов, и выбор техники полностью зависит от цели этого разделения. Рассмотрим ряд случаев.
Просмотр сведений
В некоторых сценариях, особенно при написании кода с помощью блокнотов (например Jupyter), мы заглядываем в датафрейм, только чтобы понять, как он выглядит. В таких случаях можно использовать метод head().
import pandas as pdprint(df.head(10)) # выводит первые 10 строк dataframe
Исключение столбцов
Этот метод разделяет датафрейм вдоль оси y, то есть просто выбрасывает из него часть столбцов. Используется данный метод в типичном сценарии, когда нам не нужно, чтобы конечный DataFrame содержал эти столбцы, или когда мы предполагаем, что при дальнейшем обновлении структура станет занимать слишком много памяти.
import pandas as pddf.drop('COLUMN_NAME', inplace=True, axis=1)
# указывает, что 'COLUMN_NAME' находится на оси x
Удаление датафреймов друг из друга
Представим, что у нас есть датафрейм X, состоящий из столбцов [A, B, C, D], и датафрейм Y, состоящий из подмножества столбцов X. Нам нужно удалить Y из X. Это можно сделать так:
import pandas as pdpd.concat([X, Y]).drop_duplicates(keep=False)
Конкатенация этих датафреймов приведет к дублированию общих записей, которые в итоге будут удалены выражением keep = false функции drop_duplicates().
Применение
Предположим, что столбец A — это определенный вид ID сведений о работнике. К примеру, датафрейм X состоит из всех данных о работниках, а датафрейм Y содержит данные (с той же структурой) о работниках, не разбирающихся в Python. Нам нужно отфильтровать сведения о сотрудниках, которые не знакомы с Python.
Определение дельты записей на основе столбца
Представим, что у нас есть датафрейм X, состоящий из столбцов [A, B, C, D], а также датафрейм Y, состоящий из тех же столбцов. При этом некоторые элементы столбцов A этих датафреймов являются общими. Нам нужно получить из датафрейма X строки, которые не содержат значения из столбца A, находящиеся в столбце A датафрейма Y.
import pandas as pdX[~X['A'].isin(Y['A'])]
Применение
Взгляните на эту таблицу:
Эти пары могли быть сгенерированы, например, из двух журналов: старого и нового. Нам нужно найти пары ID, принадлежащие одному и тому же человеку. Предположим, что ваш отдел кадров неожиданно заявляет, что определенный список (hr_list) сотрудников с ID_1 больше в компании не работает. Как удалить их из этого датафрейма?
import pandas as pdfiltered_pairs = employee_pairs[~employee_pairs['ID_1'].isin(hr_list)]
Разделение на основе значений столбцов
Датафрейм можно фильтровать на основе значений столбца. В этом случае критерий отбора может включать несколько выражений при условии, что они будут возвращать логические значения.
import pandas as pdfiltered_df = df[~df['A'].isna() & (df['B'] > 10)]
# Возвращает строки, где столбец A не null, а значение столбца B больше 10.
Это простейший пример.
3. Подсчет записей в столбце
Это эффективный способ определения количества различных элементов в столбце.
Ответ на приведенный выше запрос можно получить следующим подходом:
4. Чтение фрагментов DataFrame
В некоторых случаях будет более эффективно считывать только части датафрейма, особенно при его больших размерах. Обратите внимание, что каждый датафрейм является индексированной табличной структурой, находящейся в памяти, а значит потребляющей пространство, потенциально нужное другим структурам данных. В связи с этим при работе с большими массивами информации всегда лучше считывать только ее нужную часть.
import pandas as pdpd.read_csv('file.csv', usecols=['A', 'B'])
# Считать только столбцы 'A' и 'B'
Более того, можно считывать большие файлы в отдельные фрагменты и маршалировать их в датафреймы.
import pandas as pdfor chunk in pd.read_csv('file.csv', chunksize=1000):
process(chunk)
Таким образом одновременно в памяти удерживается только фрагмент размером chunksize.
5. Применение функций к строкам
Бывают случаи, в которых требуется внести изменения в конкретные столбцы детафрейма. К примеру, в датафрейме X, содержащем столбцы A, B и C, мы можем применить функцию f() к значениям столбца B, чтобы сохранить их в столбце D.
import pandas as pddf['D'] = df.apply(lambda row: f(row['B'], row['C']), axis=1)
Эта операция окажется намного быстрее, чем перебор всего датафрейма с помощью iterrows().
Есть и альтернативный метод. Его можно использовать, когда функцию f() требуется применить только к одному столбцу.
import pandas as pddf['D'] = df['B'].map(lambda b: f(b))
6. Объединение двух датафреймов
По аналогии с реляционными базами данных датафреймы можно объединять merge , используя разрешающий столбец.
import pandas as pdpd.merge(left=df_a, left_on['A'], right=df_b, right_on=['B'], how='inner')
# Также работает для left и right объединения.
Однако стоит заметить, что операция merge является дорогостоящей, в связи с чем перед слиянием больших датасетов стоит проявлять особое внимание. В случаях, когда датасеты слишком велики, рекомендуется использовать методы группировки (англ.), чтобы избежать перегрузки памяти и связанных с этим проблем производительности.
7. Переименование столбцов
Переименовывать столбцы особенно полезно перед сериализацией файла или перед внедрением стороннего хранилища данных.
import pandas
df = df.rename(columns={
"A_1": "A" "B_1": "B" })
# переименовывает оригинальные столбцы ["A_1", "B_1"] в ["A", "B"].
Читайте также:
Перевод Dasun Pubudumal: 7 Useful Pandas Operations To Use on DataFrames