首页 > 编程知识 正文

异常值 离群值,离群值是不是异常值

时间:2023-05-03 20:07:07 阅读:273055 作者:734

前天参加面试的时候被问了一个题:选择什么样的指标来代表总体情况?我回答的不是很好,具体怎么回答的记不太清了,感觉回答的不是很好。回来后吸取教训,查了查资料简单总结:

如果是类别变量,可以用众数来代表总体。如果是连续变量,可以用平均数或中位数来代表总体。如果数据的异常值、极端异常值比较多,那么尽可能使用中位数;如果没有太明显的异常值,平均数更具有代表性。

那这里就引申出一个问题,异常值的识别。异常值(outlier)是数据清洗的重要环节,异常值可能直接会导致后面的数据分析、建模工作出现偏差,因为像AdaBoost、GBDT等都对异常值很敏感。

异常值甄别 1、3σ准则

如果样本是正态分布或近似正态分布,可以考虑使用3σ方法,认为99%以上的数据集中在均值上下3个标准差的范围内。具体来说,数值分布在(μ-3σ,μ+3σ)中的概率为99.73%,超过这个范围的极大或极小值,那就是异常值了。

实例 import pandas as pdimport numpy as npimport matplotlib.pyplot as pltimport seaborn as sns# 导入试验数据df = pd.read_csv(r'F:数据分析项目游戏数据分析野蛮时代数据分析tap_fun_train.csv')# 从中取出100个数,先做一个直方图看看分布状态df = df[df['wood_add_value']>0].head(100)sns.distplot(df['wood_add_value'])

从图上看出来,其实不算是很标准的正态分布,但就凑合用吧,能说明排查方法和过程就好。

计算均值。a = df['wood_add_value'].mean(),均值为781190.89。然后计算标准差。b = df['wood_add_value'].std(),标准差为2196896.04。计算排查范围:(a-3*b, a+3*b)得到结果:(-5809497.23,7371879.01)。使用上述区间作为条件进行筛选就可以,df[(df['wood_add_value']>7371879)|(df['wood_add_value']<-5809497)]['wood_add_value'],得出异常值为:15968730、9669530、8668980。 2、使用箱型图

箱形图(Box-plot)又称为盒须图、盒式图或箱线图,是一种用作显示一组数据分散情况资料的统计图。因形状如箱子而得名。(百度百科)
还是以wood_add_value为例,因为由于这个数值受要塞等级bd_stronghold_level的影响非常大,所以做了不同要塞等级的箱型图分布。

使用seaborn绘图 df2 = df[df['wood_add_value']>0] # 没有任何数值记录说明没玩游戏,所以没有分析的意义plt.figure(figsize = (18,8))sns.boxplot(x = df2['bd_stronghold_level'],y = df2['wood_add_value'])


随便选其中的一个等级,比如就15级吧,说明箱型图的意义。

df3 = df2[df2['bd_stronghold_level']==15]plt.figure(figsize = (8,6))sns.boxplot(x = df3['bd_stronghold_level'],y = df3['wood_add_value'],width = 0.2)


非异常值的范围都在上限和下限之间,超出上限和下限的就定位为异常值。

使用DataFrame自带的绘图工具

这种方法不仅可以绘图,还可以方便的输出具体的异常值是哪些。

由于只有DataFrame格式可以使用,所以数据不能是Series格式

df4 = df3[['bd_stronghold_level','wood_add_value']]plt.figure(figsize = (8,6))outlier = df4.boxplot(return_type = 'dict')x = outlier['fliers'][1].get_xdata() # 这个get_xdata我不太清楚啥意思,可能是表示哪一个column的异常值。y = outlier['fliers'][1].get_ydata() # 具体的异常值是什么y1 = list(y)print(y1)Out[92]: [327291568.0, 539691776.0, 765436570.0, 498063299.0]


最后得出15级要塞的wood_add_value的异常值是这些:[327291568.0, 539691776.0, 765436570.0, 498063299.0]。实际处理中,除了箱型图进行客观的排查,还可以加入主观判断,对于超出范围的值,如果超出范围不是非常大,可以看做正常值。

异常值处理

异常值已经被找出来了,那么怎么处理呢?实际处理中没有固定的方法,要根据分析的目的来确定。

删除。如果想找出一般的规律,而且异常值也不太多,可以考虑删除。因为异常值可能会影响结论。很多节目中计算选手最后得分往往去掉一个最高分,去掉一个最低分,可能就是这个道理。比如我们现在研究就是要塞等级bd_stronghold_level为15级的玩家的道具消耗特征,这时候异常值显然会拉高整体的水平,影响判断,所以可以考虑删除,我们要了解大多数玩家。

放任不管。因为异常值代表的也是真实发生的事件,背后是具体的行为。有些值即使异常,也不会影响模型。比如我们研究wood_add_value和pay_price的关系,想做回归分析,也就是看道具消耗和充值金额的因果关系。我们能够很清楚的看到刚才找到的wood_add_value的4个异常值,虽然他们游离于群体之外,但是在对pay_price进行拟合的时候并没有使模型造成太大偏差。所以这种异常值对我们的模型来说很合理。

plt.figure(figsize = (12,6))plt.subplot(1,2,1)sns.scatterplot(x='wood_add_value', y='pay_price',data = df3)plt.subplot(1,2,2)sns.regplot(x='wood_add_value', y='pay_price',data = df3)

视为缺失值进行填充。因为贸然删除数据可能会损失信息,而如果放任不管可能又影响我们的模型,所以可以考虑用均值、临近值进行填充。如下面这个例子,依旧是用wood_add_value对pay_price进行回归预测(样本不一样了)。从图上看绿圈和红圈那两个点,有可能会影响回归线的方向(蓝色线是python拟合的,绿线和红线是我自己画的)。所以这种异常值还是处理掉比较好。 sns.scatterplot(x='wood_add_value', y='pay_price',data = df2)


异常值到底该怎么处理,我也在学习。在用户分层的时候,发现异常值代表了一些极端的高价值用户,ARPU可能是平均水平的几千倍,可能也是需要把极端值单独提取出来,对用户进行实时的“监控”,这类用户流失造成的损失实在太大了。还有就是异常值的甄别和处理可能还有很多其他方法,目前我也还没学,暂且如此吧,且用且学且记。

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。