Pandas 2.2+中使用groupby().apply()分组采样时消除DeprecationWarning的正确方案
Pandas 2.2+中使用groupby().apply()分组采样时消除DeprecationWarning的正确方案
嘿,我来帮你搞定这个警告问题!先拆解下警告的根源:Pandas 2.2+开始提示,groupby().apply()默认把分组列包含在操作的子DataFrame里的行为即将被弃用,你的代码刚好踩了这个点。
最直接的解决方案(简化代码+消除警告)
其实你完全不需要用apply来实现分组采样——Pandas的groupby本身就自带sample方法,不仅高效,还能完美避开这个警告!
修改你的sample_per_locale函数如下:
def sample_per_locale(df): # 直接用groupby.sample一步实现按组采样 sampled_df = df.groupby("locale", group_keys=False).sample( n=5, replace=False, random_state=42, ignore_index=True ) return sampled_df
运行这个代码,警告会彻底消失,输出结果完全符合需求:每个locale组最多取5行(组内不足5行就全取),同时保留locale列。
为什么这个方案能解决问题?
groupby.sample是Pandas官方专门为分组场景设计的采样API,内部已经处理了分组列的逻辑,不会触发apply相关的弃用警告。而且代码比你原来的嵌套groupby+apply简洁太多,性能也更好。
若必须保留apply写法的修复方案
如果因为特殊原因一定要用apply,可以调整逻辑,避免在apply中处理包含分组列的子DataFrame:
def sample_per_locale(df): sampled_df = df.groupby("locale", group_keys=False) \ .apply(lambda x: x.drop(columns="locale").sample(min(5, len(x)), random_state=42)) \ .join(df["locale"], on=lambda idx: idx.get_level_values(0)) \ .reset_index(drop=True) return sampled_df
这个思路是:在apply里先去掉locale列,采样后再通过索引把locale列合并回来,这样就不会触发分组列相关的警告。不过说实话,这个写法远不如groupby.sample优雅。
关于include_groups=False的说明
你之前尝试用这个参数报错,是因为它是Pandas 2.3版本才新增的参数,你的2.2.1确实不支持。等之后升级到2.3+版本,就可以这样写来消除警告:
df.groupby("locale", group_keys=False) \ .apply(lambda x: x.sample(min(5, len(x)), random_state=42), include_groups=False) \ .reset_index(drop=True)
不过还是那句话,能用groupby.sample就别用apply,前者是专门的API,更靠谱。
为什么你之前的尝试没用?
- 用
include_groups=False报错:版本不兼容,该参数尚未在你的Pandas版本中引入 - 显式选择
locale列:警告是在apply执行过程中触发的,你在apply之后的列选择操作根本没触及警告的根源,所以无效
备注:内容来源于stack exchange,提问作者user321627




