一个选项是pd.wide_to_long;首先必须对列进行重新排序,使Qty 和Value 出现在最前面:
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
这使用来自pyjanitor 的pivot_longer 函数。
说明:您希望重塑的列有一个模式(商店编号后跟数量或价值);我们在 names_pattern 中利用了这一点,并带有组的正则表达式 (r"(.+\s\d)\s(.+)") - 第一组指向 Store 1/Store2,而另一组指向 Qty/Value。
names_to 参数指定新数据帧的外观 - 对于这种特定情况,.value 告诉函数将与其关联的列的部分保留为标题 - 在这种情况下,.value 是第二个条目,因此它与names_pattern中的第二组配对; names_to 中的 store number 与 names_pattern 中的第一个条目配对