匹配 3 个数据框的 5 列并创建一个计算列

match 5 columns of 3 dataframes and create a calculated column

我有 3 个数据框,如下所示:

df1:

a  b  c  d  e  f  2020    2021
a1 b1 c1 d1 e1 f1 334.385 340.210
a1 b1 c1 d1 e1 f1 335.385 341.210
a2 b2 c2 d2 e2 f2 344.385 350.210
a4 b2 c4 d4 e4 f4 354.385 360.210

df2:

a  g  h  i  j  k  2020    2021
a1 b1 c1 d1 e1 f1 434.385 440.210
a5 b6 c6 d6 e6 f6 444.385 450.210
a5 b6 c6 d6 e6 f6 445.385 451.210
a4 b2 c4 d4 e4 f4 454.385 460.210
a4 b2 c4 d4 e4 f4 455.385 461.210

df3:

a  l  m  n  o  p  2020    2021
a1 b1 c1 d1 e1 f1 534.385 540.210
a7 b7 c7 d7 e7 f7 544.385 550.210
a4 b2 c4 d4 e4 f4 554.385 560.210

预期输出:

a  l  m  n  o  p  2020    2021     new_2021
a1 b1 c1 d1 e1 f1 534.385 540.210  540.210*(340.210/440.210)
a7 b7 c7 d7 e7 f7 544.385 550.210  numpy.nan
a4 b2 c4 d4 e4 f4 554.385 560.210  560.210*((460.210+461.210)/560.210)

解释:
我想匹配 3 个数据帧的所有前 5 个字符串列,并创建一个新列,对年份列进行少量计算。 df3 是我的参考数据框,我想根据 df1 和 df2 的变化率调整 df3 的年份列中的值。
例如:对于所有 5 列都匹配的行,那么我想做 df3['new_2021'] = df3['2021'] * (df1['2021'] / df2['2021']).
如果在前 5 列中有多个具有相同值的行。我想计算年列的总和,如预期输出的第 3 行所示;
并且如预期输出的第二行所示,如果在 df1 和 df2 中的一个或两个中找不到 df3 的所有 5 列的匹配项,我希望该行保留为空。

我如何有效地做到这一点?我有非常大的数据框。

您可以聚合 sum 因为前 5 列中可能存在重复值,然后根据 df5 中的列名称设置索引名称,以便在所有 DataFrames 中使用相同的索引名称,因此可能存在除法和多重:

df1 = df1.groupby(df1.columns[:5].tolist()).sum().rename_axis(df3.columns[:5].tolist())
df2 = df2.groupby(df2.columns[:5].tolist()).sum().rename_axis(df3.columns[:5].tolist())
df3 = df3.groupby(df3.columns[:5].tolist()).sum()

df3['new_2021'] = df3['2021'] * (df1['2021'] / df2['2021'])
print (df3)
                   2020    2021    new_2021
a  l  m  n  o                              
a1 b1 c1 d1 e1  534.385  540.21  836.214303
a4 b2 c4 d4 e4  554.385  560.21  219.002457
a7 b7 c7 d7 e7  544.385  550.21         NaN

编辑:在 df3 中重复 MultiIndex 是否可行,但需要更多步骤:

print (df3)
    a   l   m   n   o   p     2020    2021
0  a1  b1  c1  d1  e1  f1  534.385  540.21
1  a7  b7  c7  d7  e7  f7  544.385  550.21
2  a4  b2  c4  d4  e4  f4  554.385  560.21
3  a1  b1  c1  d1  e1  f1  534.385  200.00
4  a7  b7  c7  d7  e7  f7  544.385  800.00
5  a4  b2  c4  d4  e4  f4  554.385  500.00

df1 = df1.groupby(df1.columns[:5].tolist()).sum().rename_axis(df3.columns[:5].tolist())
df2 = df2.groupby(df2.columns[:5].tolist()).sum().rename_axis(df3.columns[:5].tolist())

#convert first 5 columns to index and sorting
df3 = df3.set_index(df3.columns[:5].tolist()).sort_index()

#create unique MultiIndex from df3 and change index in df1, df2
mux = pd.MultiIndex.from_frame(df3.index.to_frame().drop_duplicates())
df1 = df1.reindex(mux)
df2 = df2.reindex(mux)
print (df2)
                   2020    2021
a  l  m  n  o                  
a1 b1 c1 d1 e1  434.385  440.21
a4 b2 c4 d4 e4  909.770  921.42
a7 b7 c7 d7 e7      NaN     NaN

df3['new_2021'] = df3['2021'] * (df1['2021'] / df2['2021'])
print (df3)
                 p     2020    2021    new_2021
a  l  m  n  o                                  
a1 b1 c1 d1 e1  f1  534.385  540.21  836.214303
            e1  f1  534.385  200.00  309.588605
a4 b2 c4 d4 e4  f4  554.385  560.21  219.002457
            e4  f4  554.385  500.00  195.464609
a7 b7 c7 d7 e7  f7  544.385  550.21         NaN
            e7  f7  544.385  800.00         NaN