取消透视多个变量 Pandas Dataframe
Posted
技术标签:
【中文标题】取消透视多个变量 Pandas Dataframe【英文标题】:Unpivot multiple variables Pandas Dataframe 【发布时间】:2021-03-29 05:45:49 【问题描述】:问题
我有一个广泛的数据框,其中显示了不同时间段内各州的销售价格和数量。但是我想将数据帧转换(反透视)成一个长数据帧。在 SQL 中使用 UNPIVOT 很容易做到这一点,但我正在努力弄清楚如何在 pandas 中做到这一点。任何帮助将不胜感激!
我的尝试
我尝试过同时使用 pd.melt 和 pd.wide_to_long,但没有成功。下面的例子。
示例
df = pd.DataFrame('time': ['t1', 't2', 't3', 't4', 't5'],
'prod': ['A', 'B', 'C', 'D', 'E'],
'price_qld': [4, 3, 6, 3, 8],
'price_nsw': [7, 4, 7, 3, 5],
'price_vic': [9, 4, 6, 23, 7],
'vol_qld': [11, 43, 232, 234, 42],
'vol_nsw': [73, 44, 657, 53, 785],
'vol_vic': [95, 34, 666, 273, 87],
'flag_qld': [1, 1, 1, 1, 0],
'flag_nsw': [0, 1, 0, 1, 0],
'flag_vic': [1, 1, 1, 0, 1]
)
print(df)
new_df = pd.wide_to_long(df, ['price', 'vol', 'flag'], i=['time', 'prod'], j='State', sep='_')
当前数据框
time prod price_qld price_nsw ... vol_vic flag_qld flag_nsw flag_vic
0 t1 A 4 7 ... 95 1 0 1
1 t2 B 3 4 ... 34 1 1 1
2 t3 C 6 7 ... 666 1 0 1
3 t4 D 3 3 ... 273 1 1 0
4 t5 E 8 5 ... 87 0 0 1
所需的数据框
time prod state price vol flag
0 t1 A qld 4 11 1
1 t1 A nsw 7 73 0
2 t1 A vic 9 95 1
3 t2 B qld 3 43 1
4 t2 B nsw 4 44 1
5 t2 B vic 4 34 1
6 t3 C qld 6 232 1
7 t3 C nsw 7 657 0
8 t3 C vic 6 666 1
【问题讨论】:
【参考方案1】:你很接近,需要suffix='\w+'
来获取非整数作为后缀:
new_df = (pd.wide_to_long(df, ['price', 'vol', 'flag'],
i=['time', 'prod'],
j='State',
sep='_',
suffix='\w+')
.reset_index())
print (new_df)
time prod State price vol flag
0 t1 A qld 4 11 1
1 t1 A nsw 7 73 0
2 t1 A vic 9 95 1
3 t2 B qld 3 43 1
4 t2 B nsw 4 44 1
5 t2 B vic 4 34 1
6 t3 C qld 6 232 1
7 t3 C nsw 7 657 0
8 t3 C vic 6 666 1
9 t4 D qld 3 234 1
10 t4 D nsw 3 53 1
11 t4 D vic 23 273 0
12 t5 E qld 8 42 0
13 t5 E nsw 5 785 0
14 t5 E vic 7 87 1
另一种方法:
#convert all columns without separatot to MultiIndex
new_df = df.set_index(['time', 'prod'])
#split columns by separator
new_df.columns = new_df.columns.str.split('_', expand=True)
#reshape by stack
new_df = new_df.stack().reset_index().rename(columns='level_2':'state')
print (new_df)
time prod state flag price vol
0 t1 A nsw 0 7 73
1 t1 A qld 1 4 11
2 t1 A vic 1 9 95
3 t2 B nsw 1 4 44
4 t2 B qld 1 3 43
5 t2 B vic 1 4 34
6 t3 C nsw 0 7 657
7 t3 C qld 1 6 232
8 t3 C vic 1 6 666
9 t4 D nsw 1 3 53
10 t4 D qld 1 3 234
11 t4 D vic 0 23 273
12 t5 E nsw 0 5 785
13 t5 E qld 0 8 42
14 t5 E vic 1 7 87
【讨论】:
Jezrael 再次救援!!,非常感谢老板,这很有效。我会在 10 分钟内接受答案。【参考方案2】:另一种方法是使用来自pyjanitor 的pivot_longer 函数;它是 pandas 的 melt 的包装器,具有更大的灵活性:
In [219]: df.pivot_longer(index = ['time', 'prod'],
names_to=('.value', 'state'),
names_sep="_")
Out[219]:
time prod state price vol flag
0 t1 A qld 4 11 1
1 t2 B qld 3 43 1
2 t3 C qld 6 232 1
3 t4 D qld 3 234 1
4 t5 E qld 8 42 0
5 t1 A nsw 7 73 0
6 t2 B nsw 4 44 1
7 t3 C nsw 7 657 0
8 t4 D nsw 3 53 1
9 t5 E nsw 5 785 0
10 t1 A vic 9 95 1
11 t2 B vic 4 34 1
12 t3 C vic 6 666 1
13 t4 D vic 23 273 0
14 t5 E vic 7 87 1
In [220]: df.pivot_longer(index = ['time', 'prod'],
names_to=('.value', 'state'),
names_sep="_",
sort_by_appearance=True)
Out[220]:
time prod state price vol flag
0 t1 A qld 4 11 1
1 t1 A nsw 7 73 0
2 t1 A vic 9 95 1
3 t2 B qld 3 43 1
4 t2 B nsw 4 44 1
5 t2 B vic 4 34 1
6 t3 C qld 6 232 1
7 t3 C nsw 7 657 0
8 t3 C vic 6 666 1
9 t4 D qld 3 234 1
10 t4 D nsw 3 53 1
11 t4 D vic 23 273 0
12 t5 E qld 8 42 0
13 t5 E nsw 5 785 0
14 t5 E vic 7 87 1
.value
在列被names_sep
(_
) 拆分后匹配(价格、卷、标志),而状态捕获names_sep
之后的值
【讨论】:
以上是关于取消透视多个变量 Pandas Dataframe的主要内容,如果未能解决你的问题,请参考以下文章
Python Pandas Dataframe 数据透视表列和值顺序
Pandas:透视表(pivotTab)和交叉表(crossTab)