通过 N 列块重塑 Pandas 数据框列

use*_*177 1 python stack reshape melt pandas

我有 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) 
Run Code Online (Sandbox Code Playgroud)
    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
Run Code Online (Sandbox Code Playgroud)

预期结果应该是:

    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
Run Code Online (Sandbox Code Playgroud)

感谢您的时间和帮助。

jez*_*ael 5

您可以将非列名转换为_索引 by 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
Run Code Online (Sandbox Code Playgroud)

如果还需要设置列,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
Run Code Online (Sandbox Code Playgroud)

或者使用like更改值的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
Run Code Online (Sandbox Code Playgroud)