通过排除四列值的异常值(四列中位数的+-25%)来计算中位数
calculate the median by excluding outliers (+-25% of median of four columns) for values of four columns values
我有四列包含过去 4 年的销售量。我想计算中位数,然后根据条件(+-25% 的中位数)排除列值来计算平均值。
df = df[['Date','ID','amount']] # df has daily data
df['dayofYear'] = df['Date'].dt.dayofyear
df['Year_Lag1']= df.groupby(['ID','dayofYear'])['amount'].transform(lambda x: x.shift(1))
df['Year_Lag2']= df.groupby(['ID','dayofYear'])['amount'].transform(lambda x: x.shift(2))
df['Year_Lag3']= df.groupby(['ID','dayofYear'])['amount'].transform(lambda x: x.shift(3))
df['Year_Lag4']= df.groupby(['ID','dayofYear'])['amount'].transform(lambda x: x.shift(4))
df['YearLag_median']= df[['Year_Lag1','Year_Lag2','Year_Lag3','Year_Lag4']].median(axis=1) #median amount on same date (is there a better way to calculate median by avoiding outliers)
如何通过避免四列中位于中位数 +- 25% 的值来计算平均值。
假设Year_Lag1 = 5000, Year_Lag2= 230, Year_Lag3=4500, Year_Lag4= 4300
.
如何通过避免 Year_Lag2
值来计算平均值。
我希望对数据框中的所有行执行此操作。
(如果有人可以通过避免异常值来提供更好的计算中位数的方法)
数据集[数据具有1月2日和3日(2014、15、16、17、18)的值。 Year_Lag1(shift(1)) 具有去年 1 月 2 日和 3 日的值。 Year_Lag2(shift(2) 的值从去年到去年)等等..]
最后一行是我想忽略 589.0 来计算平均值的示例。
[1]: https://i.stack.imgur.com/26Dvp.pngenter code here
如果您能添加一个数据框以供参考,那就太好了。尝试通过生成今年的随机日期、随机浮点数和随机 ID 来生成您在下面指定的 df。我的 df 的 5 行头部看起来像这样:
df.head(5)
amount Date ID
0 93 2019-01-01 00:00:00.000000000 AAA
1 40 2019-01-03 08:43:38.181818181 AAA
2 47 2019-01-05 17:27:16.363636363 BBB
3 37 2019-01-08 02:10:54.545454545 CCC
4 13 2019-01-10 10:54:32.727272727 CCC
这是您的数据集的样子吗?
如果是这样,那么 运行 使您提到的导致滞后的命令似乎无法按预期工作。当我 运行 它时,我得到如下所述:
df['dayofYear'] = df['Date'].dt.dayofyear
df.head(5)
Date ID amount dayofYear
0 2019-01-01 00:00:00.000000000 AAA 93 1
1 2019-01-03 08:43:38.181818181 AAA 40 3
2 2019-01-05 17:27:16.363636363 BBB 47 5
3 2019-01-08 02:10:54.545454545 CCC 37 8
4 2019-01-10 10:54:32.727272727 CCC 13 10
df['Year_Lag1']= df.groupby(['ID','dayofYear'])['amount'].transform(lambda x: x.shift(1))
df.head(5)
Date ID amount dayofYear Year_Lag1
0 2019-01-01 00:00:00.000000000 AAA 93 1 NaN
1 2019-01-03 08:43:38.181818181 AAA 40 3 NaN
2 2019-01-05 17:27:16.363636363 BBB 47 5 NaN
3 2019-01-08 02:10:54.545454545 CCC 37 8 NaN
4 2019-01-10 10:54:32.727272727 CCC 13 10 NaN
已经确定head不是唯一有nans的。整列都得到了 nans。如果您可以修改原始 post 以包含 df ,那么回答您的问题会容易得多。
这是一个解决方案,我认为应该有更好的办法,但仍然有效:
- 定义一个函数来根据您的规格计算平均值
def calculateMean(row):
s = 0
n = 0
for i in range(4):
if ~np.isnan(row[i]) and abs(row[i] - row[-1]) < 0.25 * row[-1]:
s += row[i]
n += 1
return (s/n if n else np.nan)
- 对每一行应用这个函数
df["YearLag_mean"] = df.loc[:, ['Year_Lag1','Year_Lag2','Year_Lag3','Year_Lag4', 'YearLag_median']]\
.apply(lambda row: calculateMean(row), axis=1)
输出:
Date ID amount dayofYear Year_Lag1 Year_Lag2 Year_Lag3 Year_Lag4 YearLag_median YearLag_mean
2258 2014-01-02 200 1778.0 2 NaN NaN NaN NaN NaN NaN
2259 2014-01-03 200 2149.0 3 NaN NaN NaN NaN NaN NaN
2623 2015-01-02 200 2057.0 2 1778.0 NaN NaN NaN 1778.0 1778.00
2624 2015-01-03 200 2401.0 3 2149.0 NaN NaN NaN 2149.0 2149.00
2988 2016-01-02 200 2315.0 2 2057.0 1778.0 NaN NaN 1917.5 1917.50
2989 2016-01-03 200 589.0 3 2401.0 2149.0 NaN NaN 2275.0 2275.00
3354 2017-01-02 200 1709.0 2 2315.0 2057.0 1778.0 NaN 2057.0 2050.00
3355 2017-01-03 200 1659.0 3 589.0 2401.0 2149.0 NaN 2149.0 2275.00
3719 2018-01-02 200 1991.0 2 1709.0 2315.0 2057.0 1778.0 1917.5 1964.75
3720 2018-01-03 200 1570.0 3 1659.0 589.0 2401.0 2149.0 1904.0 1904.00
如您所见,由于您的阈值,最后一行没有使用 589
但也使用了 2401
。
要删除异常值而不是使用中位数,您可以查看 IQR 或 Z-score,但我不确定它是否适用于小数据,您可以尝试一下,只是调整或创建新函数。
我有四列包含过去 4 年的销售量。我想计算中位数,然后根据条件(+-25% 的中位数)排除列值来计算平均值。
df = df[['Date','ID','amount']] # df has daily data
df['dayofYear'] = df['Date'].dt.dayofyear
df['Year_Lag1']= df.groupby(['ID','dayofYear'])['amount'].transform(lambda x: x.shift(1))
df['Year_Lag2']= df.groupby(['ID','dayofYear'])['amount'].transform(lambda x: x.shift(2))
df['Year_Lag3']= df.groupby(['ID','dayofYear'])['amount'].transform(lambda x: x.shift(3))
df['Year_Lag4']= df.groupby(['ID','dayofYear'])['amount'].transform(lambda x: x.shift(4))
df['YearLag_median']= df[['Year_Lag1','Year_Lag2','Year_Lag3','Year_Lag4']].median(axis=1) #median amount on same date (is there a better way to calculate median by avoiding outliers)
如何通过避免四列中位于中位数 +- 25% 的值来计算平均值。
假设Year_Lag1 = 5000, Year_Lag2= 230, Year_Lag3=4500, Year_Lag4= 4300
.
如何通过避免 Year_Lag2
值来计算平均值。
我希望对数据框中的所有行执行此操作。
(如果有人可以通过避免异常值来提供更好的计算中位数的方法) 数据集[数据具有1月2日和3日(2014、15、16、17、18)的值。 Year_Lag1(shift(1)) 具有去年 1 月 2 日和 3 日的值。 Year_Lag2(shift(2) 的值从去年到去年)等等..]
最后一行是我想忽略 589.0 来计算平均值的示例。
[1]: https://i.stack.imgur.com/26Dvp.pngenter code here
如果您能添加一个数据框以供参考,那就太好了。尝试通过生成今年的随机日期、随机浮点数和随机 ID 来生成您在下面指定的 df。我的 df 的 5 行头部看起来像这样:
df.head(5)
amount Date ID
0 93 2019-01-01 00:00:00.000000000 AAA
1 40 2019-01-03 08:43:38.181818181 AAA
2 47 2019-01-05 17:27:16.363636363 BBB
3 37 2019-01-08 02:10:54.545454545 CCC
4 13 2019-01-10 10:54:32.727272727 CCC
这是您的数据集的样子吗? 如果是这样,那么 运行 使您提到的导致滞后的命令似乎无法按预期工作。当我 运行 它时,我得到如下所述:
df['dayofYear'] = df['Date'].dt.dayofyear
df.head(5)
Date ID amount dayofYear
0 2019-01-01 00:00:00.000000000 AAA 93 1
1 2019-01-03 08:43:38.181818181 AAA 40 3
2 2019-01-05 17:27:16.363636363 BBB 47 5
3 2019-01-08 02:10:54.545454545 CCC 37 8
4 2019-01-10 10:54:32.727272727 CCC 13 10
df['Year_Lag1']= df.groupby(['ID','dayofYear'])['amount'].transform(lambda x: x.shift(1))
df.head(5)
Date ID amount dayofYear Year_Lag1
0 2019-01-01 00:00:00.000000000 AAA 93 1 NaN
1 2019-01-03 08:43:38.181818181 AAA 40 3 NaN
2 2019-01-05 17:27:16.363636363 BBB 47 5 NaN
3 2019-01-08 02:10:54.545454545 CCC 37 8 NaN
4 2019-01-10 10:54:32.727272727 CCC 13 10 NaN
已经确定head不是唯一有nans的。整列都得到了 nans。如果您可以修改原始 post 以包含 df ,那么回答您的问题会容易得多。
这是一个解决方案,我认为应该有更好的办法,但仍然有效:
- 定义一个函数来根据您的规格计算平均值
def calculateMean(row):
s = 0
n = 0
for i in range(4):
if ~np.isnan(row[i]) and abs(row[i] - row[-1]) < 0.25 * row[-1]:
s += row[i]
n += 1
return (s/n if n else np.nan)
- 对每一行应用这个函数
df["YearLag_mean"] = df.loc[:, ['Year_Lag1','Year_Lag2','Year_Lag3','Year_Lag4', 'YearLag_median']]\
.apply(lambda row: calculateMean(row), axis=1)
输出:
Date ID amount dayofYear Year_Lag1 Year_Lag2 Year_Lag3 Year_Lag4 YearLag_median YearLag_mean
2258 2014-01-02 200 1778.0 2 NaN NaN NaN NaN NaN NaN
2259 2014-01-03 200 2149.0 3 NaN NaN NaN NaN NaN NaN
2623 2015-01-02 200 2057.0 2 1778.0 NaN NaN NaN 1778.0 1778.00
2624 2015-01-03 200 2401.0 3 2149.0 NaN NaN NaN 2149.0 2149.00
2988 2016-01-02 200 2315.0 2 2057.0 1778.0 NaN NaN 1917.5 1917.50
2989 2016-01-03 200 589.0 3 2401.0 2149.0 NaN NaN 2275.0 2275.00
3354 2017-01-02 200 1709.0 2 2315.0 2057.0 1778.0 NaN 2057.0 2050.00
3355 2017-01-03 200 1659.0 3 589.0 2401.0 2149.0 NaN 2149.0 2275.00
3719 2018-01-02 200 1991.0 2 1709.0 2315.0 2057.0 1778.0 1917.5 1964.75
3720 2018-01-03 200 1570.0 3 1659.0 589.0 2401.0 2149.0 1904.0 1904.00
如您所见,由于您的阈值,最后一行没有使用 589
但也使用了 2401
。
要删除异常值而不是使用中位数,您可以查看 IQR 或 Z-score,但我不确定它是否适用于小数据,您可以尝试一下,只是调整或创建新函数。