熊猫条件连接中保留左/右连接逻辑
问题描述:
熊猫目前不支持SQL意义上的条件连接;然而,可以通过在公共字段上执行较大的连接,然后在后连接处理中应用过滤器来模拟(性能较低)。熊猫条件连接中保留左/右连接逻辑
但是,我正在寻找一种方法来通过此条件连接来保留左(或右)元素。我通过后期处理失去了它们。
import pandas
# Create a dataframe
df = pandas.DataFrame([{'name': 'A', 'start': '20171201', 'end': '20180205'}, {'name': 'A', 'start': '20170901', 'end': '20170905'}, {'name': 'B', 'start': '20190101', 'end': '20190205'}])
df['start'] = pandas.to_datetime(df['start'])
df['end'] = pandas.to_datetime(df['end'])
print df
end name start
0 2018-02-05 A 2017-12-01
1 2017-09-05 A 2017-09-01
2 2019-02-05 B 2019-01-01
# Create another dataframe, don't want to lose any data here.
v_df = pandas.DataFrame([{'name': 'A', 'val': 10, 'date': '20180101'}, {'name': 'B', 'val': 20, 'date': '20170101'}])
v_df['date'] = pandas.to_datetime(v_df['date'])
print v_df
date name val
0 2018-01-01 A 10
1 2017-01-01 B 20
# Conditional Left Join both dataframes, want to avoid losing the name B val.
v_df = v_df.merge(df, how='left', on=['name'])
v_df = v_df[v_df['date'].between(v_df['start'], v_df['end'])]
print v_df
date name val end start
0 2018-01-01 A 10 2018-02-05 2017-12-01
在这种情况下
所需的输出应为以下,其中包括来自B.
date name val end start
0 2018-01-01 A 10 2018-02-05 2017-12-01
2 2017-01-01 B 20 NaT NaT
一个left
记录中的解决方案还需要能够处理的一般合并时,多条记录匹配,但是当没有一个组匹配条件时,将返回一个空记录(而不是任何记录)。
答
filter_df = df.merge(v_df)
filter_df = filter_df[filter_df['date'].between(filter_df['start'], filter_df['end'])]
v_df.merge(filter_df, how='left')
应该回到你想要什么。 filter_df
标识连接正确工作的行,您在问题中执行的操作,第二次合并将这些start
和end
值仅附加到相关行。
编辑:
@ MaxU的回答是功能上等同和语法更优雅。
答
我不知道这是最好的办法,但似乎做的工作:
In [191]: v_df.merge(v_df.merge(df).query("start <= date <= end"), how='left')
Out[191]:
date name val end start
0 2018-01-01 A 10 2018-02-05 2017-12-01
1 2017-01-01 B 20 NaT NaT
你可以发布你想要的输出吗? “避免失去B val这个名字”的意思有点不清楚。你的意思是你想要'v_df ['end']'和'v_df ['start']'blank/NaN合并条件不满足的情况吗? – EFT
@EFT是的,确切地说,我添加了所需的输出 – jab
@EFT基本上,我们希望将记录筛选到没有返回的地方。在这种情况下(如果没有要返回),请将相应的字段设置为空白/ NaN。 – jab