Вступление
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:
# df1
user_id first_name last_name email
0 id001 Rivi Valti [email protected]
1 id002 Wynnie McMurty [email protected]
2 id003 Kristos Ivanets [email protected]
3 id004 Madalyn Max [email protected]
4 id005 Tobe Riddich [email protected]
5 id006 Regan Huyghe [email protected]
6 id007 Kristin Illis [email protected]
#df2
user_id image_url
0 id001 http://example.com/img/id001.png
1 id002 http://example.com/img/id002.jpg
2 id003 http://example.com/img/id003.bmp
3 id004 http://example.com/img/id004.jpg
4 id005 http://example.com/img/id005.png
Давайте объединим эти 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?