【问题标题】:Reshape Pandas dataframe columns by block of N columns按 N 列的块重塑 Pandas 数据框列
【发布时间】:2021-05-11 19:07:01
【问题描述】:

我有 1 个数据框,其中的列块需要重新整形为行。 我尝试使用 stack() 和 melt() 但无法找到正确的方法。

这是我所期望的一个例子:

data = {'id':['a1', 'a2', 'a3', 'a4'], 
        'year':[20, 20, 19, 18],
        'b_A': [1, 2, 3, 4],
        'b_B': [5, 6, 7, 8],
        'b_C': [9, 10, 11, 12],
        'c_A': [13, 14, 15, 16],
        'c_B': [17, 18, 19, 20],
        'c_C': [21, 22, 23, 24],
        'd_A': [25, 26, 27, 28],
        'd_B': [29, 30, 31, 32],
        'd_C': [33, 34, 35, 36],
        } 
  
df = pd.DataFrame(data) 
    id  year   b_A  b_B b_C c_A c_B c_C d_A d_B d_C
0   a1  20     1    5   9   13  17  21  25  29  33
1   a2  20     2    6   10  14  18  22  26  30  34
2   a3  19     3    7   11  15  19  23  27  31  35
3   a4  18     4    8   12  16  20  24  28  32  36

预期的结果应该是:

    id  year    origin  A   B   C
0   a1  20      b       1   5   9
1   a1  20      c       13  17  21
2   a1  20      d       25  29  33
3   a2  20      b       2   6   10
4   a2  20      c       14  18  22
5   a2  20      d       26  30  34
6   a3  19      b       3   7   11
7   a3  19      c       15  19  23
8   a3  19      d       27  31  35
9   a4  18      b       4   8   12
10  a4  18      c       16  20  24
11  a4  18      d       28  32  36

感谢您的时间和帮助。

【问题讨论】:

    标签: python pandas stack reshape melt


    【解决方案1】:

    您可以将带有_ 的非列名转换为DataFrame.set_index 的索引,然后通过Series.str.split 拆分列并通过DataFrame.stack 重塑:

    df1 = df.set_index(['id','year'])
    df1.columns = df1.columns.str.split('_', expand=True)
    df1 = df1.stack(level=0).reset_index()
    print (df1)
        id  year level_2   A   B   C
    0   a1    20       b   1   5   9
    1   a1    20       c  13  17  21
    2   a1    20       d  25  29  33
    3   a2    20       b   2   6  10
    4   a2    20       c  14  18  22
    5   a2    20       d  26  30  34
    6   a3    19       b   3   7  11
    7   a3    19       c  15  19  23
    8   a3    19       d  27  31  35
    9   a4    18       b   4   8  12
    10  a4    18       c  16  20  24
    11  a4    18       d  28  32  36
    

    如果需要还设置列origin 可以使用DataFrame.rename_axis:

    df1 = df.set_index(['id','year'])
    df1.columns = df1.columns.str.split('_', expand=True)
    df1 = df1.rename_axis(['origin',None], axis=1).stack(0).reset_index()
    print (df1)
        id  year origin   A   B   C
    0   a1    20      b   1   5   9
    1   a1    20      c  13  17  21
    2   a1    20      d  25  29  33
    3   a2    20      b   2   6  10
    4   a2    20      c  14  18  22
    5   a2    20      d  26  30  34
    6   a3    19      b   3   7  11
    7   a3    19      c  15  19  23
    8   a3    19      d  27  31  35
    9   a4    18      b   4   8  12
    10  a4    18      c  16  20  24
    11  a4    18      d  28  32  36
    

    或者使用wide_to_long_ 的值更改顺序,比如A_bb_A

    df.columns = [f'{"_".join(x[::-1])}' for x in df.columns.str.split('_')]
    df1 = pd.wide_to_long(df, 
                          stubnames=['A','B','C'],
                          i=['id','year'], 
                          j='origin', 
                          sep='_',
                          suffix=r'\w+').reset_index()
    print (df1)
        id  year origin   A   B   C
    0   a1    20      b   1   5   9
    1   a1    20      c  13  17  21
    2   a1    20      d  25  29  33
    3   a2    20      b   2   6  10
    4   a2    20      c  14  18  22
    5   a2    20      d  26  30  34
    6   a3    19      b   3   7  11
    7   a3    19      c  15  19  23
    8   a3    19      d  27  31  35
    9   a4    18      b   4   8  12
    10  a4    18      c  16  20  24
    11  a4    18      d  28  32  36
    

    【讨论】:

      【解决方案2】:

      你也可以使用pyjanitor中的pivot_longer函数;目前你必须从github安装最新的开发版本:

       # install latest dev version
      # pip install git+https://github.com/ericmjl/pyjanitor.git
       import janitor
      
      df.pivot_longer(index=["id", "year"], 
                      names_to=("origin", ".value"), 
                      names_sep="_")
      
          id  year    origin  A   B   C
      0   a1  20  b   1   5   9
      1   a2  20  b   2   6   10
      2   a3  19  b   3   7   11
      3   a4  18  b   4   8   12
      4   a1  20  c   13  17  21
      5   a2  20  c   14  18  22
      6   a3  19  c   15  19  23
      7   a4  18  c   16  20  24
      8   a1  20  d   25  29  33
      9   a2  20  d   26  30  34
      10  a3  19  d   27  31  35
      11  a4  18  d   28  32  36
      

      names_sep 值拆分列;与.value 配对的拆分值保留为列标题,而其他值集中在origin 列下方。

      如果希望数据按出现顺序排列,可以使用sort_by_appearance参数:

      df.pivot_longer(
          index=["id", "year"],
          names_to=("origin", ".value"),
          names_sep="_",
          sort_by_appearance=True,
      )
      
      
          id  year    origin  A   B   C
      0   a1  20  b   1   5   9
      1   a1  20  c   13  17  21
      2   a1  20  d   25  29  33
      3   a2  20  b   2   6   10
      4   a2  20  c   14  18  22
      5   a2  20  d   26  30  34
      6   a3  19  b   3   7   11
      7   a3  19  c   15  19  23
      8   a3  19  d   27  31  35
      9   a4  18  b   4   8   12
      10  a4  18  c   16  20  24
      11  a4  18  d   28  32  36
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-12-05
        • 1970-01-01
        • 2017-11-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-12-10
        • 2020-04-19
        相关资源
        最近更新 更多