在数据框中取消展平行

时间:2019-09-16 14:26:01

标签: python pandas

具有这样的数据框:

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中进行循环。

2 个答案:

答案 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