2. 全图仅剩一个点:聚合与分组键误用定位
问题现象与最小复现
散点图或折线图只出现一个点,通常不是绘图库坏了,而是进入绘图函数的数据本身只剩一行。常见来源有三类:分组键选错(把唯一标识列当成了分组列)、聚合函数误用(对整表做了一次全局聚合)、索引重置缺失(分组后索引被压平,绘图时按索引对齐导致只剩一个有效点)。下面用一份可复现的教学数据定位问题。
import pandas as pd
import matplotlib.pyplot as plt
# 教学示例数据:3 个样本,每个样本 4 个时间点
df = pd.DataFrame({
"sample_id": ["S1"]*4 + ["S2"]*4 + ["S3"]*4,
"time_h": [0, 1, 2, 3] * 3,
"signal": [1.0, 1.8, 2.4, 3.1,
0.9, 1.5, 2.0, 2.6,
1.2, 2.0, 2.7, 3.4],
})
# 错误写法 A:把唯一标识当分组键
bad_a = df.groupby("sample_id").mean(numeric_only=True)
print(bad_a.shape) # (3, 2) —— 每个样本被压成一行
# 错误写法 B:全局聚合,整表只剩一行
bad_b = df.agg({"signal": "mean"})
print(bad_b.shape) # (1,) —— 这就是"一个点"的直接来源
# 错误写法 C:分组后未 reset_index,绘图按索引对齐
bad_c = df.groupby("time_h")["signal"].mean()
print(bad_c.index.name) # time_h,索引被替换,原 sample_id 丢失
三种写法都会让绘图输入的行数骤减。判断依据很直接:绘图前打印 df.shape 与 df.head(),若行数等于分组数而非原始观测数,就说明数据已被压缩。
定位与修复
按“先看行数、再看分组键、最后看索引”的顺序排查,能快速锁定问题。修复的核心是保留观测粒度:绘图数据必须是每个时间点一行,而不是每个样本一行。
# 修复 A:分组键改为真正的时间列,并保留样本维度
fixed_a = (df.groupby(["sample_id", "time_h"], as_index=False)
.agg(signal_mean=("signal", "mean")))
print(fixed_a.shape) # (12, 3) —— 与原始观测数一致
# 修复 B:若确实需要全局统计,单独计算,不要覆盖绘图数据
global_mean = df["signal"].mean()
print(f"全局均值 = {global_mean:.3f}") # 仅作参考线,不替代散点
# 修复 C:分组后重置索引,恢复可对齐的列
fixed_c = (df.groupby("time_h", as_index=False)
.agg(signal_mean=("signal", "mean")))
print(fixed_c.columns.tolist()) # ['time_h', 'signal_mean']
# 绘图验证
fig, ax = plt.subplots(figsize=(6, 4))
for sid, g in df.groupby("sample_id"):
ax.plot(g["time_h"], g["signal"], marker="o", label=sid)
ax.axhline(global_mean, color="gray", linestyle="--", linewidth=1, label="全局均值")
ax.set_xlabel("time_h")
ax.set_ylabel("signal")
ax.legend()
plt.tight_layout()
plt.show()
修复后应看到 3 条折线、每条 4 个点,共 12 个标记点,并有一条灰色全局均值参考线。若仍只有一个点,继续检查
ax.plot 传入的 x、y 是否被误传为标量。验证清单
| 检查项 | 期望值 | 异常含义 |
|---|---|---|
| 绘图数据行数 | 等于原始观测数(本例 12) | 行数=分组数或 1,说明被聚合压缩 |
| 分组键列 | 时间/类别列,非唯一标识 | 用 sample_id 分组会丢失时间维度 |
| 索引状态 | 已 reset_index 或 as_index=False | 索引替换导致绘图对齐失败 |
| 绘图标记数 | 与数据行数一致 | 标记数少于行数,检查 x/y 传参 |
本例的关键结论:单点问题几乎总能在绘图前的数据形状上找到证据。把 shape、分组键和索引状态三处核对清楚,再进入绘图环节,就能避免把数据压缩问题误判为坐标轴或渲染问题。