4. 探索性数据分析与可视化
在完成数据加载与初步清洗之后,我们手上通常已经有一张结构规整的作物产量数据表:每一行代表一个地块或一个年份的观测记录,列则包含产量以及降雨量、积温、土壤有机质、施肥量、播种密度、品种等候选因子。此时不要急于把全部列丢进模型,而应先做探索性数据分析(EDA)。EDA 的目标不是"画几张好看的图",而是回答三个具体问题:产量本身的分布是否正常、哪些因子与产量存在稳定关系、这些关系是线性的还是存在分组或非线性结构。本节以一份假设的玉米产量数据集为例,演示如何用 pandas 做分组统计、用 matplotlib 与 seaborn 做关系可视化,并说明每张图应该看什么、如何判断。
先看目标变量:产量分布与异常值
任何建模工作的第一步都是理解目标变量。假设数据表 df 包含 yield_t_ha(产量,吨/公顷)、rain_mm(生育期降雨量)、gdd(有效积温)、som_pct(土壤有机质百分比)、n_kg_ha(施氮量)、density(播种密度,万株/公顷)和 variety(品种)等列。先用 df['yield_t_ha'].describe() 查看均值、标准差与四分位数,再画直方图与箱线图:
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
sns.set_theme(style="whitegrid", font_scale=1.05)
fig, axes = plt.subplots(1, 2, figsize=(11, 4))
sns.histplot(df["yield_t_ha"], kde=True, ax=axes[0], color="#3b82f6")
sns.boxplot(x=df["yield_t_ha"], ax=axes[1], color="#93c5fd")
axes[0].set_title("产量分布")
axes[1].set_title("产量箱线图")
plt.tight_layout()
plt.show()
观察要点:若直方图呈明显双峰,往往意味着数据中混入了不同品种或不同生态区,应引入分组变量再分析;若箱线图出现远离上下须的点,需要结合业务判断是录入错误还是真实的高产/低产地块,不能一律删除。示例中若产量集中在 8~12 吨/公顷、仅个别点超过 15,则这些点值得回查原始记录。
用相关系数矩阵做第一轮因子筛选
对数值型因子,最快速的筛查是皮尔逊相关系数矩阵。pandas 一行即可得到,再用 seaborn 的热力图呈现:
num_cols = ["yield_t_ha", "rain_mm", "gdd", "som_pct", "n_kg_ha", "density"]
corr = df[num_cols].corr(method="pearson")
plt.figure(figsize=(7, 5.5))
sns.heatmap(corr, annot=True, fmt=".2f", cmap="RdBu_r",
vmin=-1, vmax=1, square=True, linewidths=0.5)
plt.title("数值因子相关系数矩阵")
plt.show()
读图时注意三点:第一,关注与 yield_t_ha 所在行/列的系数绝对值,通常 |r| 在 0.3 以上才值得优先纳入候选;第二,关注因子之间的高相关(如施肥量与播种密度若 r 超过 0.8),这提示多重共线性,后续建模需做取舍或正则化;第三,皮尔逊系数只度量线性关系,若某因子与产量呈明显的抛物线关系(例如施肥过量导致减产),相关系数可能接近 0,因此不能仅凭热力图淘汰因子,必须配合散点图确认。
散点图与回归趋势:看清关系的形状
对每个候选因子画"因子—产量"散点图,并叠加 LOWESS 平滑曲线,可以同时观察线性趋势与非线性拐点。seaborn 的 lmplot 还支持按品种分面:
sns.lmplot(data=df, x="rain_mm", y="yield_t_ha",
hue="variety", lowess=True,
height=4.5, aspect=1.4, scatter_kws={"alpha": 0.5})
plt.title("降雨量与产量的关系(按品种分组)")
plt.show()
判断依据:若平滑曲线近似直线且散点围绕其均匀分布,说明线性模型可初步胜任;若曲线先升后降,说明存在最适区间,建模时应考虑加入二次项或分箱特征;若不同品种的曲线斜率明显不同,说明存在交互效应,后续可构造"品种×降雨量"交互特征。示例中若发现降雨量在 450~600 mm 区间产量上升明显、超过 650 mm 后趋于平缓,就应把这一拐点信息记录到特征工程清单中。
分组统计:把分类因子纳入视野
品种、灌溉方式、土壤类型等分类变量无法直接进入相关系数矩阵,应使用分组聚合与箱线图或小提琴图对比:
summary = df.groupby("variety")["yield_t_ha"].agg(["mean", "std", "count"])
print(summary.sort_values("mean", ascending=False))
sns.violinplot(data=df, x="variety", y="yield_t_ha", inner="quartile")
plt.title("不同品种的产量分布对比")
plt.show()
这里要同时看均值与离散度:某品种均值最高但标准差也很大,说明其表现不稳定,可能对管理条件敏感;样本量 count 过小的组别结论不可靠,不宜据此下判断。分组统计的结果应直接转化为建模决策——表现差异显著的分类变量做独热编码保留,差异微弱且样本极不均衡的变量可暂不纳入。
把图读成建模决策
EDA 的终点不是图,而是一份可执行的结论。以上述示例为例,可以整理出如下判断:降雨量与产量呈先升后平的关系,应保留原始列并增加平方项;有效积温与产量中等正相关且与降雨量相关性低,可同时保留;施氮量与播种密度高度共线,二者只保留一个,或改用岭回归等正则化方法;品种间均值差异明显但品种 B 方差大,独热编码保留品种并考虑与降雨量的交互;产量超过 15 吨/公顷的记录需回查原始台账后再决定是否剔除。这些结论应逐条写入特征工程清单,作为下一阶段建模的直接输入。
最后提醒两个工程细节:一是绘图前先处理缺失值,corr() 默认按成对完整观测计算,不同单元格的样本量可能不一致,必要时用 min_periods 参数加以约束;二是分类变量较多时,热力图与散点图会变得拥挤,应先用分组统计筛掉样本量过小的类别,再进入可视化。完成这些步骤后,数据中的主要结构、异常与候选因子已经清晰,可以进入特征工程与模型构建阶段。