超越基础散点图用Statsmodels的Lowess为你的数据添加平滑趋势线附美国犯罪率案例当数据点像夜空中的繁星般散落在图表上时我们常常需要一根星座连线来揭示隐藏的规律。这就是Lowess平滑技术的魅力所在——它不假设数据遵循某种特定数学模型而是让数据自己讲述它的趋势故事。1. 为什么散点图需要趋势线原始散点图就像未经加工的钻石原石虽然包含宝贵信息但需要专业切割才能展现真正价值。在美国犯罪率数据集中每个州都是独立的点谋杀率X轴与入室盗窃率Y轴的关系被数据噪声和离群值所掩盖。关键痛点人眼难以准确判断密集点群的总体趋势异常值会扭曲对整体关系的判断非线性关系在原始散点中难以辨识提示当数据点超过50个时添加趋势线几乎总是能提升图表的信息传达效率。2. Lowess原理让数据自述其故事局部加权散点平滑Locally Weighted Scatterplot Smoothing是一种非参数回归方法它不像传统线性回归那样强加全局假设。其核心思想可以用三个关键词概括局部对每个点的估计只使用邻近数据加权距离越近的点权重越高稳健通过迭代降低异常值影响技术参数对比表参数典型值作用调整建议frac0.66平滑窗口比例数据噪声大时减小it3稳健迭代次数异常值多时增加delta0.01计算效率参数大数据集可提高# Lowess核心算法伪代码 def lowess(x, y, frac0.66, it3): for iteration in range(it): for i in range(len(x)): # 1. 计算当前点的邻域半径 # 2. 根据距离计算权重(三次方函数) # 3. 加权最小二乘拟合局部多项式 # 4. 存储拟合值 # 异常值检测与权重调整 return smoothed_y3. 实战为犯罪率数据添加Lowess曲线让我们用Python实现一个专业级的可视化方案。这个方案不仅完成基础绘图还包含多个实用技巧import pandas as pd import matplotlib.pyplot as plt import statsmodels.api as sm from matplotlib import font_manager # 中文显示解决方案 plt.rcParams[font.sans-serif] [SimHei] plt.rcParams[axes.unicode_minus] False # 数据准备 crime pd.read_csv(crimeRatesByState2005.csv) clean_data crime[~crime[state].isin([District of Columbia,United States])] # 创建专业级图表 fig, ax plt.subplots(figsize(10, 6), dpi120) ax.scatter(clean_data[murder], clean_data[burglary], marker*, color#00CC88, s80, label各州数据) # Lowess平滑 lowess sm.nonparametric.lowess( clean_data[burglary], clean_data[murder], frac0.6, # 更敏感的局部拟合 it4 # 加强异常值抵抗 ) ax.plot(lowess[:, 0], lowess[:, 1], color#FF6600, linewidth3, labelLowess趋势线) # 图表优化 ax.set_xlim(0, 10) ax.set_ylim(0, 1200) ax.set_xlabel(谋杀率(每十万人), fontsize12, labelpad10) ax.set_ylabel(入室盗窃率(每十万人), fontsize12, labelpad10) ax.set_title(美国各州谋杀率与入室盗窃率关系(2005), fontsize14, pad20) ax.grid(True, linestyle--, alpha0.6) ax.legend(locupper right, framealpha0.9) # 添加数据来源标注 fig.text(0.95, 0.02, 数据来源: 美国司法部2005年度报告, haright, vabottom, fontsize9) plt.tight_layout() plt.savefig(crime_with_lowess.png, bbox_inchestight)代码亮点解析使用dpi120确保输出图像清晰度通过s参数调整散点大小增强可读性橙色趋势线与绿色散点形成视觉对比添加数据来源标注提升专业性4. 高级应用Lowess参数调优指南不同的frac参数会产生截然不同的趋势线# 测试不同平滑参数 frac_values [0.3, 0.5, 0.7, 0.9] colors [#FF9933, #FF6600, #CC3300, #990000] plt.figure(figsize(12, 6)) for frac, color in zip(frac_values, colors): lowess sm.nonparametric.lowess( clean_data[burglary], clean_data[murder], fracfrac ) plt.plot(lowess[:, 0], lowess[:, 1], colorcolor, linewidth2, labelffrac{frac}) plt.scatter(clean_data[murder], clean_data[burglary], color#00CC88, alpha0.7) plt.legend(title平滑参数) plt.title(不同frac参数对Lowess曲线的影响, fontsize14) plt.xlabel(谋杀率) plt.ylabel(入室盗窃率)参数选择经验法则密集线性数据0.6-0.8稀疏非线性数据0.3-0.5强噪声数据增加迭代次数(it4-5)5. 超越基础复合可视化技巧真正的数据分析高手往往通过图层叠加来增强信息密度。以下是三种进阶技巧技巧一置信区间展示from sklearn.utils import resample import numpy as np # 自助法计算置信区间 n_iterations 100 frac 0.6 smooth_curves [] for _ in range(n_iterations): sample resample(clean_data) lowess sm.nonparametric.lowess( sample[burglary], sample[murder], fracfrac ) smooth_curves.append(lowess[:, 1]) mean_curve np.mean(smooth_curves, axis0) std_curve np.std(smooth_curves, axis0) plt.fill_between(lowess[:, 0], mean_curve - 1.96*std_curve, mean_curve 1.96*std_curve, color#FF6600, alpha0.2)技巧二关键点标注# 找出异常点 residuals clean_data[burglary] - np.interp( clean_data[murder], lowess[:, 0], lowess[:, 1]) outliers clean_data[abs(residuals) 2*residuals.std()] for _, row in outliers.iterrows(): plt.annotate(row[state], (row[murder], row[burglary]), textcoordsoffset points, xytext(5,5), haleft)技巧三多趋势线对比# 按地区分组拟合 regions clean_data[region].unique() colors plt.cm.tab10.colors for region, color in zip(regions, colors): subset clean_data[clean_data[region] region] lowess sm.nonparametric.lowess( subset[burglary], subset[murder], frac0.7) plt.plot(lowess[:, 0], lowess[:, 1], colorcolor, linewidth2, labelregion)