逆透视多个变量 Pandas Dataframe

问题描述 投票:0回答:3

问题

我有一个广泛的数据框,其中显示了各个时期各州的销售价格和销量。不过,我想将数据帧转换(逆透视)为长数据帧。这在 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
python pandas dataframe unpivot
3个回答
3
投票

你很接近,需要

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

1
投票

另一种方法是使用 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
) 分割后,
_
匹配 (price, vol, flag),而状态捕获
names_sep

之后的值

0
投票

后缀“\w+”对我来说不起作用 - 我的示例列名称是“Oil_LAZY M 23 CO 1HM”。然而,后缀“.+”工作得很好,因为它只是检索分隔符后面的内容,在我的例子中,它也是一个下划线。

© www.soinside.com 2019 - 2024. All rights reserved.