为何按列(axis=1)使用pandas groupby会失效报错?
pandas列分组聚合报错分析与解决
原始数据与期望结果
原始DataFrame
import pandas as pd df = pd.DataFrame({'item': [1, 2, 3, 4], 'foo_x': ['A', 'D', 'H', 'L'], 'foo_y': ['B', 'E', 'I', 'M'], 'bar_x': ['C', 'F', 'J', 'N'], 'bar_y': ['D', 'G', 'K', 'O']})
对应的表格:
| item | foo_x | foo_y | bar_x | bar_y |
|---|---|---|---|---|
| 1 | A | B | C | D |
| 2 | D | E | F | G |
| 3 | H | I | J | K |
| 4 | L | M | N | O |
期望聚合结果
| item | x | y |
|---|---|---|
| 1 | [A, C] | [B, D] |
| 2 | [D, F] | [E, G] |
| 3 | [H, J] | [I, K] |
| 4 | [L, N] | [M, O] |
报错代码与错误信息
报错代码
df_output = ( df.rename(lambda x: x.split("_")[-1], axis=1) .groupby(level=0, axis=1).agg(list) )
错误信息
ValueError: Length of values (2) does not match length of index (4)
报错原因解释
核心问题在于groupby(axis=1)时agg(list)的行为和你预期的完全相反:
- 第一步
rename后,列名变为item, x, y, x, y,groupby(axis=1)按列名分成三组:item(1列)、x(2列)、y(2列)。 - pandas中
agg(func)的默认逻辑是沿分组的反方向聚合:- 当
axis=0(行分组)时,聚合沿列方向,符合常规直觉; - 当
axis=1(列分组)时,聚合沿列方向(而非行方向):对于x组的2个列,agg(list)会把这2个列(每个是长度为4的Series)打包成一个长度为2的列表;而item组只有1个列,聚合结果长度为1。
- 当
- 合并结果时,
x/y组的结果长度(2)与DataFrame索引长度(4)不匹配,因此抛出错误。
你预期的是按行聚合:对每一行,把同组的列值合并为列表,这和agg(list)的默认行为完全不同。
正确实现方式
方法1:分组后逐行apply处理
df_output = ( df.rename(lambda x: x.split("_")[-1], axis=1) .groupby(level=0, axis=1) .apply(lambda g: g.apply(list, axis=1)) )
方法2:更高效的直接分组聚合
无需提前rename,直接提取列名后缀分组,再按行合并为列表:
# 提取每个列名的后缀(item列后缀为自身) groups = df.columns.str.split("_").str[-1] # 按后缀分组,对每组列按行合并成列表 df_output = df.groupby(groups, axis=1).agg(lambda x: x.values.tolist()) # 调整列顺序为item、x、y(可选) df_output = df_output[['item', 'x', 'y']]
两种方法都能得到你期望的结果。
内容的提问来源于stack exchange,提问作者user21474411
相关产品推荐
相关产品推荐

