如何在时间序列图中添加平滑线?为各站点生成平滑曲线
嘿,我来给你几个实用的解决方案——不用先手动计算月度均值,直接在绘图环节就能让每个站点的时间序列曲线变得更平滑:
常用的绘图时自动平滑方法
1. 滑动窗口平滑(Rolling Window Smoothing)
这是最直观也最容易上手的方法,核心是对每个时间点取前后N个数据的均值/中位数,你可以根据数据的时间粒度灵活调整窗口大小(比如日数据用7天窗口,小时数据用24小时窗口)。
用Python的pandas+matplotlib实现的示例代码:
import pandas as pd import matplotlib.pyplot as plt # 假设你的数据存储在df中,包含'time'(时间列)、'value'(数值列)、'station'(站点列) for station in df['station'].unique(): # 取出单个站点的数据并按时间排序 station_data = df[df['station'] == station].sort_values('time') # 计算7天中心滑动均值(center=True让窗口以当前点为中心) station_data['smoothed_value'] = station_data['value'].rolling(window=7, center=True).mean() # 绘制平滑后的曲线 plt.plot(station_data['time'], station_data['smoothed_value'], label=f'{station} 平滑曲线') plt.legend() plt.xlabel('时间') plt.ylabel('数值') plt.show()
2. LOESS/LOWESS局部加权回归平滑
这种方法会对数据做局部加权拟合,能自适应捕捉数据的非线性波动,比滑动窗口更灵活,适合波动不规则的时间序列。
用seaborn可以一键实现,代码非常简洁:
import seaborn as sns import matplotlib.pyplot as plt # seaborn的lineplot自带lowess平滑选项,直接指定即可 sns.lineplot(data=df, x='time', y='value', hue='station', lowess=True) plt.xlabel('时间') plt.ylabel('数值') plt.show()
如果需要更精细的控制,用statsmodels手动拟合:
from statsmodels.nonparametric.smoothers_lowess import lowess import pandas as pd import matplotlib.pyplot as plt for station in df['station'].unique(): station_data = df[df['station'] == station].sort_values('time') # frac参数控制平滑程度,取值0-1,越小越贴近原数据,越大越平滑 smoothed_result = lowess(station_data['value'], station_data['time'], frac=0.15) # 提取平滑后的时间和数值 smooth_time = smoothed_result[:, 0] smooth_value = smoothed_result[:, 1] plt.plot(smooth_time, smooth_value, label=f'{station} 平滑曲线') plt.legend() plt.xlabel('时间') plt.ylabel('数值') plt.show()
3. 三次样条插值平滑
如果你想要极致顺滑的曲线,可以用三次样条将离散的时间点连接成连续的平滑曲线,适合需要美观展示的场景。不过要注意,如果原数据存在异常值,可能会被过度拟合,建议先做异常值处理。
用scipy实现的示例:
from scipy.interpolate import make_interp_spline import numpy as np import pandas as pd import matplotlib.pyplot as plt for station in df['station'].unique(): station_data = df[df['station'] == station].sort_values('time') # 将时间转换为数值格式(比如时间戳) time_num = np.array(station_data['time'].astype('int64')) values = station_data['value'].values # 创建三次样条插值函数 spline_func = make_interp_spline(time_num, values, k=3) # 生成更密集的时间点,让曲线更顺滑 smooth_time_num = np.linspace(time_num.min(), time_num.max(), 500) smooth_values = spline_func(smooth_time_num) # 转换回时间格式 smooth_time = pd.to_datetime(smooth_time_num) plt.plot(smooth_time, smooth_values, label=f'{station} 平滑曲线') plt.legend() plt.xlabel('时间') plt.ylabel('数值') plt.show()
补充:R语言用户的方案
如果你用ggplot2绘图,直接用geom_smooth()函数就能轻松实现平滑:
library(ggplot2) ggplot(df, aes(x = time, y = value, color = station)) + geom_line(alpha = 0.3) + # 可选:绘制原曲线作为对比 geom_smooth(method = "loess", se = FALSE) + # LOESS平滑,se=FALSE去掉置信区间 labs(x = "时间", y = "数值")
你可以根据自己数据的特点和需求选择合适的方法——滑动窗口适合简单场景,LOESS适合非线性波动数据,样条插值适合追求美观顺滑的展示~
内容的提问来源于stack exchange,提问作者Essi
相关产品推荐
相关产品推荐

