pandas:对多层列数据框进行排序/重新排列列
我有以下数据:
from pandas import Timestamp
values = [['IDX100', 'field1', Timestamp('1999-02-01 05:00:00'), '101'],
['IDX100', 'field1', Timestamp('1999-02-02 05:00:00'), '102'],
['IDX100', 'field1', Timestamp('1999-02-03 05:00:00'), '103'],
['IDX200', 'field1', Timestamp('1999-02-01 05:00:00'), '601'],
['IDX200', 'field1', Timestamp('1999-02-02 05:00:00'), '602'],
['IDX200', 'field1', Timestamp('1999-02-03 05:00:00'), '603'],
['IDX100', 'field2', Timestamp('1999-02-01 05:00:00'), '201'],
['IDX100', 'field2', Timestamp('1999-02-02 05:00:00'), '202'],
['IDX100', 'field2', Timestamp('1999-02-03 05:00:00'), '203'],
['IDX200', 'field2', Timestamp('1999-02-01 05:00:00'), '701'],
['IDX200', 'field2', Timestamp('1999-02-02 05:00:00'), '702'],
['IDX200', 'field2', Timestamp('1999-02-03 05:00:00'), '703'],
['IDX100', 'field3', Timestamp('1999-02-01 05:00:00'), '301'],
['IDX100', 'field3', Timestamp('1999-02-02 05:00:00'), '302'],
['IDX100', 'field3', Timestamp('1999-02-03 05:00:00'), '303'],
['IDX200', 'field3', Timestamp('1999-02-01 05:00:00'), '801'],
['IDX200', 'field3', Timestamp('1999-02-02 05:00:00'), '802'],
['IDX200', 'field3', Timestamp('1999-02-03 05:00:00'), '803']]
df = pd.DataFrame(values, columns = ['identifier', 'code', 'date', 'value'])
在对我的数据表进行透视后,我得到了以下结果:
df = df.pivot(index=['date'], columns=['identifier', 'code'], values=['value'])
value
identifier IDX100 IDX200 IDX100 IDX200 IDX100 IDX200
code field1 field1 field2 field2 field3 field3
date
1999-02-01 05:00:00 101 601 201 701 301 801
1999-02-02 05:00:00 102 602 202 702 302 802
1999-02-03 05:00:00 103 603 203 703 303 803
不过,我希望输出的结果看起来像这样:
identifier IDX100 IDX200
code field3 field2 field1 field3 field2 field1
date
1999-02-01 05:00:00 301 201 101 801 701 601
1999-02-02 05:00:00 302 202 102 802 702 602
1999-02-03 05:00:00 303 203 103 803 703 603
我可以通过做一些类似的操作接近这个结果:
df = df.reindex(sorted(df.columns), axis=1)
但是这样做会保持level2列的顺序为field1、field2、field3。我希望能够以不同的顺序来排列这些字段……最好是根据我提供的一个列表来排序。例如,我可能想要的顺序是field3、field2、field1,或者field2、field1、field3。
有没有人能帮我解决这个问题?
2 个回答
3
一种标准且可靠的方法是使用有序的 CategoricalDtype
:
codes = pd.CategoricalDtype(['field2', 'field1', 'field3'], ordered=True)
out = (df.astype({'code': codes})
.pivot(index=['date'], columns=['identifier', 'code'], values='value')
.sort_index(axis=1)
)
或者,可以在透视后进行排序:
codes = pd.CategoricalDtype(['field2', 'field1', 'field3'], ordered=True)
out = df.pivot(index=['date'], columns=['identifier', 'code'], values='value')
out.columns = pd.MultiIndex.from_frame(out.columns.to_frame().astype({'code': codes}))
out = out.sort_index(axis=1)
输出结果:
identifier IDX100 IDX200
code field2 field1 field3 field2 field1 field3
date
1999-02-01 05:00:00 201 101 301 701 601 801
1999-02-02 05:00:00 202 102 302 702 602 802
1999-02-03 05:00:00 203 103 303 703 603 803
2
示例代码
特别是当数据框(dataframe)包含多重索引时,需要提供创建数据框的代码,以便你能够复现你的数据框。
这次,我为你提供了代码。
import pandas as pd
data = [[101, 601, 201, 701, 301, 801], [102, 602, 202, 702, 302, 802], [103, 603, 203, 703, 303, 803]]
idx = pd.Index(['1999-02-01 05:00:00', '1999-02-02 05:00:00', '1999-02-03 05:00:00'], name='date')
cols = pd.MultiIndex.from_product([['field1', 'field2', 'field3'], ['IDX100', 'IDX200']], names=['code', 'identifier']).swaplevel(0, 1)
df = pd.DataFrame(data, index=idx, columns=cols)
df
代码
让我们按照 field2 -> field1 -> field3 的顺序进行排序
使用 sort_index
方法
order = ['field2', 'field1', 'field3']
m = {key: num for num, key in enumerate(order)}
out = df.sort_index(axis=1, key=lambda x: x.map(m) if x.name == 'code' else x)
输出: