【问题标题】:Unpivot multiple variables Pandas Dataframe取消透视多个变量 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

【问题讨论】:

    标签: python pandas dataframe unpivot


    【解决方案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】:

    另一种方法是使用来自pyjanitorpivot_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 之后的值

    【讨论】:

      猜你喜欢
      • 2020-08-25
      • 2014-06-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-07-06
      • 2021-10-14
      • 1970-01-01
      相关资源
      最近更新 更多