给定两个数据帧,如下所示:
>>> 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()肯定是解决方案的一部分,但我不能直接使用它,因为它不接受“ ON”条件的任意表达式(除非我遗漏了什么?)。
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||
我目前用于内部联接的方法是,通过向两者都添加一列“ 1”,然后在“ 1”列上使用merge(),然后应用“ c> a”,来生成df_a和df_b的笛卡尔积。标准。
>>> 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”中获取我们需要的其他索引ID,并从“ 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的想法是只对那些我们需要比较的cols进行笛卡尔运算的想法基本上是正确的答案,尽管在我的特定情况下,实现(通用化和全部化)可能会有些棘手。
问题:
您将如何在“ c> a”上产生df_1和df_2的“ join”?您会采用相同的“笛卡尔积,过滤器”方法还是有更好的方法?
您将如何产生相同的“左外部连接”?
我使用ufunc的外部方法来计算结果,这是示例:
首先,一些数据:
import pandas as pd import numpy as np df_a = pd.DataFrame([{"a": 1, "b": 4}, {"a": 2, "b": 5}, {"a": 3, "b": 6}, {"a": 4, "b": 8}, {"a": 1, "b": 7}]) df_b = pd.DataFrame([{"c": 2, "d": 7}, {"c": 3, "d": 8}, {"c": 2, "d": 10}]) print "df_a" print df_a print "df_b" print df_b
输出:
df_a a b 0 1 4 1 2 5 2 3 6 3 4 8 4 1 7 df_b c d 0 2 7 1 3 8 2 2 10
内部联接,因为这仅计算c&的笛卡尔积a,内存使用率小于整个DataFrame的笛卡尔积:
c
a
ia, ib = np.where(np.less.outer(df_a.a, df_b.c)) print pd.concat((df_a.take(ia).reset_index(drop=True), df_b.take(ib).reset_index(drop=True)), axis=1)
a b c d 0 1 4 2 7 1 1 4 3 8 2 1 4 2 10 3 2 5 3 8 4 1 7 2 7 5 1 7 3 8 6 1 7 2 10
要计算左外部联接,请使用numpy.setdiff1d()查找df_a不在内部联接中的所有行:
numpy.setdiff1d()
df_a
na = np.setdiff1d(np.arange(len(df_a)), ia) nb = -1 * np.ones_like(na) oa = np.concatenate((ia, na)) ob = np.concatenate((ib, nb)) print pd.concat([df_a.take(oa).reset_index(drop=True), df_b.take(ob).reset_index(drop=True)], axis=1)
a b c d 0 1 4 2 7 1 1 4 3 8 2 1 4 2 10 3 2 5 3 8 4 1 7 2 7 5 1 7 3 8 6 1 7 2 10 7 3 6 NaN NaN 8 4 8 NaN NaN