Учитывая два фрейма данных, как показано ниже:
>>> import pandas as pd
>>> df_a = pd.DataFrame([{"a": 1, "b": 4}, {"a": 2, "b": 5}, {"a": 3, "b": 6}])
>>> df_b = pd.DataFrame([{"c": 2, "d": 7}, {"c": 3, "d": 8}])
>>> df_a
a b
0 1 4
1 2 5
2 3 6
>>> df_b
c d
0 2 7
1 3 8
мы хотели бы создать соединение в стиле SQL обоих фреймов данных, используя неупрощенный критерий, скажем, «df_b.c> df_a.a». Насколько я могу судить, хотя merge()
, безусловно, является частью решения, я не могу использовать его напрямую, поскольку он не принимает произвольные выражения для критерия «ВКЛ» (если я чего-то не упускаю?).
В SQL результаты выглядят так:
# inner join
sqlite> select * from df_a join df_b on c > a;
1|4|2|7
1|4|3|8
2|5|3|8
# outer join
sqlite> select * from df_a left outer join df_b on c > a;
1|4|2|7
1|4|3|8
2|5|3|8
3|6||
мой текущий подход к внутреннему соединению - создать декартово произведение df_a и df_b, добавив столбец «1» к обоим, затем используя merge () в столбце «1» и затем применив «c> a» критерии.
>>> import numpy as np
>>> df_a['ones'] = np.ones(3)
>>> df_b['ones'] = np.ones(2)
>>> cartesian = pd.merge(df_a, df_b, left_on='ones', right_on='ones')
>>> cartesian
a b ones c d
0 1 4 1 2 7
1 1 4 1 3 8
2 2 5 1 2 7
3 2 5 1 3 8
4 3 6 1 2 7
5 3 6 1 3 8
>>> cartesian[cartesian.c > cartesian.a]
a b ones c d
0 1 4 1 2 7
1 1 4 1 3 8
3 2 5 1 3 8
для внешнего соединения я не уверен в лучшем способе, пока я играл с получением внутреннего соединения, затем применял отрицание критериев, чтобы получить все другие строки, а затем пытался отредактировать это "отрицание "установить на оригинал, но на самом деле это не работает.
Изменить. HYRY ответил на конкретный вопрос здесь, но мне нужно было что-то более общее и большее в Pandas API, так как моим критерием соединения может быть что угодно, а не только одно сравнение. Для внешнего соединения сначала я добавляю дополнительный индекс к «левой» стороне, который будет поддерживать себя после того, как я выполню внутреннее соединение:
df_a['_left_index'] = df_a.index
затем мы делаем декартово и получаем внутреннее соединение:
cartesian = pd.merge(df_a, df_b, left_on='ones', right_on='ones')
innerjoin = cartesian[cartesian.c > cartesian.a]
затем я получаю дополнительные идентификаторы индексов в «df_a», которые нам понадобятся, и получаю строки из «df_a»:
remaining_left_ids = set(df_a['_left_index']).\
difference(innerjoin['_left_index'])
remaining = df_a.ix[remaining_left_ids]
затем мы используем прямую concat (), которая заменяет отсутствующие столбцы на «NaN» для левого края (я думал, что раньше этого не делали, но думаю, что это так):
outerjoin = pd.concat([innerjoin, remaining]).reset_index()
Идея HYRY сделать декартово только для тех столбцов, которые нам нужно сравнить, в основном является правильным ответом, хотя в моем конкретном случае это может быть немного сложно реализовать (обобщенно и все).
вопросов:
Как бы вы произвели «соединение» df_1 и df_2 на «c> a»? Вы бы применили тот же подход «декартово произведение, фильтр» или есть какой-то лучший способ?
Как бы вы создали такое же «левое внешнее соединение»?