MultiIndex 上的 Pandas set_levels:级别值必须是唯一的

gof*_*onx 4 python indexing multi-index dataframe pandas

给定一个数据帧 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
Run Code Online (Sandbox Code Playgroud)

我想在没有(见下文)的情况下将级别PoolClass整数转换为整数reset_index

我尝试使用get_level_valuesset_levels像这样的组合

for c in ['Pool', 'Class']:
    df.index.set_levels(df.index.get_level_values(c).astype(int), level=c, inplace=True)
Run Code Online (Sandbox Code Playgroud)

然而,这引发了

ValueError: Level values must be unique: [1, 1, 1, 1, 1] on level 1
Run Code Online (Sandbox Code Playgroud)

为了了解会发生什么,我还尝试使用verify_integrity=False. 然后

df.index.set_levels(df.index.get_level_values('Class').astype(int),
                    level='Class', verify_integrity=False, inplace=True)
Run Code Online (Sandbox Code Playgroud)

产生

                    Value
Category Pool Class      
A        1.0  1         1
              1         2
B        1.0  1         3
C        1.0  1         4
              9         5
Run Code Online (Sandbox Code Playgroud)

而我的目标是获得

                    Value
Category Pool Class      
A        1.0  1         1
              9         2
B        1.0  1         3
C        1.0  1         4
              5         5
Run Code Online (Sandbox Code Playgroud)

如何正确实现这一目标?是链接get_level_valuesset_levels正确的方法吗?为什么pandas在用 转换后无法正确设置级别astype

我想你可以使用reset_indexset_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)
Run Code Online (Sandbox Code Playgroud)

jpp*_*jpp 7

您可以通过以下方式直接访问索引级别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
Run Code Online (Sandbox Code Playgroud)

  • 谢谢!如何通过名称来引用级别?事实上,我有一个级别名称和类型的“dict”,我想用它来进行转换。另外,上面的“ValueError”的原因是什么? (3认同)
  • @jpp是否有某种“set_level_values”方法可以补充“get_level_values”? (2认同)

Era*_*ran 5

以下函数可以用作 的补充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)
Run Code Online (Sandbox Code Playgroud)

使用此函数,原始问题的解决方案将是:

for c in ['Pool', 'Class']:
    df.index = set_level_values(df.index, level=c, values=df.index.get_level_values(c).astype(int))
Run Code Online (Sandbox Code Playgroud)