微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

按 N 列块重塑 Pandas 数据框列

如何解决按 N 列块重塑 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,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

感谢您的时间和帮助。

解决方法

您可以将 _ 的非列名称转换为 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',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
,

您也可以使用 pivot_longer 中的 pyjanitor 函数;目前您必须从 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",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

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。