Unpivot pandas DataFrame 部分

Unpivot pandas DataFrame partly

我有以下 table DataFrame

Items Description Store 1 Qty Store 1 Value Store 2 Qty Store 2 Value
item 1 Some item name 5 120 7 240
item 2 Some other item 9 1234 12 98

在 Python 上是否有任何简单的方法来仅逆向存储? 这样做:

Items Description Store number Value Qty
Item 1 Some item name Store 1 5 120

我正在考虑完全取消它的旋转,然后将它旋转回来,保持价值和数量作为价值。但我认为,应该有一些更有效的解决方案

如果需要 Qty, Value 分隔列,将第一列转换为 MultiIndex,因此可以使用 Series.str.rsplit by last space to MultiIndex in columns, so last reshape by DataFrame.stack:

df = df.set_index(['Items','Description'])
df.columns = df.columns.str.rsplit(n=1, expand=True)
df = df.rename_axis(('Store number',None), axis=1).stack(0).reset_index()
print (df)
    Items      Description Store number  Qty  Value
0  item 1   Some item name      Store 1    5    120
1  item 1   Some item name      Store 2    7    240
2  item 2  Some other item      Store 1    9   1234
3  item 2  Some other item      Store 2   12     98

您可以将 pd.melt()pd.pivot 一起使用,如下所示:

df_ = pd.melt(df, id_vars=['Items', 'Description'])
df_[['Store number', 'Type']] = df_['variable'].str.rsplit(n=1, expand=True)
df_ = df_.pivot(index=['Items', 'Description', 'Store number'], columns='Type', values='value').reset_index()
print(df_)
Type   Items      Description Store number  Qty  Value
0     item 1   Some item name      Store 1    5    120
1     item 1   Some item name      Store 2    7    240
2     item 2  Some other item      Store 1    9   1234
3     item 2  Some other item      Store 2   12     98

一个选项是pd.wide_to_long;首先必须对列进行重新排序,以便 QtyValue 出现在前面:

columns = df.columns.str.rsplit(n=1).str[::-1].str.join(' ')
temp = df.set_axis(columns, axis = 'columns')
(pd.wide_to_long(temp, 
                 stubnames = ['Qty', 'Value'], 
                 i = ['Items', 'Description'], 
                 j = 'Store Number', 
                 sep = ' ', 
                 suffix='.+')
   .reset_index()
)
    Items      Description Store Number  Qty  Value
0  item 1   Some item name      Store 1    5    120
1  item 1   Some item name      Store 2    7    240
2  item 2  Some other item      Store 1    9   1234
3  item 2  Some other item      Store 2   12     98

下面是另一种可能的选择:

#pip install git+https://github.com/pyjanitor-devs/pyjanitor.git
import pandas as pd
import janitor
df.pivot_longer(index = ['Items', 'Description'], 
                names_to = ('Store Number', '.value'), 
                names_pattern = r"(.+\s\d)\s(.+)")

    Items      Description Store Number  Qty  Value
0  item 1   Some item name      Store 1    5    120
1  item 2  Some other item      Store 1    9   1234
2  item 1   Some item name      Store 2    7    240
3  item 2  Some other item      Store 2   12     98

这使用了 pivot_longer function from pyjanitor.

说明:您希望重塑的列有一个模式(商店编号后跟 Qty 或 Value);我们在 names_pattern 中利用这一点,使用组的正则表达式 (r"(.+\s\d)\s(.+)") - 第一组指向 Store 1/Store2,而另一组指向 Qty/Value

names_to 参数指定新数据框的外观 - 对于这种特定情况,.value 告诉函数将与其关联的部分列保留为 header - 在这种情况下,.value 是第二个条目,因此它与 names_pattern 中的第二组配对; names_to 中的 store numbernames_pattern

中的第一个条目配对