Python 通过箱线图去除异常值以计算序列/数据帧的平均值?

Python 通过箱线图去除异常值以计算序列/数据帧的平均值?,python,dataframe,seaborn,boxplot,outliers,Python,Dataframe,Seaborn,Boxplot,Outliers,我试图计算数据帧中没有异常值的每列(系列)的平均值。我使用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); 这就是我得到的: 我真的很想得到没有异常值的每个单位(x轴)的平均值。这背后的原因是,如果我错了,请纠正我,

我试图计算数据帧中没有异常值的每列(系列)的平均值。我使用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);
这就是我得到的:

我真的很想得到没有异常值的每个单位(x轴)的平均值。这背后的原因是,如果我错了,请纠正我,我希望得到这个特性的平均值,没有异常值,如下所示 他们把它弄歪了


谢谢

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

一旦去除了异常值,计算平均值就非常简单,只需在数据帧的每一列上调用
.mean()
函数,或使用
.descripe()
函数即可

在不涉及太多细节的情况下,这是一种确定值与平均值之间的标准偏差的方法。其实很简单,就是每个值减去平均值,除以数据集的标准偏差。一般来说,对于接近平均值的正态分布数据,z分数为3可以用作过滤器,如下例所示

计算z分数的一种简单方法是使用
scipy.stats
模块,并使用

对于这个例子,我合成了一个数据集,可以在这个答案的底部找到。此外,由于我比seaborn更熟悉plotly,所以我选择使用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分数进行筛选: 这显示了如何在数据帧的每列上计算z分数的示例,其中过滤的值存储到第二个数据帧

步骤:

  • 迭代每个列
  • 使用
    scipy.stats.zscore()函数计算z分数
  • 筛选以仅保留z分数大于3的记录
  • 存储到新的数据帧中
例如:

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]
输出:

样本数据集构造: 下面是更无关的代码,用于构建示例数据集

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})

有趣的问题。(无论如何对我来说)。我只是给你一个答案,并试图尽可能多地解释,这使它简单明了。帮帮忙这帮你上车!嘿,谢谢你的帮助!试图运行代码,但在计算z_分数的代码块中出现以下错误:“值的长度与索引的长度不匹配”。同样奇怪的是,剔除异常值后,平均值似乎在0左右。这是正确的吗?我想知道为什么这不是seaborn的一个选项,因为我认为有人会很容易地得到一个没有异常值的平均值。再次感谢!更新。我为“after”示例中的零均值表示歉意,感谢您指出这一点。愚蠢的我绘制了z分数,而不是通过z分数过滤的数据。这一点已得到纠正。请告诉我你进展如何。更改:1)过滤行已更新为:
df_z[f'{c}u z']=df.loc[zYes,它现在可以工作了。谢谢!所以您只需通过z_分数过滤掉,我自己也可以使用它。我认为Seaborn的箱线图是基于四分位数的计算和IQR(75%-25%)之上的他们计算一个下限和一个上限,并标记这些异常值,如果它们延伸到胡须之上/之下。根据你的经验,z_分数比他们用来计算异常值的分数更好吗?顺便说一句,我从你的代码中学到了很多,所以谢谢你。非常感谢!非常好,很高兴它起作用。请你点击e在答案中打勾表示您已接受?(标准SO实践)。有很多方法可以跟踪异常值-但是,是的,z-score通常是我的第一站,因为它可以查看标准偏差。此外,您可以绘制数据的直方图并直观地确定异常值边界…任何真正符合目的的方法。关于代码,谢谢。有更有效的方法来编写其中一些,但选择了t他是最具可读性的选择。干杯,伙计。干杯,伙计,祝你一切顺利!
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})