第三章:数据采集与预处理
数据采集与预处理,说白了就是给削峰填谷算法「喂饭」。
饭喂得不好,算法再牛也白搭。我在项目中见过太多次了——数据没洗干净,模型跑出来全是噪音,最后还得回头查数据源。
这一章,咱们就把数据采集和预处理这摊事聊透。
3.1 数据源类型:你从哪儿搞数据?
削峰填谷算法需要的数据,通常来自三个地方:
- 服务器指标:CPU、内存、磁盘IO、网络带宽。这些数据一般通过监控系统(比如Prometheus、Zabbix)采集。
- 数据库记录:业务表里的订单量、用户活跃数、交易流水。直接从MySQL、PostgreSQL或者ClickHouse里拉。
- 业务日志:Nginx访问日志、应用日志(比如Java的log4j)。日志里藏着用户行为模式,对预测峰值很有用。
我个人习惯,先把数据源分类画个图,这样心里有数。
我的经验:别一上来就全量采集。先搞清楚你削峰填谷要预测什么指标,再决定数据源。比如你要预测数据库连接数,那服务器CPU和业务日志可能比数据库记录更直接。
3.2 数据清洗:脏数据必须处理
数据采集上来,第一件事不是分析,是清洗。
你想想看,服务器偶尔宕机、网络闪断、业务代码bug——这些都会产生脏数据。脏数据不处理,模型学到的全是错误模式。
常见的脏数据有:
- 重复数据:同一时间戳采集了多条记录
- 缺失字段:某条记录CPU使用率为null
- 格式不一致:时间戳有的是"2024-01-01 12:00:00",有的是"2024/01/01 12:00"
- 越界值:CPU使用率出现-5%或者150%
清洗策略我一般这么定:
| 脏数据类型 | 处理方法 | 适用场景 |
|---|---|---|
| 重复数据 | 去重(保留第一条或最后一条) | 所有场景 |
| 缺失字段 | 前向填充 / 插值 / 删除 | 时间序列数据用前向填充 |
| 格式不一致 | 统一转换为标准格式 | 时间戳必须统一为Unix时间戳 |
| 越界值 | 截断或标记为异常 | 物理上限明确的指标用截断 |
注意:我曾经在一个项目中,因为没处理重复数据,导致削峰填谷模型把同一个峰值算了两次,结果扩容策略直接翻倍。嗯,那天的运维同学差点没骂死我。
3.3 异常值处理:别让离群点带偏了
异常值跟脏数据不太一样。脏数据是明显错误的,异常值可能是真实发生的极端情况。
比如双十一零点,订单量突然暴涨100倍——这不是脏数据,这是真实的业务峰值。削峰填谷算法恰恰要学习这种模式。
那怎么区分?我一般用两种方法:
- 3σ原则:数据服从正态分布时,超过均值±3倍标准差的值视为异常。适合CPU、内存这类相对稳定的指标。
- IQR(四分位距):超过Q1-1.5*IQR或Q3+1.5*IQR的值视为异常。适合订单量这类分布不均匀的指标。
处理方式上,我的建议是:
- 如果是明显错误(比如CPU使用率-5%),直接删除或修正
- 如果是真实极端值(比如双十一峰值),保留并打标签
- 如果是传感器抖动导致的毛刺,用滑动平均平滑掉
# 一个简单的异常值检测示例(Python伪代码)
import numpy as np
def detect_outliers_iqr(data):
Q1 = np.percentile(data, 25)
Q3 = np.percentile(data, 75)
IQR = Q3 - Q1
lower_bound = Q1 - 1.5 * IQR
upper_bound = Q3 + 1.5 * IQR
outliers = (data < lower_bound) | (data > upper_bound)
return outliers
# 使用:标记异常但不删除,留给后续判断
data['is_outlier'] = detect_outliers_iqr(data['cpu_usage'])
避坑指南:我曾经把双十一的峰值当异常值删掉了,结果模型预测出来的扩容策略完全不够用。后来我学乖了——异常值先标记,再结合业务判断。削峰填谷的场景里,峰值往往是最重要的信号。
3.4 时间序列对齐:让数据在同一个节拍上
不同数据源的时间粒度不一样。服务器指标可能是10秒一个点,数据库记录是1分钟一个点,业务日志可能是5分钟聚合一次。
削峰填谷算法要求所有输入数据在同一个时间轴上。这就需要对时间序列进行对齐。
对齐方式有两种:
- 降采样:把高频数据聚合到低频。比如把10秒的CPU数据聚合成1分钟的平均值。
- 升采样:把低频数据插值到高频。比如把1分钟的订单量插值到10秒一个点。
我个人习惯用降采样。原因很简单——升采样会引入人为构造的数据,反而可能误导模型。
# 时间序列对齐示例(Python伪代码)
import pandas as pd
# 假设有两个数据源
cpu_data = pd.read_csv('cpu_10s.csv', parse_dates=['timestamp'])
order_data = pd.read_csv('order_1min.csv', parse_dates=['timestamp'])
# 统一降采样到1分钟
cpu_1min = cpu_data.resample('1T', on='timestamp').mean()
order_1min = order_data.resample('1T', on='timestamp').sum()
# 合并到同一个DataFrame
aligned_data = pd.merge(cpu_1min, order_1min, on='timestamp', how='inner')
注意:对齐的时候要小心时区问题。我遇到过服务器用UTC,数据库用东八区,日志用本地时间——三个时间轴对不上,模型训练出来全是乱的。统一转成Unix时间戳再对齐,最保险。
嗯,数据采集与预处理这部分,说白了就是「垃圾进,垃圾出」的反面——你把数据搞干净了,算法才能好好干活。下一章咱们聊聊特征工程,怎么从这些干净数据里挖出真正有用的信号。
公众号:蓝海资料掘金营,微信deep3321