在多个条件下合并来自多个数据帧的数据
Posted
技术标签:
【中文标题】在多个条件下合并来自多个数据帧的数据【英文标题】:merge data from multiple data frames on multiple conditions 【发布时间】:2018-05-30 05:37:34 【问题描述】:我想合并多个数据框,但前提是键匹配并且日期范围在 df1 中的“InitialAdmit”日期范围的 90 天内。我想保留 df1 中的所有行,并且只合并 df2、df3 等中的其他行,只要它们与键匹配并在日期范围内。
注意:先合并 dfs 然后考虑日期范围条件对我不起作用。我第一次使用这种方法,但是在很多情况下合并是成功的,但是由于日期范围超出了限制,我让脚本删除了行。我需要以某种方式保留 df1 中的所有行。
Python Pandas: Merging data frames on multiple conditions - 这个问题很相似,但它似乎合并然后应用条件。我认为更好的方法是应用条件,然后在满足条件时合并。不过,我愿意接受建议。
数据帧:
a = 'Key': [100000204, 100000255, 100000271,100000286,100000628],
'InitialAdmit': ['2012-06-04', '2012-05-03', '2012-01-16', '2012-10-26', '2012-02-21'],
'90DayRange': ['2012-09-02', '2012-08-01', '2012-04-15', '2013-01-24', '2012-05-21']
df1 = pandas.DataFrame(data=a)
df1
b = 'Key': [100000208, 100000255, 100000723,100000286,100000866],
'InitialAdmit': ['2012-01-22', '2012-06-03', '2012-10-26', '2012-11-26', '2012-05-11'],
df2 = pandas.DataFrame(data=b)
df2
c = 'Key': [100000255, 100000255, 100000702,100000221,100000628],
'InitialAdmit': ['2012-06-22', '2012-10-03', '2012-10-26', '2012-11-26', '2012-04-11'],
df3 = pandas.DataFrame(data=c)
df3
脚本:
df_NotIncludedRows = pandas.DataFrame()
df_final = pandas.DataFrame()
dfs = [df2] #I plan to add more dataframes so I'm iterating through this list of dfs
for df in dfs: #iterate through each df in dfs
for key in df1["Key"]: #iterate through each key found in column 'Id'
if key in df["Key"]: # find any matching key from df1 in df2 (part of my issue exists here)
if (df["Admit"] >= df1["InitialAdmit"]) | (df["Admit"] <= df1["90DayRange"]):
df_final = pandas.merge(df1,df.loc[:],on='Key',how='left') # my df.loc[:] is a little off i think
else:
df_NotIncludedRows = df_NotIncludedRows.append(df.loc[:]) # same df.loc[:] issue i believe
df_NotIncludedRows
【问题讨论】:
【参考方案1】:我还是推荐先合并再过滤,这里我们使用布尔索引和combine_first
df=df1.merge(df2,on='Key')
m=(df.InitialAdmit_y>=df.InitialAdmit_x)&(df.InitialAdmit_y<=df.InitialAdmit_x)
df1.set_index('Key').combine_first(df[m].set_index('Key'))
Out[215]:
90DayRange InitialAdmit InitialAdmit_x InitialAdmit_y
Key
100000204 2012-09-02 2012-06-04 NaT NaT
100000255 2012-08-01 2012-05-03 2012-05-03 2012-06-03
100000271 2012-04-15 2012-01-16 NaT NaT
100000286 2013-01-24 2012-10-26 2012-10-26 2012-11-26
100000628 2012-05-21 2012-02-21 NaT NaT
【讨论】:
跟进此方法。这很棒,似乎可以满足我的需要!那谢谢啦!但是我应该指定更多的背景:我有大约 25 个数据帧,每个数据帧大约有 500k mil - 3 mil 行。就速度和内存使用而言,过滤器然后合并方法是否会更有效地处理如此大的数据集? @MartyBobak 在合并之前我们不知道哪个是过滤器,这就是为什么我们需要先合并,我们需要找到值的范围然后过滤 这很公平。如果没问题,我想用另一个 df 扩展这个问题,因为我发现很难将你的答案应用于两个以上的 df。我使用: dfs = [df1, df2, df3] df_merged = reduce(lambda left,right: pandas.merge(left,right,on='Key',how='left'), dfs) -- 合并多个 dfs ,基本上取代了你的第一行。【参考方案2】:考虑reduce
使用左连接进行链合并。下面演示了 3 个 df2 副本。此外,下面假设 InitialAdmit 是数据框的最后一列。根据需要重新排序。
import pandas
import numpy
from functools import reduce
...
# LIST OF DATAFRAMES WITH SUFFIXING OF INITIALADMIT TO AVOID NAME COLLISION
dfList = [d.rename(columns='InitialAdmit':'InitialAdmit_' + str(i))
for i,d in enumerate([df1, df2, df2, df2])]
# USER-DEFINED METHOD CONDITIONING ON LAST COLUMN
def mergefilter(x, y):
tmp = pandas.merge(x, y, on='Key', how='left')
tmp.loc[~(tmp.iloc[:, -1].between(tmp['InitialAdmit_0'], tmp['90DayRange'])),
tmp.columns[-1]] = numpy.nan
return tmp
finaldf = reduce(mergefilter, dfList)
print(finaldf)
# 90DayRange InitialAdmit_0 Key InitialAdmit_1 InitialAdmit_2 InitialAdmit_3
# 0 2012-09-02 2012-06-04 100000204 NaN NaN NaN
# 1 2012-08-01 2012-05-03 100000255 2012-06-03 2012-06-03 2012-06-03
# 2 2012-04-15 2012-01-16 100000271 NaN NaN NaN
# 3 2013-01-24 2012-10-26 100000286 2012-11-26 2012-11-26 2012-11-26
# 4 2012-05-21 2012-02-21 100000628 NaN NaN NaN
【讨论】:
以上是关于在多个条件下合并来自多个数据帧的数据的主要内容,如果未能解决你的问题,请参考以下文章
为 pyspark 数据帧的每一行评估多个 if elif 条件
如何合并两个或多个具有不同 where 条件的查询?我必须重用在第一个代码中使用的代码