简体   繁体   English

取消透视多个变量 Pandas Dataframe

[英]Unpivot multiple variables Pandas Dataframe

Problem问题

I've got a wide dataframe which shows sale prices and volume by State for various time periods.我有一个广泛的 dataframe 显示不同时间段的 State 的销售价格和数量。 However I want to transform (unpivot) the dataframe into a long dataframe.但是,我想将 dataframe 转换(取消旋转)为长 dataframe。 this is easy enough to do in SQL with UNPIVOT, but I am struggling to figure out how to do it in pandas.这在 SQL 中使用 UNPIVOT 很容易做到,但我正在努力弄清楚如何在 pandas 中做到这一点。 Any help be appreciated!任何帮助将不胜感激!

What I've tried我试过的

I've tried using both pd.melt, & pd.wide_to_long, but without success.我试过同时使用 pd.melt 和 pd.wide_to_long,但没有成功。 example below.下面的例子。

Example例子

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='_')

Current Dataframe电流 Dataframe

  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

Desired Dataframe所需 Dataframe

  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

You are close, need suffix='\w+' for get non-integers as suffixes:你很接近,需要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

Another approach:另一种方法:

#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

Another approach would be to use the pivot_longer function from pyjanitor ;另一种方法是使用pyjanitor的 pivot_longer function it is a wrapper around pandas' melt , with more flexibility:它是 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

The .value matches (price, vol, flag) after the columns have been split by names_sep ( _ ), while state captures the values after names_sep .value在由names_sep ( _ ) 拆分列之后匹配 (price, vol, flag),而 state 捕获names_sep之后的值

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM