Моя шпаргалка по pandas
Один преподаватель как-то сказал мне, что если поискать аналог программиста в мире книг, то окажется, что программисты похожи не на учебники, а на оглавления учебников: они не помнят всего, но знают, как быстро найти то, что им нужно.
Возможность быстро находить описания функций позволяет программистам продуктивно работать, не теряя состояния потока. Поэтому я и создал представленную здесь шпаргалку по pandas и включил в неё то, чем пользуюсь каждый день, создавая веб-приложения и модели машинного обучения.
Нельзя сказать, что это — исчерпывающий список возможностей pandas , но сюда входят функции, которыми я пользуюсь чаще всего, примеры и мои пояснения по поводу ситуаций, в которых эти функции особенно полезны.
1. Подготовка к работе
Если вы хотите самостоятельно опробовать то, о чём тут пойдёт речь, загрузите набор данных Anime Recommendations Database с Kaggle. Распакуйте его и поместите в ту же папку, где находится ваш Jupyter Notebook (далее — блокнот).
Теперь выполните следующие команды.
После этого у вас должна появиться возможность воспроизвести то, что я покажу в следующих разделах этого материала.
2. Импорт данных
▍Загрузка CSV-данных
Здесь я хочу рассказать о преобразовании CSV-данных непосредственно в датафреймы (в объекты Dataframe). Иногда при загрузке данных формата CSV нужно указывать их кодировку (например, это может выглядеть как encoding=’ISO-8859–1′ ). Это — первое, что стоит попробовать сделать в том случае, если оказывается, что после загрузки данных датафрейм содержит нечитаемые символы.
Загруженные CSV-данные
Существует похожая функция для загрузки данных из Excel-файлов — pd.read_excel .
▍Создание датафрейма из данных, введённых вручную
Это может пригодиться тогда, когда нужно вручную ввести в программу простые данные. Например — если нужно оценить изменения, претерпеваемые данными, проходящими через конвейер обработки данных.
Данные, введённые вручную
▍Копирование датафрейма
Копирование датафреймов может пригодиться в ситуациях, когда требуется внести в данные изменения, но при этом надо и сохранить оригинал. Если датафреймы нужно копировать, то рекомендуется делать это сразу после их загрузки.
Копия датафрейма
3. Экспорт данных
▍Экспорт в формат CSV
При экспорте данных они сохраняются в той же папке, где находится блокнот. Ниже показан пример сохранения первых 10 строк датафрейма, но то, что именно сохранять, зависит от конкретной задачи.
Экспортировать данные в виде Excel-файлов можно с помощью функции df.to_excel .
4. Просмотр и исследование данных
▍Получение n записей из начала или конца датафрейма
Сначала поговорим о выводе первых n элементов датафрейма. Я часто вывожу некоторое количество элементов из начала датафрейма где-нибудь в блокноте. Это позволяет мне удобно обращаться к этим данным в том случае, если я забуду о том, что именно находится в датафрейме. Похожую роль играет и вывод нескольких последних элементов.
Данные из начала датафрейма
Данные из конца датафрейма
▍Подсчёт количества строк в датафрейме
Функция len(), которую я тут покажу, не входит в состав pandas . Но она хорошо подходит для подсчёта количества строк датафреймов. Результаты её работы можно сохранить в переменной и воспользоваться ими там, где они нужны.
▍Подсчёт количества уникальных значений в столбце
Для подсчёта количества уникальных значений в столбце можно воспользоваться такой конструкцией:
▍Получение сведений о датафрейме
В сведения о датафрейме входит общая информация о нём вроде заголовка, количества значений, типов данных столбцов.
Сведения о датафрейме
Есть ещё одна функция, похожая на df.info — df.dtypes . Она лишь выводит сведения о типах данных столбцов.
▍Вывод статистических сведений о датафрейме
Знание статистических сведений о датафрейме весьма полезно в ситуациях, когда он содержит множество числовых значений. Например, знание среднего, минимального и максимального значений столбца rating даёт нам некоторое понимание того, как, в целом, выглядит датафрейм. Вот соответствующая команда:
Статистические сведения о датафрейме
▍Подсчёт количества значений
Для того чтобы подсчитать количество значений в конкретном столбце, можно воспользоваться следующей конструкцией:
Подсчёт количества элементов в столбце
5. Извлечение информации из датафреймов
▍Создание списка или объекта Series на основе значений столбца
Это может пригодиться в тех случаях, когда требуется извлекать значения столбцов в переменные x и y для обучения модели. Здесь применимы следующие команды:
Результаты работы команды anime[‘genre’].tolist()
Результаты работы команды anime[‘genre’]
▍Получение списка значений из индекса
Поговорим о получении списков значений из индекса. Обратите внимание на то, что я здесь использовал датафрейм anime_modified , так как его индексные значения выглядят интереснее.
Результаты выполнения команды
▍Получение списка значений столбцов
Вот команда, которая позволяет получить список значений столбцов:
Результаты выполнения команды
6. Добавление данных в датафрейм и удаление их из него
▍Присоединение к датафрейму нового столбца с заданным значением
Иногда мне приходится добавлять в датафреймы новые столбцы. Например — в случаях, когда у меня есть тестовый и обучающий наборы в двух разных датафреймах, и мне, прежде чем их скомбинировать, нужно пометить их так, чтобы потом их можно было бы различить. Для этого используется такая конструкция:
▍Создание нового датафрейма из подмножества столбцов
Это может пригодиться в том случае, если требуется сохранить в новом датафрейме несколько столбцов огромного датафрейма, но при этом не хочется выписывать имена столбцов, которые нужно удалить.
Результат выполнения команды
▍Удаление заданных столбцов
Этот приём может оказаться полезным в том случае, если из датафрейма нужно удалить лишь несколько столбцов. Если удалять нужно много столбцов, то эта задача может оказаться довольно-таки утомительной, поэтому тут я предпочитаю пользоваться возможностью, описанной в предыдущем разделе.
Результаты выполнения команды
▍Добавление в датафрейм строки с суммой значений из других строк
Для демонстрации этого примера самостоятельно создадим небольшой датафрейм, с которым удобно работать. Самое интересное здесь — это конструкция df.sum(axis=0) , которая позволяет получать суммы значений из различных строк.
Результат выполнения команды
Команда вида df.sum(axis=1) позволяет суммировать значения в столбцах.
Похожий механизм применим и для расчёта средних значений. Например — df.mean(axis=0) .
7. Комбинирование датафреймов
▍Конкатенация двух датафреймов
Эта методика применима в ситуациях, когда имеются два датафрейма с одинаковыми столбцами, которые нужно скомбинировать.
В данном примере мы сначала разделяем датафрейм на две части, а потом снова объединяем эти части:
Датафрейм df1
Датафрейм df2
Датафрейм, объединяющий df1 и df2
▍Слияние датафреймов
Функция df.merge , которую мы тут рассмотрим, похожа на левое соединение SQL. Она применяется тогда, когда два датафрейма нужно объединить по некоему столбцу.
Результаты выполнения команды
8. Фильтрация
▍Получение строк с нужными индексными значениями
Индексными значениями датафрейма anime_modified являются названия аниме. Обратите внимание на то, как мы используем эти названия для выбора конкретных столбцов.
Результаты выполнения команды
▍Получение строк по числовым индексам
Эта методика отличается от той, которая описана в предыдущем разделе. При использовании функции df.iloc первой строке назначается индекс 0 , второй — индекс 1 , и так далее. Такие индексы назначаются строкам даже в том случае, если датафрейм был модифицирован и в его индексном столбце используются строковые значения.
Следующая конструкция позволяет выбрать три первых строки датафрейма:
Результаты выполнения команды
▍Получение строк по заданным значениям столбцов
Для получения строк датафрейма в ситуации, когда имеется список значений столбцов, можно воспользоваться следующей командой:
Результаты выполнения команды
Если нас интересует единственное значение — можно воспользоваться такой конструкцией:
▍Получение среза датафрейма
Эта техника напоминает получение среза списка. А именно, речь идёт о получении фрагмента датафрейма, содержащего строки, соответствующие заданной конфигурации индексов.
Результаты выполнения команды
▍Фильтрация по значению
Из датафреймов можно выбирать строки, соответствующие заданному условию. Обратите внимание на то, что при использовании этого метода сохраняются существующие индексные значения.
Результаты выполнения команды
9. Сортировка
Для сортировки датафреймов по значениям столбцов можно воспользоваться функцией df.sort_values :
Результаты выполнения команды
10. Агрегирование
▍Функция df.groupby и подсчёт количества записей
Вот как подсчитать количество записей с различными значениями в столбцах:
Результаты выполнения команды
▍Функция df.groupby и агрегирование столбцов различными способами
Обратите внимание на то, что здесь используется reset_index() . В противном случае столбец type становится индексным столбцом. В большинстве случаев я рекомендую делать то же самое.
▍Создание сводной таблицы
Для того чтобы извлечь из датафрейма некие данные, нет ничего лучше, чем сводная таблица. Обратите внимание на то, что здесь я серьёзно отфильтровал датафрейм, что ускорило создание сводной таблицы.
Результаты выполнения команды
11. Очистка данных
▍Запись в ячейки, содержащие значение NaN, какого-то другого значения
Здесь мы поговорим о записи значения 0 в ячейки, содержащие значение NaN . В этом примере мы создаём такую же сводную таблицу, как и ранее, но без использования fill_value=0 . А затем используем функцию fillna(0) для замены значений NaN на 0 .
Таблица, содержащая значения NaN
Результаты замены значений NaN на 0
12. Другие полезные возможности
▍Отбор случайных образцов из набора данных
Я использую функцию df.sample каждый раз, когда мне нужно получить небольшой случайный набор строк из большого датафрейма. Если используется параметр frac=1 , то функция позволяет получить аналог исходного датафрейма, строки которого будут перемешаны.
Результаты выполнения команды
▍Перебор строк датафрейма
Следующая конструкция позволяет перебирать строки датафрейма:
Результаты выполнения команды
▍Борьба с ошибкой IOPub data rate exceeded
Если вы сталкиваетесь с ошибкой IOPub data rate exceeded — попробуйте, при запуске Jupyter Notebook, воспользоваться следующей командой:
Итоги
Здесь я рассказал о некоторых полезных приёмах использования pandas в среде Jupyter Notebook. Надеюсь, моя шпаргалка вам пригодится.
Уважаемые читатели! Есть ли какие-нибудь возможности pandas , без которых вы не представляете своей повседневной работы?
Rukovodstvo
статьи и идеи для разработчиков программного обеспечения и веб-разработчиков.
Как объединить DataFrames в Pandas — merge (), join (), append (), concat () и update ()
Введение Pandas предоставляет огромный набор методов и функций для управления данными, включая слияние DataFrames. Слияние DataFrames позволяет вам создавать новый DataFrame без изменения исходного источника данных или изменения исходного источника данных. Если вы знакомы с SQL или аналогичным типом табличных данных, вы, вероятно, знакомы с термином соединение, которое означает объединение DataFrames для формирования нового DataFrame. Если вы новичок, может быть трудно полностью понять типы соединения (в
Время чтения: 14 мин.
Вступление
Pandas предоставляет огромный набор методов и функций для управления данными, включая слияние DataFrames. Слияние DataFrames позволяет вам создавать новый DataFrame без изменения исходного источника данных или изменения исходного источника данных.
Если вы знакомы с SQL или аналогичным типом табличных данных, вы, вероятно, знакомы с термином join , что означает объединение DataFrames для формирования нового DataFrame. Если вы новичок, может быть трудно полностью понять типы соединения ( внутреннее, внешнее, левое, правое ). В этом руководстве мы рассмотрим типы соединений с примерами.
Наше основное внимание будет сосредоточено на использовании функций merge() и concat() Однако мы обсудим другие методы слияния, чтобы дать вам как можно больше практических альтернатив.
В этом руководстве мы используем Pandas версии 1.1.4 и NumPy версии 1.19.4 .
Для вашего удобства вот содержание:
- Объединить фреймы данных с помощью merge ()
- Объединить фреймы данных с помощью join ()
- Объединить фреймы данных с помощью append ()
- Объединить фреймы данных с помощью concat ()
- Объединение фреймов данных с помощью comb_first () и update ()
Объединить фреймы данных с помощью merge ()
Начнем с настройки наших DataFrames, которые мы будем использовать в оставшейся части учебника.
df1 будет включать наш воображаемый список пользователей с именами, адресами электронной почты и идентификаторами.
При разработке баз данных считается хорошей практикой хранить настройки профиля (например, цвет фона, ссылку на изображение аватара, размер шрифта и т. Д.) В отдельной таблице от данных пользователя (электронная почта, дата добавления и т. Д.). Эти таблицы могут иметь взаимно-однозначное отношение.
Чтобы смоделировать этот сценарий, мы сделаем то же самое, создав df2 с URL-адресами изображений и идентификаторами пользователей:
Вот как выглядят наши DataFrames:
Давайте объединим эти DataFrames с функцией merge() . Во-первых, взгляните на все параметры, которые может принимать эта функция:
Большинство этих параметров имеют значения по умолчанию, за исключением левого и правого . Эти два параметра являются именами DataFrames, которые мы будем объединять. Сама функция вернет новый DataFrame, который мы сохраним в переменной df3_merged
Введите следующий код в оболочку Python:
Поскольку оба наших DataFrames имеют столбец user_id с одинаковым именем, merge() автоматически объединяет две таблицы, соответствующие этому ключу. Если бы у нас было два столбца с разными именами, мы могли бы использовать left_on=’left_column_name’ и right_on=’right_column_name’ чтобы явно указать ключи для обоих DataFrames.
df3_merged чтобы увидеть ее содержимое:
Вы заметите, что df3_merged имеет только 5 строк, в то время как исходный df1 имел 7. Почему?
Когда значение по умолчанию для how установлено на inner , новый DataFrame создается из пересечения левого и правого DataFrame. Следовательно, если user_id отсутствует в одной из таблиц, его не будет в объединенном DataFrame.
Это останется верным, даже если поменять местами левую и правую строки:
Пользователи с идентификаторами ‘id006’ и ‘id007’ не являются частью объединенных DataFrames, поскольку они не пересекаются в обеих таблицах.
Однако бывают случаи, когда мы хотим использовать один из DataFrames в качестве основного DataFrame и включать все строки из него, даже если они не все пересекаются друг с другом. То есть, чтобы иметь всех наших пользователей, в то время как image_url является обязательным.
Как? Используя merge() , мы можем передать аргумент ‘left’ how :
При левом соединении мы включили все элементы левого DataFrame ( df1 ) и каждый элемент правого DataFrame ( df2 ). Выполнение приведенного выше кода отобразит следующее:
Ячейки, которые не имеют совпадающих значений с левым DataFrame, заполняются NaN .
Почему бы нам не попробовать правильное соединение? Создайте следующий объединенный DataFrame:
Как вы могли ожидать, правое соединение вернет каждое значение из левого DataFrame, которое соответствует правому DataFrame:
Поскольку каждая строка в df2 имеет значение в df1 , в этом случае это right соединение аналогично inner
Давайте посмотрим на outer соединения. Чтобы лучше всего проиллюстрировать, как они работают, давайте поменяем местами наши DataFrames и создадим две новые переменные для левого и внешнего соединений:
Имейте в виду, что наш левый DataFrame — это df2 а правый DataFrame — это df1 . Использование how=’outer’ объединяет DataFrames, совпадающие по ключу, но также включает значения, которые отсутствуют или не совпадают.
Мы также добавили indicator и установили для него значение True чтобы Pandas добавил дополнительный столбец _merge в конец нашего DataFrame. Этот столбец сообщает нам, была ли найдена строка в левом, правом или обоих фреймах данных.
df_left выглядит так:
Однако в df_outer есть такие данные:
Обратите внимание, что в df_outer DataFrame id006 и id007 существует только в правом DataFrame (в данном случае это df1 ). Если мы попытаемся сравнить левое и внешнее соединения, не меняя местами, мы получим одинаковые результаты для них обоих.
Объединить фреймы данных с помощью join ()
В отличие от merge() который является методом экземпляра Pandas, join() является методом самого DataFrame. Это означает, что мы можем использовать его как статический метод в DataFrame: DataFrame.join(other, on=None, how=’left’, lsuffix=», rsuffix=», sort=False) .
DataFrame, из которого мы вызываем join() будет нашим левым DataFrame. DataFrame в other аргументе будет нашим правильным DataFrame.
Параметр on может принимать один или несколько [‘key1’, ‘key2’ . ] ) для определения соответствующего ключа, в то время how параметр how принимает один из аргументов дескриптора (левый, правый, внешний, внутренний), и он по умолчанию установлено left
Попробуем присоединить df2 к df1 :
Как и функция merge() join() автоматически пытается сопоставить ключи (столбцы) с тем же именем. В нашем случае это ключ user_id
Приведенный выше код распечатывает это:
Вы, наверное, заметили «повторяющийся столбец» под названием user_id_right . Если вы не хотите отображать этот столбец, вы можете установить user_id в качестве индекса для обоих столбцов, чтобы он присоединялся без суффикса:
Таким образом мы избавляемся от user_id и вместо этого устанавливаем его в качестве столбца индекса. Это дает нам более чистый результирующий DataFrame:
Объединить фреймы данных с помощью append ()
Как указывает официальная документация Pandas, поскольку concat() и append() возвращают новые копии DataFrames, чрезмерное использование этих методов может повлиять на производительность вашей программы.
Добавление очень полезно, когда вы хотите объединить два DataFrames только по оси строк. Это означает, что вместо сопоставления данных в их столбцах нам нужен новый DataFrame, содержащий все строки 2 DataFrame.
Давайте df2 к df1 и распечатаем результат:
Использование append() не приведет к сопоставлению DataFrames ни по каким ключам. Он просто добавит другой DataFrame к первому и вернет его копию. Если формы DataFrames не совпадают, Pandas заменит все несовпадающие ячейки на NaN.
Результат для добавления двух DataFrames выглядит следующим образом:
Большинство пользователей выбирают concat() append() поскольку он также предоставляет параметр сопоставления ключей и оси.
Объединить фреймы данных с помощью concat ()
Конкатенация немного более гибкая по сравнению с merge() и join() поскольку она позволяет нам комбинировать DataFrames по вертикали (по строкам) или по горизонтали (по столбцам).
Компромисс заключается в том, что любые несоответствующие данные будут отброшены. Вот полная функция с параметрами:
Вот наиболее часто используемые параметры функции concat() :
- objs — это список объектов DataFrame ([df1, df2, . ]) для объединения
- axis определяет направление конкатенации, 0 для строк и 1 для столбцов
- join может быть inner (пересечение) или outer (объединение)
- ignore_index по умолчанию установлен на False что позволяет значениям индекса оставаться такими, какими они были в исходных DataFrames, может привести к дублированию значений индекса. Если установлено значение True , он будет игнорировать исходные значения и повторно назначать значения индекса в последовательном порядке.
- keys позволяет нам построить иерархический индекс. Подумайте об этом как о другом уровне индекса, который добавлен слева от DataFrame, который помогает нам различать индексы, когда значения не уникальны.
Давайте создадим новый DataFrame с теми же типами столбцов с df2 , но этот включает image_url для id006 и id007 :
Чтобы объединить df2 и df2_addition строкам, мы можем передать их в списке в качестве objs и присвоить полученный DataFrame новой переменной:
Мы успешно заполнили недостающие значения:
Однако обратите внимание на индексы в крайнем левом столбце. Индексы 0 и 1 повторяются. Чтобы получить совершенно новые и уникальные значения индекса, мы передаем True параметру ignore_index
Теперь наш df_row_concat имеет уникальные значения индекса:
Как мы упоминали ранее, конкатенация может работать как по горизонтали, так и по вертикали. Чтобы объединить два DataFrames вместе по столбцам, нам нужно будет изменить значение axis 0 по 1 :
Вы заметите, что это не работает как слияние, сопоставление двух таблиц по ключу:
Если бы в нашем правом DataFrame даже не было user_id , эта конкатенация все равно вернула бы тот же результат. Функция concat() склеивает два DataFrames вместе, принимая во внимание значения индексов DataFrames и форму таблицы.
Он не выполняет сопоставление ключей, например merge() или join() . Попробуйте разные комбинации конкатенации, изменив join чтобы увидеть различия!
Объединение фреймов данных с помощью comb_first () и update ()
В некоторых случаях вы можете захотеть заполнить недостающие данные в вашем DataFrame, объединив их с другим DataFrame. Таким образом вы сохраните все не пропущенные значения в первом фрейме данных, заменив все NaN доступными не пропущенными значениями из второго фрейма данных (если они есть).
В этом примере мы импортируем NumPy, чтобы использовать значения NaN Если вы установили Pandas с помощью pip , NumPy уже должен быть установлен.
Введите следующий код в оболочку Python или файл сценария:
df_first df_first имеет 3 столбца и по 1 пропущенному значению в каждом из них:
В то время как df_second имеет только 2 столбца и одно отсутствующее значение в первом столбце:
Мы можем использовать df_second для исправления отсутствующих значений в df_first всеми соответствующими значениями:
Как упоминалось ранее, использование combine_first() заменит NaN только в порядке индексации и оставит все не пропущенные значения в первом DataFrame такими, какие они есть:
С другой стороны, если мы хотим перезаписать значения в df_first соответствующими значениями из df_second (независимо от того, являются они NaN или нет), мы бы использовали метод update() .
Давайте сначала добавим в наш код еще один DataFrame:
Форма (1, 3) — 1 строка и три столбца, не считая индекса:
Теперь давайте обновим df_first значениями из df_third :
Имейте в виду, что в отличие от combine_first() , update() не возвращает новый DataFrame. Он изменяет df_first на месте, изменяя соответствующие значения:
Для параметра overwrite update() по умолчанию установлено значение True Вот почему он изменяет все соответствующие значения, а не только значения NaN Мы можем изменить его на False чтобы заменить только значения NaN
Вот окончательное состояние нашего df_tictactoe df_tictactoe:
Мы не только успешно обновили значения, но и выиграли игру «Крестики-нолики»!
Заключение
Pandas предоставляет мощные инструменты для объединения DataFrames. Но бывает сложно решить, когда что использовать. Хотя в большинстве случаев функции merge() достаточно, в некоторых случаях вы можете использовать concat() для слияния по строкам, или использовать join() с суффиксами, или избавиться от отсутствующих значений с помощью combine_first() и update() . Вы даже можете добавлять строки данных с помощью append() .
Используйте ту функцию, которая вам удобна и лучше всего подходит для вашей задачи. Как эти функции помогут вам управлять данными в Pandas?
Как создать DataFrames Pandas в Python – 7 методов
Фрейм данных – это двухмерный набор данных, структура, в которой данные хранятся в табличной форме. Наборы данных упорядочены по строкам и столбцам; мы можем хранить несколько наборов данных во фрейме данных. Мы можем выполнять различные арифметические операции, такие как добавление выбора столбца или строки и столбцов или строк во фрейме данных.
Мы можем импортировать DataFrames из внешнего хранилища; эти хранилища могут быть базой данных SQL, файлом CSV или файлом Excel. Мы также можем использовать списки, словарь, список словаря и т. д.
В этом руководстве мы научимся создавать фрейм данных несколькими способами. Давайте разберемся как создать DataFrames Pandas в Python. Во-первых, нам нужно установить библиотеку pandas в среду Python.
Пустой фрейм данных
Мы можем создать базовый пустой фрейм данных. Для создания DataFrame необходимо вызвать конструктор фрейма данных.
Метод – 2: создать фрейм данных с помощью списка
Мы можем создать фрейм данных, используя простой список или список списков. Давайте разберемся в следующем примере.
Метод – 3: Dataframe из dict ndarray / lists
Dict ndarray / lists можно использовать для создания фрейма данных, все ndarray должны иметь одинаковую длину. По умолчанию индекс будет диапазоном(n); где n обозначает длину массива.
Метод – 4: Создание фрейма данных индексов с использованием массивов
Давайте разберемся в примере создания фрейм данных индексов с использованием массивов.
В приведенном выше коде мы определили имя столбца с различными названиями автомобилей и их рейтингами. Мы использовали массив для создания индексов.
Метод – 5: Dataframe из списка dicts
Мы можем передать списки словарей в качестве входных данных для создания фрейма данных Pandas. Имена столбцов по умолчанию используются в качестве ключей.
Давайте разберемся в другом примере создания фрейма данных pandas из списка словарей с индексом строки и индексом столбца.
Рассмотрим пример создания фрейма данных путем передачи списков словарей и строк.
Мы обсудили три способа создания фрейма данных с использованием списков словаря.
Метод – 6: с помощью функции zip()
Функция zip() используется для объединения двух списков. Давайте разберемся в следующем примере.
Метод – 7: из Dicts серии
Словарь можно передать для создания фрейма данных. Мы можем использовать Dicts of series, где последующий индекс представляет собой объединение всех серий переданного значения индекса. Давайте разберем на примере.
Combining DataFrames with Pandas
In many “real world” situations, the data that we want to use come in multiple files. We often need to combine these files into a single DataFrame to analyze the data. The pandas package provides various methods for combining DataFrames including merge and concat .
To work through the examples below, we first need to load the species and surveys files into pandas DataFrames. In iPython:
Take note that the read_csv method we used can take some additional options which we didn’t use previously. Many functions in Python have a set of options that can be set by the user if needed. In this case, we have told pandas to assign empty values in our CSV to NaN keep_default_na=False, na_values=[«»] . More about all of the read_csv options here.
Concatenating DataFrames
We can use the concat function in pandas to append either columns or rows from one DataFrame to another. Let’s grab two subsets of our data to see how this works.
When we concatenate DataFrames, we need to specify the axis. axis=0 tells pandas to stack the second DataFrame UNDER the first one. It will automatically detect whether the column names are the same and will stack accordingly. axis=1 will stack the columns in the second DataFrame to the RIGHT of the first DataFrame. To stack the data vertically, we need to make sure we have the same columns and associated column format in both datasets. When we stack horizontally, we want to make sure what we are doing makes sense (i.e. the data are related in some way).
Row Index Values and Concat
Have a look at the vertical_stack dataframe? Notice anything unusual? The row indexes for the two data frames survey_sub and survey_sub_last10 have been repeated. We can reindex the new dataframe using the reset_index() method.
Writing Out Data to CSV
We can use the to_csv command to do export a DataFrame in CSV format. Note that the code below will by default save the data into the current working directory. We can save it to a different folder by adding the foldername and a slash to the file vertical_stack.to_csv(‘foldername/out.csv’) . We use the ‘index=False’ so that pandas doesn’t include the index number for each line.
Check out your working directory to make sure the CSV wrote out properly, and that you can open it! If you want, try to bring it back into Python to make sure it imports properly.
Challenge — Combine Data
In the data folder, there are two survey data files: surveys2001.csv and surveys2002.csv . Read the data into Python and combine the files to make one new data frame. Create a plot of average plot weight by year grouped by sex. Export your results as a CSV and make sure it reads back into Python properly.
Joining DataFrames
When we concatenated our DataFrames we simply added them to each other — stacking them either vertically or side by side. Another way to combine DataFrames is to use columns in each dataset that contain common values (a common unique id). Combining DataFrames using a common field is called “joining”. The columns containing the common values are called “join key(s)”. Joining DataFrames in this way is often useful when one DataFrame is a “lookup table” containing additional data that we want to include in the other.
NOTE: This process of joining tables is similar to what we do with tables in an SQL database.
For example, the species.csv file that we’ve been working with is a lookup table. This table contains the genus, species and taxa code for 55 species. The species code is unique for each line. These species are identified in our survey data as well using the unique species code. Rather than adding 3 more columns for the genus, species and taxa to each of the 35,549 line Survey data table, we can maintain the shorter table with the species information. When we want to access that information, we can create a query that joins the additional columns of information to the Survey data.
Storing data in this way has many benefits including:
- It ensures consistency in the spelling of species attributes (genus, species and taxa) given each species is only entered once. Imagine the possibilities for spelling errors when entering the genus and species thousands of times!
- It also makes it easy for us to make changes to the species information once without having to find each instance of it in the larger survey data.
- It optimizes the size of our data.
Joining Two DataFrames
To better understand joins, let’s grab the first 10 lines of our data as a subset to work with. We’ll use the .head method to do this. We’ll also read in a subset of the species table.
In this example, species_sub is the lookup table containing genus, species, and taxa names that we want to join with the data in survey_sub to produce a new DataFrame that contains all of the columns from both species_df and survey_df .
Identifying join keys
To identify appropriate join keys we first need to know which field(s) are shared between the files (DataFrames). We might inspect both DataFrames to identify these columns. If we are lucky, both DataFrames will have columns with the same name that also contain the same data. If we are less lucky, we need to identify a (differently-named) column in each DataFrame that contains the same information.
In our example, the join key is the column containing the two-letter species identifier, which is called species_id .
Now that we know the fields with the common species ID attributes in each DataFrame, we are almost ready to join our data. However, since there are different types of joins, we also need to decide which type of join makes sense for our analysis.
Inner joins
The most common type of join is called an inner join. An inner join combines two DataFrames based on a join key and returns a new DataFrame that contains only those rows that have matching values in both of the original DataFrames.
Inner joins yield a DataFrame that contains only rows where the value being joined exists in BOTH tables. An example of an inner join, adapted from Jeff Atwood’s blogpost about SQL joins is below:
The pandas function for performing joins is called merge and an Inner join is the default option:
The result of an inner join of survey_sub and species_sub is a new DataFrame that contains the combined set of columns from survey_sub and species_sub . It only contains rows that have two-letter species codes that are the same in both the survey_sub and species_sub DataFrames. In other words, if a row in survey_sub has a value of species_id that does not appear in the species_id column of species , it will not be included in the DataFrame returned by an inner join. Similarly, if a row in species_sub has a value of species_id that does not appear in the species_id column of survey_sub , that row will not be included in the DataFrame returned by an inner join.
The two DataFrames that we want to join are passed to the merge function using the left and right argument. The left_on=’species’ argument tells merge to use the species_id column as the join key from survey_sub (the left DataFrame). Similarly , the right_on=’species_id’ argument tells merge to use the species_id column as the join key from species_sub (the right DataFrame). For inner joins, the order of the left and right arguments does not matter.
The result merged_inner DataFrame contains all of the columns from survey_sub (record id, month, day, etc.) as well as all the columns from species_sub (species_id, genus, species, and taxa).
Notice that merged_inner has fewer rows than survey_sub . This is an indication that there were rows in surveys_df with value(s) for species_id that do not exist as value(s) for species_id in species_df .
Left joins
What if we want to add information from species_sub to survey_sub without losing any of the information from survey_sub ? In this case, we use a different type of join called a “left outer join”, or a “left join”.
Like an inner join, a left join uses join keys to combine two DataFrames. Unlike an inner join, a left join will return all of the rows from the left DataFrame, even those rows whose join key(s) do not have values in the right DataFrame. Rows in the left DataFrame that are missing values for the join key(s) in the right DataFrame will simply have null (i.e., NaN or None) values for those columns in the resulting joined DataFrame.
Note: a left join will still discard rows from the right DataFrame that do not have values for the join key(s) in the left DataFrame.
A left join is performed in pandas by calling the same merge function used for inner join, but using the how=’left’ argument:
The result DataFrame from a left join ( merged_left ) looks very much like the result DataFrame from an inner join ( merged_inner ) in terms of the columns it contains. However, unlike merged_inner , merged_left contains the same number of rows as the original survey_sub DataFrame. When we inspect merged_left , we find there are rows where the information that should have come from species_sub (i.e., species_id , genus , and taxa ) is missing (they contain NaN values):
These rows are the ones where the value of species_id from survey_sub (in this case, PF ) does not occur in species_sub .