假设我有一个类似这样的数据框:
我希望可以过滤掉异常值并用前两天的平均值代替。
我的“异常值规则”如下:如果某个属性/支付方式的值比前两天该属性/支付方式的平均值大两倍以上或小于一半,则将该异常值替换为前两天该属性/支付方式的平均值。否则保留该值。在此情况下,所有值都应该保留,除了$1000的销售额和5123/'2021-01-03'/'现金'的500件商品。这些值应该被替换为销售额的$90和商品数量的15。
以下是我的尝试(使用for循环,但无法正常工作)。每当我在使用循环和Pandas时,就会在我的脑海中想起一个红色警告。正确的做法是什么?
import pandas as pd
import numpy as np
data = [[5123, '2021-01-01 00:00:00', 'cash','sales$', 105],
[5123, '2021-01-01 00:00:00', 'cash','items', 20],
[5123, '2021-01-01 00:00:00', 'card','sales$', 190],
[5123, '2021-01-01 00:00:00', 'card','items', 40],
[5123, '2021-01-02 00:00:00', 'cash','sales$', 75],
[5123, '2021-01-02 00:00:00', 'cash','items', 10],
[5123, '2021-01-02 00:00:00', 'card','sales$', 170],
[5123, '2021-01-02 00:00:00', 'card','items', 35],
[5123, '2021-01-03 00:00:00', 'cash','sales$', 1000],
[5123, '2021-01-03 00:00:00', 'cash','items', 500],
[5123, '2021-01-03 00:00:00', 'card','sales$', 150],
[5123, '2021-01-03 00:00:00', 'card','items', 20]]
columns = ['Store', 'Date', 'Payment Method', 'Attribute', 'Value']
df = pd.DataFrame(data = data, columns = columns)
商店 | 日期 | 支付方式 | 属性 | 值 |
---|---|---|---|---|
5123 | 2021年1月1日 00:00:00 | 现金 | 销售额 | 105 |
5123 | 2021年1月1日 00:00:00 | 现金 | 商品数 | 20 |
5123 | 2021年1月1日 00:00:00 | 信用卡 | 销售额 | 190 |
5123 | 2021年1月1日 00:00:00 | 信用卡 | 商品数 | 40 |
5123 | 2021年1月2日 00:00:00 | 现金 | 销售额 | 75 |
5123 | 2021年1月2日 00:00:00 | 现金 | 商品数 | 10 |
5123 | 2021年1月2日 00:00:00 | 信用卡 | 销售额 | 170 |
5123 | 2021年1月2日 00:00:00 | 信用卡 | 商品数 | 35 |
5123 | 2021年1月3日 00:00:00 | 现金 | 销售额 | 1000 |
5123 | 2021年1月3日 00:00:00 | 现金 | 商品数 | 500 |
5123 | 2021年1月3日 00:00:00 | 信用卡 | 销售额 | 150 |
5123 | 2021年1月3日 00:00:00 | 信用卡 | 商品数 | 20 |
以下是我的尝试(使用for循环,但无法正常工作)。每当我在使用循环和Pandas时,就会在我的脑海中想起一个红色警告。正确的做法是什么?
stores = df['Store'].unique()
payment_methods = df['Payment Method'].unique()
attributes = df['Attribute'].unique()
df_no_outliers = pd.DataFrame()
for store in stores:
for payment_method in payment_methods:
for attribute in attributes:
df_temp = df.loc[df['Store'] == store]
df_temp = df_temp.loc[df_temp['Payment Method'] == payment_method]
df_temp = df_temp.loc[df_temp['Attribute'] == attribute]
df_temp['Value'] = np.where(df_temp['Value'] <= (df_temp['Value'].shift(-1)
+df_temp['Value'].shift(-2))*2/2,
df_temp['Value'],
(df_temp['Value'].shift(-1)+df_temp['Value'].shift(-2))/2)
df_temp['Value'] = np.where(df_temp['Value'] >= (df_temp['Value'].shift(-1)
+df_temp['Value'].shift(-2))*0.5/2,
df_temp['Value'],
(df_temp['Value'].shift(-1)+df_temp['Value'].shift(-2))/2)
df_no_outliers = df_no_outliers.append(df_temp)
如果有人好奇为什么我要使用这种滚动平均方法,而不是像 Tukey 的方法一样在 1Q 和 3Q 处截断数据多于或少于 1.5*IQR,原因是我的数据是 COVID 期间的时间序列数据,这意味着 IQR 很大(COVID 前有高销售量,然后是销售量极低的深谷),因此 IQR 最终没有过滤掉任何东西。我不想去除 COVID 导致的销售下降,而是想去掉一些错误的数据输入失败(一些商店可能会在某些日子输入一些额外的零...)。我将使用最近 5 或 7 天(即一周)作为滚动过滤器,而不是使用最近两天。我也愿意尝试其他的清理/异常值移除方法。
df.where
代替np.where
。这样就不需要import numpy
:) - not_speshal