2016-10-10 57 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 + + +是經常+好+比+意味着+和+標準+偏差 –