给出一个数据框df
Value
Category Pool Class
A 1.0 1.0 1
9.0 2
B 1.0 1.0 3
C 1.0 1.0 4
5.0 5
我想将级别Pool
和Class
转换为没有reset_index
的整数(见下文)。
我尝试像这样使用get_level_values
和set_levels
的组合
for c in ['Pool', 'Class']:
df.index.set_levels(df.index.get_level_values(c).astype(int), level=c, inplace=True)
但是,这引起了
ValueError: Level values must be unique: [1, 1, 1, 1, 1] on level 1
要了解会发生什么,我还尝试使用verify_integrity=False
。然后
df.index.set_levels(df.index.get_level_values('Class').astype(int),
level='Class', verify_integrity=False, inplace=True)
产生
Value
Category Pool Class
A 1.0 1 1
1 2
B 1.0 1 3
C 1.0 1 4
9 5
我的目标是获得
Value
Category Pool Class
A 1.0 1 1
9 2
B 1.0 1 3
C 1.0 1 4
5 5
如何正确实现? get_level_values
和set_levels
的链接是正确的方式吗?为什么pandas
用astype
转换后不能正确设置级别?
我想您可以使用reset_index
和set_index
,但是拥有方法set_levels
有什么好处?
d = {'Category': str, 'Pool': int, 'Class': int}
df.reset_index(drop=False, inplace=True)
for k, v in d.items():
df[k] = df[k].astype(v)
df.set_index(list(d.keys()), inplace=True)
答案 0 :(得分:1)
您可以直接通过pd.MultiIndex.levels
访问索引级别并馈送到pd.MultiIndex.set_levels
:
df.index = df.index.set_levels(df.index.levels[2].astype(int), level=2)
print(df)
Value
Category Pool Class
A 1.0 1 1
9 2
B 1.0 1 3
C 1.0 1 4
5 5
答案 1 :(得分:1)
以下功能可以用作get_level_values
的补充:
def set_level_values(midx, level, values):
full_levels = list(zip(*midx.values))
names = midx.names
if isinstance(level, str):
if level not in names:
raise ValueError(f'No level {level} in MultiIndex')
level = names.index(level)
if len(full_levels[level]) != len(values):
raise ValueError('Values must be of the same size as original level')
full_levels[level] = values
return pd.MultiIndex.from_arrays(full_levels, names=names)
使用此功能,原始问题的解决方案是:
for c in ['Pool', 'Class']:
df.index = set_level_values(df.index, level=c, values=df.index.get_level_values(c).astype(int))