使用Pandas筛选分组中a列大于组内均值的行时遇值错误的问询
解决Pandas分组后出现的「Duplicated level name」错误
嘿,这个问题我碰到过好几次!你之所以触发ValueError: Duplicated level name: "id", assigned to level 1, is already used for level 0,核心原因很简单:你的DataFrame的索引已经命名为"id"了,而groupby("id").apply()默认会把分组键"id"作为结果的上层索引,这就导致最终的索引里出现了两个同名的"id"层级,Pandas可不允许这种情况~
下面给你三种靠谱的解决办法,按需选用:
方法1:用transform计算组内均值(最推荐,性能最优)
这种方式不需要用apply,直接通过广播实现筛选,速度快代码也简洁:
import pandas as pd import numpy as np # 先构造你给出的示例DataFrame df = pd.DataFrame( data = {"a": np.arange(10), "b": np.arange(10)[::-1], "c": np.random.choice(np.arange(10), size=10)}, index = pd.Index(np.random.choice([1,2,3], size=10), name="id") ) # 计算每个id分组的a列均值,自动广播到原DataFrame的每一行 group_a_mean = df.groupby("id")["a"].transform("mean") # 直接筛选a列大于组内均值的行 filtered_df = df[df["a"] > group_a_mean]
方法2:在apply后清理重复索引层级
如果你坚持要用apply的写法,只需要在结果里把重复的"id"索引层级去掉就行:
filtered_df = df.groupby("id").apply(lambda x: x[x.a > x.a.mean()]).reset_index(level=0, drop=True)
这里reset_index(level=0, drop=True)会把apply新增的外层"id"索引删掉,保留你原来的索引结构,就不会有重复名称的问题了。
方法3:用groupby.filter方法(最直观)
Pandas的filter方法就是专门用来筛选符合组内条件的行的,用法非常直接:
filtered_df = df.groupby("id").filter(lambda x: x["a"] > x["a"].mean())
这个方法会直接返回符合条件的原DataFrame行,完全不会改动索引结构,完美避开重复层级的坑。
再啰嗦下原代码的问题
你的原代码执行后,apply会把分组的"id"作为外层索引,而你的原始DataFrame索引已经叫"id",所以最终结果的索引会变成一个两层的MultiIndex,两层都叫"id"——Pandas对索引层级的名称唯一性有要求,所以直接抛出了错误。
内容的提问来源于stack exchange,提问作者Alex
相关产品推荐
相关产品推荐

