pivot_wider
(参见mozway的回答)从纯pandas角度来看,可能是最好的选择,但如果您需要更多的灵活性,也可以使用melt
和pivot
:
import pandas as pd
df = pd.DataFrame(['AA-24', '0', '700', '2100', '300', '1159', '2877', '30', '30', '47', '10', '5'],
index= ['Num', 'TP1(USD)', 'TP2(USD)', 'TP3(USD)', 'VReal1(USD)', 'VReal2(USD)', 'VReal3(USD)', 'TiV1(EUR)', 'TiV2(EUR)', 'TiV3(EUR)', 'TR', 'TR-Tag']).T
(df.melt(id_vars=['Num','TR', 'TR-Tag'])
.assign(col=lambda x: x['variable'].str[:2], idx=lambda x: x['variable'].str.extract("([0-9])"))
.pivot(values='value', columns='col', index='idx')
.rename(columns={'TP': 'Price', 'VR': 'Net', 'Ti': 'Range'})
)
或许令人意外的是,这种方法也比 wide_to_long
更快。基准测试给出了每次循环7.76毫秒±841微秒的结果。
wide_to_long
的方法来自mozway:
(pd
.wide_to_long(df.set_axis(df.columns.str.replace(r'\([A-Z]{3}\)$', '', regex=True),
axis=1),
stubnames=['TP', 'VReal', 'TiV'], i='Num', j='ID')
.reset_index('ID')
.drop(columns=['TR', 'TR-Tag'])
.rename(columns={'TP': 'Price', 'VReal': 'Net', 'TiV': 'Range'})
)
在我的机器上,每次循环的基准测试为30.4毫秒±3.07毫秒。
Umar.H的答案使用stack
比两者都更快:
df1 = df.filter(regex='TP|VR|TV')
df1.columns = df1.columns\
.str.replace('(\d+)', r' \1' ,regex=True).str.split(' ',expand=True)
df1.stack(1).rename(columns={'TP': 'Price', 'VR': 'Net', 'TV': 'Range'})
每次循环运行时间为6.07毫秒±156微秒
如果你不介意额外的导入,可以使用pivot_wider
函数提供的速度和优雅的语法,参考sammywemmy的回答
(df
.select_columns('TP*', 'VR*', 'Ti*')
.pivot_longer(index = None,
names_to = ('.value', 'ID'),
names_pattern = ('(.+)(\d).+'))
.rename(columns = {'TP':'Price', 'VReal':'Net', 'TiV':'Range'})
)
测试结果为每个循环11.2毫秒±229微秒
名称模式方法如下:
df.pivot_longer(index = None,
names_to = ('Price', 'Net', 'Range'),
names_pattern = ('TP.*', 'VR.*', 'Ti.*'),
ignore_index = False)
经测试,它的速度是最快的,每次循环需要3.53毫秒左右,误差为95微秒。
值得注意的是,这个数据集可能太小而无需关注速度,并且在更大的数据集上顺序可能不同。