附加具有多列索引和重叠列名称的DataFrames

时间:2019-03-05 20:26:57

标签: python pandas dataframe merge jupyter-notebook

我有多个数据帧,这些数据帧是在循环的不同迭代中生成的,如下所示: 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。有人可以建议一种更好的方法,以更快,更高效的方式实现相同的输出。

请注意,该循环迭代了数十万条记录,并且比上面的示例显示的列多得多。

1 个答案:

答案 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)