2016-10-10 60 views
4

正如您从以下摘要中看到的,9月1日的计数(1542677)远低于每月的平均计数。如何查找低于(或高于)平均值的值

from StringIO import StringIO 

myst="""01/01/2016 8781262 
01/02/2016 8958598 
01/03/2016 8787628 
01/04/2016 9770861 
01/05/2016 8409410 
01/06/2016 8924784 
01/07/2016 8597500 
01/08/2016 6436862 
01/09/2016 1542677 
""" 
u_cols=['month', 'count'] 

myf = StringIO(myst) 
import pandas as pd 
df = pd.read_csv(StringIO(myst), sep='\t', names = u_cols) 

是否有一个数学公式可以定义(暧昧)的概念这个“低于或太高的方式”?

如果我定义一个限制(例如9或10%),这很容易。但是我希望脚本能够为我决定,如果最低值和倒数第二低值之间的差值超过整体5%,则返回值。在这种情况下,应该返回9月的月数。

回答

3

过滤异常值的常用方法是使用标准偏差。在这种情况下,我们将计算一个zscore,它将快速确定每个观测值偏离平均值多少个标准偏差。然后,我们可以过滤那些大于2个标准偏差的观察值。对于正态分布的随机变量,这应该发生在大约5%的时间。

定义zscore功能

def zscore(s): 
    return (s - np.mean(s))/np.std(s) 

其应用到count

zscore(df['count']) 

0 0.414005 
1 0.488906 
2 0.416694 
3 0.831981 
4 0.256946 
5 0.474624 
6 0.336390 
7 -0.576197 
8 -2.643349 
Name: count, dtype: float64 

注意,九月观察是2.6标准偏差值的距离。

使用absgt识别异常

zscore(df['count']).abs().gt(2) 

0 False 
1 False 
2 False 
3 False 
4 False 
5 False 
6 False 
7 False 
8  True 
Name: count, dtype: bool 

此外,九月回来真。

将其结合在一起来过滤原始数据帧

df[zscore(df['count']).abs().gt(2)] 

enter image description here

过滤器的其他方式

df[zscore(df['count']).abs().le(2)] 

enter image description here

+0

如果我改变四月值从9770861至977086.它不会返回任何东西。在这种情况下,我预计四月和九月。可能超过2个月超出范围! – shantanuo

+0

@shantanuo当然,你正在用很少的观察来重新定义分布的样子。如果这些只是你的观察结果,那么4月份的新价值就意味着9月份的价值不再像我们想象的那样“奇怪”了。你仍然可以通过将你的阈值从'2'降低到'1.5'来捕获这两者,我不建议这样做。或者你可以相信,由于你有更多的观测值来计算平均值,所以这两个值实际上会被识别为异常值。 – piRSquared

+0

将阈值从2改为1.5解决了我的问题。这正是我所期待的。有没有什么特别的原因,你不推荐这个? – shantanuo

2

首先,在下面的“方式或太高“的概念是你所指的被称为Outlier,并引用了维基百科(不是最好的来源),

有什么构成异常值没有严格的数学定义;确定观察是否异常最终是一种主观练习。

但在另一边:

在一般情况下,如果人口分布的性质是先验已知的,可以测试是否异常值的数量显著从什么可以预期偏离。

所以在我看来,这可以归结为这个问题,是否有可能对数据的性质做出假设,以便能够自动化这种分解。

简单的方法

如果你足够幸运,有一个比较大的样本大小,和你不同的样本是不相关的,你可以应用central limit theorem,其中指出,你的价值观会按照正常分配(有关python相关说明,请参见this)。

在这种情况下,您可以快速获取平均值标准偏差给定数据集的。通过将the corresponding function(使用这两个参数)应用于每个给定值,您可以计算出其属于“集群”的概率(有关可能的python解决方案,请参阅此stackoverflow post)。

然后你必须放一个下限,因为这个分布只有当一个点离平均值无限远时才返回0%概率。但好处是(如果假设是真实的),这个界限将很好地适应每个不同的数据集,因为它是指数规范化的性质。这种约束通常表示为西格玛单位,并广泛用于科学和统计。作为事实上,物理诺贝尔奖2013年,致力于为希格斯玻色子的发现,在达到5-sigma范围之后得到了批准,引用链接:

高能物理需要更低的p值宣布证据或发现。 “粒子证据”的阈值对应于p = 0.003,并且“发现”的标准是p = 0.0000003。

替代物

如果你不能让你的数据应该怎么看起来像这样简单的假设,你总是可以让一个程序infere他们。这种方法是大多数机器学习算法的核心特征,如果调整得当,它可以很好地适应强相关甚至偏斜的数据。如果这是你所需要的,那么Python有很多很好的库,甚至可以放入一个小脚本中(我最熟悉的是谷歌的tensorflow)。

在这种情况下,我会认为两种不同的方法,对请问你的数据看起来同样取决于:

  • 监督学习:如果你有一个训练集在处置,各国该样本属于并且哪些不属于(称为,标记为),但有像support vector machine这样的算法,虽然很轻,但可以惊人地适应高度非线性边界。

  • 无监督学习:这可能是我会先尝试的:当你只是有未标记的数据集。我之前提到的“简单方法”是异常检测器的最简单情况,因此可以对其进行高度调整和定制,从而也考虑到由于kernel trick而导致的尺寸甚至无限大的相关性。为了理解基于ML的异常探测器的动机和方法,我建议看看Andrew Ng的videos

我希望它有帮助! 干杯

+0

彻底而有见地。当然值得赞赏:-) – piRSquared

2

筛选异常值的一种方法是四分位数间距(IQR,wikipedia),它是75%(Q3)和25%四分位数(Q1)之间的差值。

如果数据低于Q1-k * IQR resp,则定义异常值。高于Q3 + k * IQR。

您可以根据您的领域知识选择常数k(常见选择是1.5)。

给出的数据,在大熊猫的过滤器看起来是这样的:

iqr_filter = pd.DataFrame(df["count"].quantile([0.25, 0.75])).T 
iqr_filter["iqr"] = iqr_filter[0.75]-iqr_filter[0.25] 
iqr_filter["lo"] = iqr_filter[0.25] - 1.5*iqr_filter["iqr"] 
iqr_filter["up"] = iqr_filter[0.75] + 1.5*iqr_filter["iqr"] 
df_filtered = df.loc[(df["count"] > iqr_filter["lo"][0]) & (df["count"] < iqr_filter["up"][0]), :] 
+0

对于少数样品来说,这可能会工作得更好,我发现这篇文章很有趣 https://www.dataz.io/display/Public/2013/03/20/Describing+Data%3A+为什么+ +中位数和IQR + + +是经常+好+比+意味着+和+标准+偏差 –