删除异常值以通过箱线图计算 series/dataframe 的平均值?

Removing outliers to calculate mean of a series/dataframe via boxplots?

我正在尝试计算没有异常值的数据框中每一列(系列)的平均值。我使用 seaborn 的箱线图来完成这项任务:

plt.figure(figsize=(50, 10),dpi=200)
sns.boxplot(x='Unit_Code',y='Leadtime',hue='Has_Weekend?',data=df ,palette='winter')
plt.xticks(rotation=90);

这就是我得到的:

plot1

我真的很想得到没有异常值的每个单位(x 轴)的平均值。这背后的合理性,如果我错了请纠正我,我想得到这个特征的平均值,没有异常值,因为 他们扭曲了它。

谢谢!

可以通过多种方式移除异常值。此示例使用 z-score 方法移除异常值。

一旦异常值被移除,计算平均值就像在 DataFrame 的每一列上调用 .mean() 函数或使用 .describe() 函数一样简单。

无需过多赘述,z-score 是一种确定某个值与平均值之间有多少标准差的方法。这真的很简单,就是每个值减去平均值,除以数据集的标准差。一般来说,对于接近均值的正态分布数据,z 分数 3 可以用作过滤器 - 这在下面的案例中得到了证明。

This article might be of interest, regarding the detection and removal of outliers.

计算 z 得分的一种简单方法可能是使用 scipy.stats 模块,以及 docs referenced here.

对于这个例子,我合成了一个数据集,可以在这个答案的底部找到。此外,由于我对 plotly 比 seaborn 更熟悉,所以我选择使用 plotly 进行绘图。

让我们继续吧...

之前:

此示例代码与问题无关,只是绘制代码。

l = {'title': 'Boxplot - With Outliers'}
t = []
t.append({'y': df['AZGD01'], 'type': 'box', 'name': 'AZGD01'})
t.append({'y': df['AZPH01'], 'type': 'box', 'name': 'AZPH01'})
t.append({'y': df['AZPV01'], 'type': 'box', 'name': 'AZPV01'})

iplot({'data': t, 'layout': l})

输出:

使用 z 分数过滤:

这显示了如何在 DataFrame 的每一列上计算 z-score 的示例,其中 filtered 值存储到第二个 DataFrame。

步骤:

  • 迭代每一列
  • 使用 scipy.stats.zscore() 函数计算 z 分数
  • 过滤以仅保留 z 得分 > 3 的记录
  • 存储到新的 DataFrame

示例:

from scipy import stats

df_z = pd.DataFrame()

for c in df:
    # Calculate z-score for each column.
    z = stats.zscore(df[c])
    # Filter to keep records with z-scores < 3.
    df_z[f'{c}_z'] = df.loc[z<3, c]

之后:

同样,只是不相关的绘图代码 - 但请注意第二个(过滤后的)DataFrame 用于绘图。

l = {'title': 'Boxlot - Outliers (> 3 std) Removed'}
t = []
t.append({'y': df_z['AZGD01_z'], 'type': 'box', 'name': 'AZGD01'})
t.append({'y': df_z['AZPH01_z'], 'type': 'box', 'name': 'AZPH01'})
t.append({'y': df_z['AZPV01_z'], 'type': 'box', 'name': 'AZPV01'})

iplot({'data': t, 'layout': l})

输出:

示例数据集构建:

下面是更不相关的代码,用于构建示例数据集。

import numpy as np
import pandas as pd
from plotly.offline import iplot
from sklearn.preprocessing import MinMaxScaler

mms = MinMaxScaler((0, 100))

np.random.seed(7)
vals1 = mms.fit_transform(np.random.randn(1000).reshape(-1, 1)).ravel()
np.random.seed(3)
vals2 = mms.fit_transform(np.random.randn(1000).reshape(-1, 1)).ravel()
np.random.seed(73)
vals3 = mms.fit_transform(np.random.randn(1000).reshape(-1, 1)).ravel()
outl1 = np.arange(150, 200, 10)
outl2 = np.arange(200, 250, 10)
outl3 = np.arange(250, 300, 10)

data1 = np.concatenate([vals1, outl1])
data2 = np.concatenate([vals2, outl2])
data3 = np.concatenate([vals3, outl3])

df = pd.DataFrame({'AZGD01': data1, 'AZPH01': data2, 'AZPV01': data3})