【问题标题】:Pandas set_levels on MultiIndex: Level values must be uniqueMultiIndex 上的 Pandas set_levels:级别值必须是唯一的
【发布时间】:2019-03-26 18:53:20
【问题描述】:

给定一个 DataFrame 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)

【问题讨论】:

    标签: python pandas dataframe indexing multi-index


    【解决方案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
    

    【讨论】:

    • 谢谢!如何按名称引用级别?事实上,我有一个级别名称和类型的dict,我想用于转换。还有,上面的ValueError是什么原因?
    • levels 与 get_level_values 不同,前者是 set_levels 所期望的。 levels 获取唯一索引,get_level_values 获取每个索引。它们本质上是不同的,自己测试一下。这也可能是您收到ValueError 的原因。
    • @jpp 是否有某种set_level_values 方法可以补充get_level_values?
    • @Eran,据我所知,这不存在。我只看到set_levels。
    【解决方案2】:

    以下函数可以作为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))
    

    【讨论】:

      猜你喜欢
      • 2014-08-21
      • 2019-10-18
      • 1970-01-01
      • 2022-01-04
      • 2020-02-14
      • 2013-01-22
      • 2018-11-18
      • 2020-09-16
      • 2015-05-22
      相关资源
      最近更新 更多