PAYATHON 2026

Pandas aggregate() 后 id 列为何变成索引,如何绘图?

数据小陈

聚合结果没有问题。groupby() 默认把分组键作为结果索引,因此 id 已经是索引,不再是普通列。绘图时可以直接使用索引作为横轴:

ax = df_new.plot(kind="line", y="sales")

横轴是索引中的 101、102、103,纵轴是聚合后的 sales。

为什么会出现两个 KeyError?

原代码按 id 分组:

df_new = df.groupby(df['id']).aggregate(agg_functions)

这个示例也可以写成:

df_new = df.groupby("id").aggregate(agg_functions)

分组结果包含 employee、sales、returns 三列,索引名称为 id。可以分别查看:

print(df_new.columns)
print(df_new.index)
print(df_new.index.name)

df_new["id"] 会报错,因为这种写法访问的是列,而 id 不在列中。

第二个错误来自绘图参数。这里使用的 DataFrame.plot(kind="line", ...) 要求 x 和 y 传入列名等列选择标识,不能像 matplotlib 的横纵坐标参数那样传入数据数组。

传入 x=df_new.index 后,Pandas 会尝试在列中查找 101、102、103,因此报出这些值不在 columns 中。原代码中的 y=df_new["sales"] 也应改为 y="sales"。

方法一:直接使用索引绘图

当前数据已经以 id 为索引,省略 x 后,Pandas 默认使用索引作为横轴:

import pandas as pd
import matplotlib.pyplot as plt

df = pd.DataFrame({
    'id': [101, 101, 102, 103, 103, 103],
    'employee': ['Dan', 'Dan', 'Rick', 'Ken', 'Ken', 'Ken'],
    'sales': [4, 1, 3, 2, 5, 3],
    'returns': [1, 2, 2, 1, 3, 2]
})

agg_functions = {
    'employee': 'first',
    'sales': 'sum',
    'returns': 'sum'
}

df_new = df.groupby("id").aggregate(agg_functions)

ax = df_new.plot(kind="line", y="sales")
ax.set_xlabel("id")
ax.set_ylabel("sales")
plt.show()

示例中的三个数据点是 (101, 5)、(102, 3)、(103, 10)。

方法二:将 id 恢复为普通列

如果后续需要使用 df_new["id"],可以用 reset_index() 把索引放回列中:

df_plot = df_new.reset_index()

ax = df_plot.plot(kind="line", x="id", y="sales")
plt.show()

reset_index() 默认返回新的 DataFrame,需要接收返回值。如果只执行下面这句,原来的 df_new 不会改变:

df_new.reset_index()

要更新变量,可以写成:

df_new = df_new.reset_index()

这里不要使用 reset_index(drop=True),它会丢弃原索引中的 id 值,不会将它们恢复为列。set_index() 则是把列设为索引,不适用于当前恢复普通列的需求。

方法三:聚合时保留 id 列

也可以在分组时指定 as_index=False,让分组键保留为普通列:

df_new = df.groupby("id", as_index=False).aggregate(agg_functions)

ax = df_new.plot(kind="line", x="id", y="sales")
plt.show()

这段代码从原始 df 重新聚合,不依赖前面是否已经调用过 reset_index()。

如何单独提取 id 的值?

如果仍保留最初以 id 为索引的聚合结果,可以这样获取:

# 获取 Index 对象
a_ids = df_new.index

# 转为列表
id_list = df_new.index.tolist()

# 转为 NumPy 数组
id_values = df_new.index.to_numpy()

如果想把实际数据直接传给 matplotlib,可以使用它自己的绘图接口:

fig, ax = plt.subplots()
ax.plot(df_new.index, df_new["sales"])
ax.set_xlabel("id")
ax.set_ylabel("sales")
plt.show()

这段代码要求 df_new 仍以 id 为索引。如果已经将 id 恢复为普通列,横坐标应改用 df_new["id"]。

备注:内容仅供参考。