4. 时间序列数据可视化

任务说明

本案例使用Matplotlib绘制一个温度传感器的时间序列数据图,数据模拟工业设备每10秒采集一次的温度读数,持续24小时。目标是通过折线图展示温度的整体趋势,并利用阈值检测在图上高亮标记异常点(超出正常范围的数据)。

实现方案

代码首先生成24小时内的模拟温度数据(含正常波动与人为注入的异常尖峰),然后计算滑动平均值以平滑噪声并突出趋势,最后通过上下阈值识别异常点,在折线图上用红色散点标记。图表包含图例、网格和阈值参考线,便于直接观察趋势与异常。

时间序列可视化流程 ① 数据生成 时间戳 + 温度值 含异常尖峰 ② 趋势提取 滑动平均(窗口=30) 平滑噪声 ③ 异常检测 阈值: 20°C ~ 32°C 越界即标记 ④ 绘图 折线+散点 图例+网格 预期输出示意图(温度趋势与异常标记) 15°C 25°C 35°C 上限32°C 下限20°C 温度 异常 阈值

完整代码

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.dates import DateFormatter

# ---------- 1. 生成模拟传感器数据 ----------
np.random.seed(42)
time_steps = 8640  # 24小时 * 3600秒 / 10秒
time_index = pd.date_range(start="2024-01-01 00:00:00", periods=time_steps, freq="10s")

# 基础温度:24°C + 昼夜波动 + 随机噪声
hour_of_day = time_index.hour + time_index.minute / 60
daily_cycle = 3 * np.sin(2 * np.pi * (hour_of_day - 6) / 24)  # 最低温在凌晨6点
noise = np.random.normal(0, 0.5, time_steps)
temperature = 24 + daily_cycle + noise

# 注入5个异常尖峰(模拟传感器故障或环境突变)
anomaly_positions = [1000, 3000, 5200, 7000, 8200]
for pos in anomaly_positions:
    temperature[pos] += np.random.choice([-8, 8])  # 大幅偏离

# ---------- 2. 计算滑动平均(趋势线) ----------
df = pd.DataFrame({"time": time_index, "temp": temperature})
df["trend"] = df["temp"].rolling(window=30, center=True).mean()

# ---------- 3. 异常检测(阈值法) ----------
LOWER, UPPER = 20.0, 32.0
df["is_anomaly"] = (df["temp"] < LOWER) | (df["temp"] > UPPER)
anomalies = df[df["is_anomaly"]]

# ---------- 4. 绘制时间序列图 ----------
fig, ax = plt.subplots(figsize=(14, 6))

# 原始数据(浅色细线)与趋势线(深色粗线)
ax.plot(df["time"], df["temp"], color="#94a3b8", linewidth=0.8, alpha=0.7, label="原始数据")
ax.plot(df["time"], df["trend"], color="#2563eb", linewidth=2.0, label="趋势(滑动平均)")

# 异常点高亮
ax.scatter(anomalies["time"], anomalies["temp"], color="#dc2626", s=40, 
           zorder=5, label=f"异常点 (n={len(anomalies)})")

# 阈值参考线
ax.axhline(y=LOWER, color="#f59e0b", linestyle="--", linewidth=1.2, label=f"下限 {LOWER}°C")
ax.axhline(y=UPPER, color="#f59e0b", linestyle="--", linewidth=1.2, label=f"上限 {UPPER}°C")

# 坐标轴与格式
ax.set_xlabel("时间", fontsize=12)
ax.set_ylabel("温度 (°C)", fontsize=12)
ax.set_title("传感器温度时间序列 - 趋势与异常检测", fontsize=14, fontweight="bold")
ax.xaxis.set_major_formatter(DateFormatter("%m-%d %H:%M"))
ax.legend(loc="upper right", fontsize=10)
ax.grid(True, alpha=0.3)
plt.xticks(rotation=45)
plt.tight_layout()

# 保存图片(可选)
# plt.savefig("sensor_timeseries.png", dpi=150)
plt.show()

# ---------- 验证输出 ----------
print(f"数据点总数: {len(df)}")
print(f"检测到异常点数量: {len(anomalies)}")
print(f"温度范围: {df['temp'].min():.2f}°C ~ {df['temp'].max():.2f}°C")
print("异常点时间分布:")
print(anomalies[["time", "temp"]].head(10).to_string(index=False))

运行与验证

依赖安装:确保已安装 numpy、pandas、matplotlib,可通过 pip install numpy pandas matplotlib 安装。

运行方式:将代码保存为 timeseries_plot.py,在终端执行 python timeseries_plot.py。

验证判定标准:

  • 程序正常弹出窗口并显示折线图,无报错;
  • 图中可见蓝色趋势线平滑跟随灰色原始数据波动;
  • 红色散点恰好标记5个注入的异常位置(时间点1000、3000、5200、7000、8200附近);
  • 控制台输出“检测到异常点数量: 5”,且温度范围包含低于20°C或高于32°C的极值。

若以上条件均满足,则说明时间序列可视化与异常检测功能实现正确。