【问题标题】:How to join a dataframe with packed column and row names to an unpacked dataframe如何将具有打包列和行名称的数据框连接到未打包的数据框
【发布时间】:2021-12-27 17:10:36
【问题描述】:

假设下一个打包的df,其中column_name代表列名,row_name代表未打包数据帧中的行名:

  column_name row_name  value
0        col1        a      1
1        col1        b      2
2        col1        c      3
3        col2        d      4
4        col2        e      5
5        col2        f      6
6        col2        g      7
7        col2        h      8

解压后的数据框如下所示:

   individual col1 col2
0           1    a    e
1           2    b    f
2           3    c    g
3           4    a    h
4           5    b    e
5           6    c    f
6           7    a    g
7           8    b    h

所需的输出可能如下所示:

individual  col1  col2   value_col1   value_col2
1             a     e       1              5
2             b     f       2              6
3             c     g       3              7
4             a     h       1              8
5             b     e       2              5
6             c     f       3              6
7             a     g       1              7
8             b     h       2              8

有没有办法进行连接,以便将 value 列解压缩为解压缩数据框中的两个不同列?

可重现的数据:

unpacked_df = pd.DataFrame({
    'individual': [1,2,3,4,5,6,7,8],
    'col1':['a','b','c','a','b','c','a','b'],
    'col2':['e','f','g','h','e','f','g','h']
})

packed_df = pd.DataFrame({
    'column_name': ['col1','col1','col1','col2','col2','col2','col2','col2'],
     'row_name': ['a','b','c','d','e','f','g','h'],
    'value':[1,2,3,4,5,6,7,8]
})

【问题讨论】:

  • value_col1 for individual 4 应该是 1 而不是 4

标签: python pandas dataframe join


【解决方案1】:

你可以做一个双重merge,首先是col1,然后是col2

unpacked_df.merge(packed_df[packed_df.column_name.eq("col1")], left_on="col1", right_on="row_name").merge(packed_df[packed_df.column_name.eq("col2")], left_on="col2", right_on="row_name", suffixes=("_col1","_col2")).sort_values("individual")[["individual", "col1", "col2", "value_col1", "value_col2"]]

结果:

   individual col1 col2  value_col1  value_col2
0           1    a    e           1           5
6           2    b    f           2           6
5           3    c    g           3           7
2           4    a    h           1           8
1           5    b    e           2           5
7           6    c    f           3           6
4           7    a    g           1           7
3           8    b    h           2           8

【讨论】:

  • 哇,虽然很长,但哈哈:P
  • @user17242583:是的,我认为对于两列来说没关系,对于更多列,它肯定会变得笨拙
【解决方案2】:

这行得通:

cols = packed_df['column_name'].unique()
dct = {k: [] for k in cols}
for row in unpacked_df.iloc:
    for col in cols:
        dct[col].append(packed_df[(packed_df['column_name'] == col) & (packed_df['row_name'] == row[col])]['value'].iloc[0])

【讨论】:

    【解决方案3】:

    一种选择是融化打包的 df,将其连接到未打包的 df,进行枢轴/翻转和一些列名调整:

    temp = (unpacked_df
            .melt('individual', 
                  var_name ='column_name', 
                  value_name='row_name')
            .merge(packed_df, 
                   on=['column_name', 'row_name'])
            .pivot('individual', 'column_name')
            .rename(columns={'row_name':''})
    )
    
    # collapse the columns
    temp.columns = temp.columns.map('_'.join)
    
    # removeprefix is a python3.9 addition
    temp.rename(columns=lambda col: col.removeprefix('_')) 
     
               col1 col2  value_col1  value_col2
    individual                                  
    1             a    e           1           5
    2             b    f           2           6
    3             c    g           3           7
    4             a    h           1           8
    5             b    e           2           5
    6             c    f           3           6
    7             a    g           1           7
    8             b    h           2           8
    

    目的是得到individual的配对以及col1col2的组合,以便在packed_df中镜像相同的形式;从那里开始,它只是合并和重塑(只要索引/列组合是唯一的,重塑就可以工作)。

    另一个可能有助于方法链接(从长到宽的部分)的选项是使用来自pyjanitorpivot_wider 函数:

    pip install git+https://github.com/pyjanitor-devs/pyjanitor.git
    import janitor
    import pandas as pd
    
    (unpacked_df
            .melt('individual', 
                  var_name ='column_name', 
                  value_name='row_name')
            .merge(packed_df, 
                   on=['column_name', 'row_name'])
             # wrapper around pivot
            .pivot_wider(index = 'individual', 
                         names_from = 'column_name',
                         names_sep = '_',
                         names_glue = lambda col: f"{col[-4:]}" 
                                                  if col[:-5]=="row_name" 
                                                  else col)
    )
    
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-12-05
      • 2016-12-27
      • 1970-01-01
      • 1970-01-01
      • 2015-12-29
      • 1970-01-01
      相关资源
      最近更新 更多