如何在Pandas中实现基于星期几的中心滚动窗口异常值检测?
实现基于星期几的同周几滚动窗口异常值检测
核心思路是按星期几分组,同一星期几的日期按时间顺序排列后,用窗口大小为5的中心滚动窗口,就能自动取到当前日期的往前2个、往后2个同星期几的数据(共5个)。具体实现步骤如下:
步骤1:添加星期几标识列
给原DataFrame添加一列标记日期对应的星期几,用pd.Series.dt.weekday,其中0代表周一,1代表周二,以此类推。
步骤2:按星期几分组计算滚动统计量
对每个星期几的分组,单独做滚动窗口计算(窗口大小5,中心=True),这样每个日期对应的窗口就是同星期几的前后各2个数据。
步骤3:合并统计量并替换异常值
把分组计算得到的均值、标准差合并回原DataFrame,然后按照原逻辑检测异常值并替换。
完整代码
import pandas as pd import numpy as np np.random.seed(0) # 生成原始数据 dates = pd.date_range(start='2022-01-01', end='2023-12-31', freq='D') prices1 = np.random.randint(10, 100, size=len(dates)) prices2 = np.random.randint(20, 120, size=len(dates)).astype(float) df = pd.DataFrame({'Date': dates, 'Price1': prices1, 'Price2': prices2}) # 添加星期几列,0=周一,1=周二...6=周日 df['dow'] = df['Date'].dt.weekday # 按星期几分组,计算滚动均值和标准差 def rolling_stats(group): # 确保分组内数据按日期排序(生成数据时已有序,此处做保险) group = group.sort_values('Date') r = group['Price1'].rolling(window=5, center=True) group['roll_mean'] = r.mean() group['roll_std'] = r.std() return group # 应用分组计算并重置索引 df = df.groupby('dow').apply(rolling_stats).reset_index(drop=True) # 计算上下限并替换异常值 price_up = df['roll_mean'] + 2 * df['roll_std'] price_low = df['roll_mean'] - 2 * df['roll_std'] mask_upper = df['Price1'] > price_up mask_lower = df['Price1'] < price_low df.loc[mask_upper, 'Price1'] = df['roll_mean'] df.loc[mask_lower, 'Price1'] = df['roll_mean'] # 可查看周一的数据验证窗口逻辑 print(df[df['dow'] == 0].head(10))
关键说明
- 分组后每个组都是同一星期几的日期,按时间排序后,
rolling(window=5, center=True)会自动以当前行为中心,取前后各2行数据,完全匹配你要的“往前2个同星期几+往后2个同星期几”的需求。 - 分组的首尾2行数据因无法凑齐5个样本(比如第一个周一没有往前2个周一),滚动统计量会是
NaN,你可以根据需求处理这些值(比如保留原始数据,或用前/后向填充)。
内容的提问来源于stack exchange,提问作者r ram
相关产品推荐
相关产品推荐

