我有多个数据帧,这些数据帧是在循环的不同迭代中生成的,如下所示: d1在迭代1中创建,d2在迭代2中创建,依此类推。
d1=pd.DataFrame({'PARTICIPANT_ID':['idA'],'AGE':[32],'GENDER':['male'],'colA':[20],'colB':[100]})
d2=pd.DataFrame({'PARTICIPANT_ID':['idA'],'AGE':[32],'GENDER':['male'],'colC':[1],'colD':[6]})
d3=pd.DataFrame({'PARTICIPANT_ID':['idA'],'AGE':[32],'GENDER':['male'],'colE':[60],'colF':[11]})
d4=pd.DataFrame({'PARTICIPANT_ID':['idB'],'AGE':[43],'GENDER':['female'],'colA':[30],'colB':[200]})
d5=pd.DataFrame({'PARTICIPANT_ID':['idB'],'AGE':[43],'GENDER':['female'],'colC':[2],'colD':[7]})
d6=pd.DataFrame({'PARTICIPANT_ID':['idB'],'AGE':[43],'GENDER':['female'],'colE':[70],'colF':[12]})
d7=pd.DataFrame({'PARTICIPANT_ID':['idC'],'AGE':[28],'GENDER':['female'],'colE':[56],'colF':[48]})
我想在每次迭代后继续将这些数据帧合并到一个更大的最终数据帧,或者将它们存储为字典或其他某种数据类型,并在循环结束时将它们合并在一起。
这是输出的外观(仅PARTICIPANT_ID可以充当这些数据帧的索引):
PARTICIPANT_ID AGE GENDER colA colB colC colD colE colF
idA 32 male 20.0 100.0 1.0 6.0 60 11
idB 43 female 30.0 200.0 2.0 7.0 70 12
idC 28 female NaN NaN NaN NaN 56 48
我目前的状态是:
df_final = df_final.set_index(['PARTICIPANT_ID','AGE','GENDER'],inplace=True).combine_first(d1.set_index(['PARTICIPANT_ID','AGE','GENDER'],inplace=True))
其中df_final是最终的输出数据帧,我将针对每次迭代中生成的每个新数据帧循环执行此过程。
这种合并的问题是PAINFULLY SLOW。有人可以建议一种更好的方法,以更快,更高效的方式实现相同的输出。
请注意,该循环迭代了数十万条记录,并且比上面的示例显示的列多得多。
答案 0 :(得分:0)
您可以通过concat
+ groupby
+ first
来获得相同的逻辑,也许对您的真实数据更快:
df_res = (pd.concat([d1, d2, d3, d4, d5, d6, d7], sort=False)
.groupby(['PARTICIPANT_ID', 'AGE', 'GENDER']).first())
# colA colB colC colD colE colF
#PARTICIPANT_ID AGE GENDER
#idA 32 male 20.0 100.0 1.0 6.0 60.0 11.0
#idB 43 female 30.0 200.0 2.0 7.0 70.0 12.0
#idC 28 female NaN NaN NaN NaN 56.0 48.0
否则,我会说reduce
,但您似乎已经在这样做了:
from functools import reduce
reduce(lambda l,r: l.combine_first(r),
[x.set_index(['PARTICIPANT_ID', 'AGE', 'GENDER']) for x in [d1, d2, d3, d4, d5, d6, d7]])
myl = [d1, d2, d3, d4, d5, d6, d7]
%timeit pd.concat(myl, sort=False).groupby(['PARTICIPANT_ID', 'AGE', 'GENDER']).first()
#9.11 ms ± 310 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%timeit reduce(lambda l,r: l.combine_first(r), [x.set_index(['PARTICIPANT_ID', 'AGE', 'GENDER']) for x in myl])
#61.3 ms ± 1.18 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)