2017-07-21 5 views
1

私は50の異なる値と数値の列 "値"を持つことができる "グループ"という列を持つデータフレームを持っています。Zscoreによってグループごとにパンダの異常をフィルタリングする

例は次のようになります。

pd.DataFrame({'group':['a','b','c','a','a','b','a','c','c'],'value':[2,123,4,2.3,2.5,127,128,4,0.003]}) 

group value 
0 a 2.000 
1 b 123.000 
2 c 4.000 
3 a 2.300 
4 a 2.500 
5 b 127.000 
6 a 128.000 
7 c 4.000 
8 c 0.003 

Iは、例えば、ABS(zscore)> 3またはそのような何かのために、データフレームから自分のグループのために異常な値を削除したいと思います。この例では、値a、128はグループaに異常であり、値c、0.003も削除されるため削除されます。それらのグループが "b"であるため、123と127は正常です。

出力(Zスコア欄付き)のようなものでなければなりません。これを行うための効率的な方法だろう

group value 
0 a 2.0 
1 b 123.0 
2 c 4.0 
3 a 2.3 
4 a 2.5 
5 b 127.0 
6 c 4.0 

何?

ありがとうございます!

+0

?あなたの希望する出力の具体的な証拠を提供してください。 –

+0

各グループの値としてzscoreを指定し、zscoreがあるしきい値を超えているレコードをフィルタリングします。 Tx。 – user3635284

+0

zスコアには仮説検定が必要です。あなたの帰無仮説は何ですか? – hausdork

答えて

2

特定のグループでグループ化されたZスコアの列、作成:DFがしきい値を所与

df['z_score'] = df.groupby('group')['value'].apply(lambda x: (x - x.mean())/x.std()) 

フィルタ:これは、各グループ内の絶対Zスコアである

df[abs(df['z_score']) > 3] 
0

df.groupby('group').value.transform(lambda x: (x - x.mean())/x.std()).abs() 

0 0.504239 
1 0.707107 
2 0.577350 
3 0.499467 
4 0.496286 
5 0.707107 
6 1.499992 
7 0.577350 
8 1.154701 
Name: value, dtype: float64 

データセットは非常に小さく、128があなたの思っていたよりも大きな役割を果たします。 Zスコアはわずか1.5です。

他のすべての統計的モーメントに対するデータポイントのzスコアを計算することをお勧めします。

ここでそれを行う関数があります。これを行うには、少なくとも4つのポイントが必要であることに注意してください。グループの長さが4未満の場合は、グループ全体で0を返します。

def _zscore(x): 
    if len(x) > 3: 
     v = x.values 

     m = (v.sum() - v)/(v.size - 1) 

     vm = v - m[:, None] 
     np.fill_diagonal(vm, 0) 

     s = ((vm ** 2).sum(1)/(v.size - 2)) ** .5 

     return (v - m)/s 
    else: 
     return np.zeros_like(x) 

は今groupbytransform

df.groupby('group').value.transform(_zscore) 

0  -0.582866 
1  0.000000 
2  0.000000 
3  -0.576658 
4  -0.572532 
5  0.000000 
6 499.613605 
7  0.000000 
8  0.000000 
Name: value, dtype: float64 

そして、我々は128499_zscore得ることをはっきりと見ることができます。単純な仮説検定から、128がグループ内の残りのデータと同じ分布から来る可能性は非常に低いと結論付けることができます。

のように我々はそれをフィルタリングすることができます:あなたは、各グループのzscoreを計算したい

df[df.groupby('group').value.transform(_zscore) <= 3] 

    group value 
0  a 2.000 
1  b 123.000 
2  c 4.000 
3  a 2.300 
4  a 2.500 
5  b 127.000 
7  c 4.000 
8  c 0.003 
関連する問題