具有这样的数据框:
date user sales_blue sales_red
2019/06/01 A 30 50
2019/06/01 B 60 70
2019/06/02 A 25 35
2019/06/02 B 42 52
我正在尝试达到以下目标:
date user color sales
2019/06/01 A blue 30
2019/06/01 A red 50
2019/06/01 B blue 60
2019/06/01 B red 70
2019/06/02 A blue 25
2019/06/02 A red 35
2019/06/02 B blue 42
2019/06/02 B red 52
通过使用循环,这在某种“手动”方式中是相当可行的,但是出于性能方面的考虑,我正在寻找一种更有效的解决方案,该解决方案不涉及在Python中进行循环。
答案 0 :(得分:3)
您可以使用melt
。为了从颜色中删除前缀,您可以使用str
访问器对字符串进行切片。如果您需要指定的顺序,只需按照@anky的建议添加.sort_values('date')
。
out = df.melt(id_vars=['date', 'user'], var_name='color', value_name='sales')
out['color'] = out.color.str[6:]
print(out)
date user color sales
0 2019/06/01 A blue 30
1 2019/06/01 B blue 60
2 2019/06/02 A blue 25
3 2019/06/02 B blue 42
4 2019/06/01 A red 50
5 2019/06/01 B red 70
6 2019/06/02 A red 35
7 2019/06/02 B red 52
答案 1 :(得分:3)
当您想使用列名的 all 来标识行时,通常使用melt
。但是,当您想使用一列名称的较小部分(前缀为常量)时,melt
的通用,更用户友好的版本称为wide_to_long
。
这不仅可以清晰地处理前缀,还可以扩展以处理多个不同的前缀。
pd.wide_to_long(
df, stubnames='sales', i=['date', 'user'], j='color', suffix='\w+', sep='_'
).reset_index(-1)
color sales
user date
A 2019/06/01 blue 30
2019/06/01 red 50
B 2019/06/01 blue 60
2019/06/01 red 70
A 2019/06/02 blue 25
2019/06/02 red 35
B 2019/06/02 blue 42
2019/06/02 red 52
要概括这种行为以融化不止一个列:
print(df)
date user sales_blue sales_red calls_blue calls_red
0 2019/06/01 A 30 50 3 4
1 2019/06/01 B 60 70 1 2
2 2019/06/02 A 25 35 4 6
3 2019/06/02 B 42 52 5 7
pd.wide_to_long(
df, stubnames=['sales', 'calls'], i=['date', 'user'], j='color', suffix='\w+', sep='_'
).reset_index(-1)
color sales calls
date user
2019/06/01 A blue 30 3
A red 50 4
B blue 60 1
B red 70 2
2019/06/02 A blue 25 4
A red 35 6
B blue 42 5
B red 52 7