看过来
《pandas 教程》 持续更新中,提供建议、纠错、催更等加作者微信: gr99123(备注:pandas教程)和关注公众号「盖若」ID: gairuo。跟作者学习,请进入 Python学习课程。欢迎关注作者出版的书籍:《深入浅出Pandas》 和 《Python之光》。
在监控系统、销售分析或运维日志中,我们常需检测时间序列中“短时间内数值剧烈波动”的异常行为。例如:某服务器 CPU 使用率在 5 分钟内从 20% 飙升到 95%,或某商品销量在连续两天内翻倍。这类异常往往比单点离群值更具业务意义。pandas 的 diff()、rolling().std() 与布尔索引组合,能高效识别此类连续波动模式。本文将通过一个每日销售额数据集,演示如何结合这些方法,在链式操作中自动标记“连续两日增幅超阈值”或“局部标准差突增”的异常时段。你将掌握一种实用的时间序列异常检测技巧,适用于多种监控场景。
假设我们有一张按日期记录的销售额表:
我们的目标是:
正确结果应满足:
源数据如下:
data = """
date,sales
2025-03-01,100
2025-03-02,120
2025-03-03,300
2025-03-04,50
2025-03-05,60
2025-03-06,800
2025-03-07,900
"""
读取代码:
import pandas as pd
from io import StringIO
df = pd.read_csv(StringIO(data.strip()))
我们需要同时计算两种异常信号:
sales.pct_change() > 1.0(即增长率 > 100%);sales.rolling(window=3, center=True).std() > 200;然后将两个布尔条件用 |(或)合并为最终的 is_anomaly。
注意:
pct_change() 默认计算 (当前 - 前一) / 前一,首行为 NaN;rolling(..., center=True) 使窗口以当前行为中心(如第3行对应 [2,3,4]);整个过程可通过 assign 链式完成。
代码如下:
import pandas as pd
from io import StringIO
data = """
date,sales
2025-03-01,100
2025-03-02,120
2025-03-03,300
2025-03-04,50
2025-03-05,60
2025-03-06,800
2025-03-07,900
"""
anomaly_df = (
pd.read_csv(StringIO(data.strip()))
.assign(date=lambda df: pd.to_datetime(df['date']))
.sort_values('date')
.assign(
pct_change=lambda df: df['sales'].pct_change(),
rolling_std=lambda df: df['sales'].rolling(window=3, center=True).std()
)
.assign(
is_anomaly=lambda df: (df['pct_change'] > 1.0) | (df['rolling_std'] > 200)
)
.drop(columns=['pct_change', 'rolling_std'])
)
print(anomaly_df)
'''
date sales is_anomaly
0 2025-03-01 100 False
1 2025-03-02 120 False
2 2025-03-03 300 True
3 2025-03-04 50 False
4 2025-03-05 60 True
5 2025-03-06 800 True
6 2025-03-07 900 False
'''
代码分析:
pct_change() 自动计算环比增长率,首行 NaN 不影响布尔判断(NaN 与任何比较均为 False);rolling(window=3, center=True).std() 计算以当前日为中心的 3 日标准差,边缘行(如首尾)因窗口不足返回 NaN,同样在比较中视为 False;| 合并,只要满足其一即标记为异常;pct_change 和 rolling_std 在最后被删除,保持输出简洁;例如:
该方法灵活可调(如修改阈值、窗口大小),适用于各类时间序列异常初筛任务。
(完)
更新时间:2025-11-24 13:46:52 标签:pandas python 连续 异常波动