【问题标题】:using pandas, extract data from long format df and add it to wide format df使用 pandas,从长格式 df 中提取数据并将其添加到宽格式 df
【发布时间】:2020-06-02 18:34:15
【问题描述】:

我有两个数据框,df1 和 df2。 df1 具有以宽格式排列的重复观察,而 df2 以长格式排列。

import pandas as pd
df1 = pd.DataFrame({"ID":[1,2,3],"colA_1":[1,2,3],"date1":["1.1.2001", "2.1.2001","3.1.2001"],"colA_2":[4,5,6],"date2":["1.1.2002", "2.1.2002","3.1.2002"]})
df2 = pd.DataFrame({"ID":[1,1,2,2,3,3],"col1":[1,1.5,2,2.5,3,3.5],"date":["1.1.2001", "1.1.2002","2.1.2001","2.1.2002","3.1.2001","3.1.2002"], "col3":[11,12,13,14,15,16],"col4":[21,22,23,24,25,26]})

df1 看起来像:

   ID  colA_1     date1  colA_2     date2
0   1       1  1.1.2001       4  1.1.2002
1   2       2  2.1.2001       5  2.1.2002
2   3       3  3.1.2001       6  3.1.2002

df2 看起来像:

   ID  col1     date1  col3  col4
0   1   1.0  1.1.2001    11    21
1   1   1.5  1.1.2002    12    22
2   2   2.0  2.1.2001    13    23
3   2   2.5  2.1.2002    14    24
4   3   3.0  3.1.2001    15    25
5   3   3.5  3.1.2002    16    26
6   3   4.0  4.1.2002    17    27


我想从 df2 中取出一个给定的列,“col3”,然后:

(1) 如果 df2 中的“ID”和“date”列与 df1 中的“ID”和“date1”列匹配,我想将该值放在 df1 中名为“colB_1”的新列中。

(2) 否则,如果 df2 中的“ID”和“date”列与 df1 中的“ID”和“date2”列匹配,我想将该值放在 df1 中名为“colB_2”的新列中。

(3) 否则,如果 df2 中的“ID”和“date”列与(“ID”和“date1”)或(“ID”和“date2”)都不匹配,我想忽略这些行.

因此,这个输出数据帧 df3 的输出应该如下所示:

   ID  colA_1     date1  colA_2     date2  colB_1  colB_2
0   1       1  1.1.2001       4  1.1.2002      11      12
1   2       2  2.1.2001       5  2.1.2002      13      14
2   3       3  3.1.2001       6  3.1.2002      15      16

最好的方法是什么?

我找到了this 链接,但答案不适用于我的情况。我想要一种非常明确的方式来指定列匹配。我认为 df.mask 可能可以帮助我,但我不确定如何实现它。

例如:以下代码

df3 = df1.copy()
df3["colB_1"] = ""
df3["colB_2"] = ""
filter1 = (df1["ID"] == df2["ID"]) & (df1["date1"] == df2["date"])
filter2 = (df1["ID"] == df2["ID"]) & (df1["date2"] == df2["date"])
df3["colB_1"] = df.mask(filter1, other=df2["col3"])
df3["colB_2"] = df.mask(filter2, other=df2["col3"])

给出错误

ValueError: Can only compare identically-labeled Series objects

我问了这个问题previously,它被标记为已关闭;我的问题被标记为与this 重复。然而,这种情况并非如此。链接问题中的答案建议使用map 或df.merge。地图不适用于多种条件(在我的情况下,ID 和日期)。当 df1 和 df2 中要合并的列名之一不同(例如,“date”和“date1”)时,df.merge(匹配多个列的答案)在我的情况下不起作用。

例如下面的代码:

df3 = df1.merge(df2[["ID","date","col3"]], on=['ID','date1'], how='left')

因密钥错误而失败。

另外值得注意的是,我将处理许多不同的文件,具有许多不同的列命名方案,并且每次都需要不同的子集。这就是为什么我想要一个明确命名列和条件的答案。

对此的任何帮助将不胜感激。

【问题讨论】:

    标签: python pandas dataframe


    【解决方案1】:

    您可以在替换下划线后使用pd.wide_to_long,这将取消透视数据框,您可以使用它与df2 合并,然后使用pivot 返回unstack

    m =df1.rename(columns=lambda x: x.replace('_',''))
    unpiv = pd.wide_to_long(m,['colA','date'],'ID','v').reset_index()
    
    merge_piv = (unpiv.merge(df2[['ID','date','col3']],on=['ID','date'],how='left')
         .set_index(['ID','v'])['col3'].unstack().add_prefix('colB_'))
    
    final = df1.merge(merge_piv,left_on='ID',right_index=True)
    

       ID  colA_1     date1  colA_2     date2  colB_1  colB_2
    0   1       1  1.1.2001       4  1.1.2002      11      12
    1   2       2  2.1.2001       5  2.1.2002      13      14
    2   3       3  3.1.2001       6  3.1.2002      15      16
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-05-12
      • 1970-01-01
      • 2021-09-14
      • 1970-01-01
      • 1970-01-01
      • 2023-01-30
      • 1970-01-01
      • 2022-11-04
      相关资源
      最近更新 更多