第1章:数据准备与预处理——时间序列分析的基石

说实话,我见过太多人一上来就急着建模,结果模型跑出来一塌糊涂。为什么?数据没处理好。时间序列分析里,数据准备占了80%的工作量,这绝不是夸张。我自己踩过的坑,十个有八个都出在数据预处理阶段。

核心观点:数据准备的质量,直接决定预测模型的天花板。数据脏,模型再牛也白搭。

1.1 时间序列数据清洗——先把垃圾倒掉

数据清洗,说白了就是把那些明显不对劲的数据揪出来。我接手过一个项目,某天的销量突然飙到100万,一看就知道是系统bug。如果不处理,模型会以为那天有什么特殊事件,预测全乱套。

常见的脏数据有这几类:

  • 重复数据:同一时间点出现多条记录
  • 异常值:明显偏离正常范围的数据点
  • 格式错误:日期格式不统一,比如有的用"2024-01-01",有的用"01/01/2024"
  • 逻辑错误:比如结束时间早于开始时间

我的经验:清洗时别用肉眼扫数据,写个脚本自动检查。我习惯先画个时序图,异常点一眼就能看出来。

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

# 加载数据
df = pd.read_csv('sales_data.csv', parse_dates=['date'])
df.set_index('date', inplace=True)

# 快速检查重复
print(f"重复行数:{df.index.duplicated().sum()}")

# 删除重复
df = df[~df.index.duplicated(keep='first')]

# 可视化检查异常
plt.figure(figsize=(12, 4))
plt.plot(df.index, df['sales'])
plt.title('销量时序图——一眼看出异常')
plt.show()

1.2 缺失值处理——别让空值毁了你的模型

时间序列的缺失值处理,跟普通表格数据不一样。你不能随便填个平均值,因为时间序列有趋势和季节性。我曾经犯过这个错,结果模型预测出来全是平的,毫无意义。

常用的方法有:

方法 适用场景 注意事项
前向填充(ffill) 数据变化缓慢,比如温度 连续缺失太多会失真
后向填充(bfill) 数据有滞后性 会引入未来信息,慎用
线性插值 趋势明显的序列 对突变数据不友好
季节性插值 有周期性的数据 需要先确定周期长度

避坑指南:我曾经用均值填充处理股票数据,结果模型完全忽略了波动性。记住,时间序列的缺失值处理,一定要考虑前后文关系。

# 前向填充
df['sales_ffill'] = df['sales'].fillna(method='ffill')

# 线性插值
df['sales_interp'] = df['sales'].interpolate(method='linear')

# 季节性插值(假设周期为7天)
df['sales_seasonal'] = df['sales'].interpolate(method='time')

1.3 重采样与对齐——让数据节奏一致

你想想看,如果有的数据是小时级的,有的是天级的,怎么一起分析?重采样就是解决这个问题的。我做过一个项目,销售数据是日频,但天气数据是小时频,不重采样根本没法用。

重采样的核心是确定目标频率:

  • 降采样:高频转低频,比如小时转天。常用聚合函数:sum、mean、max
  • 升采样:低频转高频,比如天转小时。需要插值或填充

关键点:重采样时一定要想清楚业务含义。比如销量用sum聚合,温度用mean聚合,别搞混了。

# 降采样:日数据转周数据
weekly_sales = df['sales'].resample('W').sum()

# 升采样:日数据转小时数据
hourly_sales = df['sales'].resample('H').ffill()

# 对齐两个时间序列
df1_aligned = df1.reindex(df2.index, method='ffill')

1.4 日期时间索引处理——时间序列的身份证

日期时间索引是时间序列的灵魂。没有它,你没法做任何时间相关的操作。我刚开始学的时候,总把日期当普通列处理,结果各种报错。后来才明白,必须把日期设成索引。

常见的处理包括:

  • 解析日期:把字符串转成datetime对象
  • 设置索引:用set_index把日期列变成行索引
  • 提取特征:从日期中提取年、月、日、星期几等
  • 处理时区:跨时区数据要统一

我的习惯:拿到数据第一件事,就是检查索引是不是datetime类型。如果不是,立刻转换。这一步做对了,后面省心很多。

# 解析日期
df['date'] = pd.to_datetime(df['date'], format='%Y-%m-%d')

# 设置索引
df.set_index('date', inplace=True)

# 提取特征
df['year'] = df.index.year
df['month'] = df.index.month
df['day_of_week'] = df.index.dayofweek  # 0=周一

# 处理时区
df.index = df.index.tz_localize('UTC').tz_convert('Asia/Shanghai')

知识体系总览

下面这张图,是我自己总结的数据准备流程。每次做项目前,我都会对照着走一遍,确保不遗漏任何步骤。

时间序列数据准备流程 数据加载 数据清洗 缺失值处理 重采样与对齐 日期时间索引处理 常见问题 • 重复数据 • 异常值 • 格式错误 • 前向填充 • 线性插值 • 季节性插值 • 降采样 • 升采样 • 时区处理 • 特征提取 避坑指南 1. 别用均值填充 2. 重采样选对聚合函数 3. 索引必须是datetime 4. 先画图再处理 5. 保留原始数据备份 6. 注意时区统一 7. 连续缺失别超过阈值 8. 异常值要确认再删

嗯,以上就是数据准备与预处理的全部内容。记住,这一步做扎实了,后面的建模才能顺风顺水。我自己每次做项目,都会在这个阶段花最多时间,因为我知道——数据准备好了,模型自然就出来了。