126

次のようなことをするためのnumpyビルトインはありますか?つまり、リストを取得し、のポイントの想定される分布に基づいて、範囲外の要素が削除されdたリストを返します。filtered_dd

import numpy as np

def reject_outliers(data):
    m = 2
    u = np.mean(data)
    s = np.std(data)
    filtered = [e for e in data if (u - 2 * s < e < u + 2 * s)]
    return filtered

>>> d = [2,4,5,1,6,5,40]
>>> filtered_d = reject_outliers(d)
>>> print filtered_d
[2,4,5,1,6,5]

関数がさまざまな分布(ポアソン、ガウスなど)およびそれらの分布内のさまざまな外れ値しきい値(mここで使用したように)を許可する可能性があるため、「のようなもの」と言います。

4

14 に答える 14

211

外れ値を処理するときに重要なことは、可能な限り堅牢な推定量を使用するようにする必要があるということです。分布の平均は外れ値によってバイアスされますが、たとえば中央値ははるかに小さくなります。

eumiroの答えに基づいて:

def reject_outliers(data, m = 2.):
    d = np.abs(data - np.median(data))
    mdev = np.median(d)
    s = d/mdev if mdev else 0.
    return data[s<m]

ここでは、平均をより堅牢な中央値に置き換え、標準偏差を中央値までの絶対距離の中央値に置き換えました。次に、距離を(再び)中央値でスケーリングしmて、妥当な相対スケールにしました。

data[s<m]構文が機能するにdataは、numpy配列である必要があることに注意してください。

于 2013-05-15T09:58:26.050 に答える
138

この方法はあなたの方法とほとんど同じですが、より多くのnumpyst(numpy配列のみで機能します):

def reject_outliers(data, m=2):
    return data[abs(data - np.mean(data)) < m * np.std(data)]
于 2012-07-27T11:22:30.733 に答える
18

ベンジャミンバニエの答えは、中央値からの距離の中央値が0のときにパススルーを生成するため、この変更されたバージョンは、以下の例に示すような場合に少し役立つことがわかりました。

def reject_outliers_2(data, m=2.):
    d = np.abs(data - np.median(data))
    mdev = np.median(d)
    s = d / (mdev if mdev else 1.)
    return data[s < m]

例:

data_points = np.array([10, 10, 10, 17, 10, 10])
print(reject_outliers(data_points))
print(reject_outliers_2(data_points))

与える:

[[10, 10, 10, 17, 10, 10]]  # 17 is not filtered
[10, 10, 10, 10, 10]  # 17 is filtered (it's distance, 7, is greater than m)
于 2017-07-30T11:10:24.607 に答える
14

ベンジャミンの上に構築し、を使用し、 MADをIQRpandas.Seriesに置き換えます:

def reject_outliers(sr, iq_range=0.5):
    pcnt = (1 - iq_range) / 2
    qlow, median, qhigh = sr.dropna().quantile([pcnt, 0.50, 1-pcnt])
    iqr = qhigh - qlow
    return sr[ (sr - median).abs() <= iqr]

たとえば、を設定iq_range=0.6すると、四分位範囲のパーセンタイルは次のようになります。0.20 <--> 0.80したがって、より多くの外れ値が含まれます。

于 2016-09-10T10:05:48.787 に答える
5

別の方法は、標準偏差のロバスト推定を行うことです(ガウス統計を想定)。オンライン計算機を調べると、90%のパーセンタイルが1.2815σに対応し、95%が1.645σであることがわかります(http://vassarstats.net/tabs.html?#z

簡単な例として:

import numpy as np

# Create some random numbers
x = np.random.normal(5, 2, 1000)

# Calculate the statistics
print("Mean= ", np.mean(x))
print("Median= ", np.median(x))
print("Max/Min=", x.max(), " ", x.min())
print("StdDev=", np.std(x))
print("90th Percentile", np.percentile(x, 90))

# Add a few large points
x[10] += 1000
x[20] += 2000
x[30] += 1500

# Recalculate the statistics
print()
print("Mean= ", np.mean(x))
print("Median= ", np.median(x))
print("Max/Min=", x.max(), " ", x.min())
print("StdDev=", np.std(x))
print("90th Percentile", np.percentile(x, 90))

# Measure the percentile intervals and then estimate Standard Deviation of the distribution, both from median to the 90th percentile and from the 10th to 90th percentile
p90 = np.percentile(x, 90)
p10 = np.percentile(x, 10)
p50 = np.median(x)
# p50 to p90 is 1.2815 sigma
rSig = (p90-p50)/1.2815
print("Robust Sigma=", rSig)

rSig = (p90-p10)/(2*1.2815)
print("Robust Sigma=", rSig)

私が得る出力は次のとおりです。

Mean=  4.99760520022
Median=  4.95395274981
Max/Min= 11.1226494654   -2.15388472011
Sigma= 1.976629928
90th Percentile 7.52065379649

Mean=  9.64760520022
Median=  4.95667658782
Max/Min= 2205.43861943   -2.15388472011
Sigma= 88.6263902244
90th Percentile 7.60646688694

Robust Sigma= 2.06772555531
Robust Sigma= 1.99878292462

これは期待値2に近いです。

5標準偏差より上/下のポイントを削除する場合(1000ポイントの場合、1つの値> 3標準偏差が予想されます):

y = x[abs(x - p50) < rSig*5]

# Print the statistics again
print("Mean= ", np.mean(y))
print("Median= ", np.median(y))
print("Max/Min=", y.max(), " ", y.min())
print("StdDev=", np.std(y))

これは次のようになります。

Mean=  4.99755359935
Median=  4.95213030447
Max/Min= 11.1226494654   -2.15388472011
StdDev= 1.97692712883

どちらのアプローチがより効率的/堅牢であるかわかりません

于 2017-07-20T12:43:15.460 に答える
3

数値をデータから削除するのではなくNaNに設定することを除いて、同様のことをしたかったのです。削除すると、プロットを台無しにする可能性のある長さを変更するためです(つまり、テーブルの1つの列から外れ値のみを削除する場合)。 、ただし、他の列と同じままにして、互いにプロットできるようにする必要があります)。

そうするために、私はnumpyのマスキング関数を使用しました:

def reject_outliers(data, m=2):
    stdev = np.std(data)
    mean = np.mean(data)
    maskMin = mean - stdev * m
    maskMax = mean + stdev * m
    mask = np.ma.masked_outside(data, maskMin, maskMax)
    print('Masking values outside of {} and {}'.format(maskMin, maskMax))
    return mask
于 2018-06-20T19:53:51.060 に答える
3

この回答では、「zスコア」に基づく解決策と「IQR」に基づく解決策の2つの方法を提供したいと思います。

この回答で提供されているコードは、単一のdimnumpy配列と複数のnumpy配列の両方で機能します。

まず、いくつかのモジュールをインポートしましょう。

import collections
import numpy as np
import scipy.stats as stat
from scipy.stats import iqr

zスコアベースの方法

このメソッドは、数値が3つの標準偏差を超えているかどうかをテストします。このルールに基づいて、値が外れ値の場合、メソッドはtrueを返し、そうでない場合はfalseを返します。

def sd_outlier(x, axis = None, bar = 3, side = 'both'):
    assert side in ['gt', 'lt', 'both'], 'Side should be `gt`, `lt` or `both`.'

    d_z = stat.zscore(x, axis = axis)

    if side == 'gt':
        return d_z > bar
    elif side == 'lt':
        return d_z < -bar
    elif side == 'both':
        return np.abs(d_z) > bar

IQRベースの方法

このメソッドは、値が、より小さいq1 - 1.5 * iqrか大きいかをテストしますq3 + 1.5 * iqr。これは、SPSSのプロットメソッドと同様です。

def q1(x, axis = None):
    return np.percentile(x, 25, axis = axis)

def q3(x, axis = None):
    return np.percentile(x, 75, axis = axis)

def iqr_outlier(x, axis = None, bar = 1.5, side = 'both'):
    assert side in ['gt', 'lt', 'both'], 'Side should be `gt`, `lt` or `both`.'

    d_iqr = iqr(x, axis = axis)
    d_q1 = q1(x, axis = axis)
    d_q3 = q3(x, axis = axis)
    iqr_distance = np.multiply(d_iqr, bar)

    stat_shape = list(x.shape)

    if isinstance(axis, collections.Iterable):
        for single_axis in axis:
            stat_shape[single_axis] = 1
    else:
        stat_shape[axis] = 1

    if side in ['gt', 'both']:
        upper_range = d_q3 + iqr_distance
        upper_outlier = np.greater(x - upper_range.reshape(stat_shape), 0)
    if side in ['lt', 'both']:
        lower_range = d_q1 - iqr_distance
        lower_outlier = np.less(x - lower_range.reshape(stat_shape), 0)

    if side == 'gt':
        return upper_outlier
    if side == 'lt':
        return lower_outlier
    if side == 'both':
        return np.logical_or(upper_outlier, lower_outlier)

最後に、外れ値を除外する場合は、numpyセレクターを使用します。

良い1日を。

于 2018-09-20T02:48:17.987 に答える
3

巨大な外れ値が原因で標準偏差が非常に大きくなると、上記のすべての方法が失敗することを考慮してください。

平均計算は失敗するため、中央値を計算する必要があります。ただし、平均は「stdDvなどのエラーが発生しやすい」ためです。

アルゴリズムを繰り返し適用するか、四分位範囲を使用してフィルタリングすることができます:(ここで「係数」は*シグマ範囲に関連しますが、データがガウス分布に従う場合のみ)

import numpy as np

def sortoutOutliers(dataIn,factor):
    quant3, quant1 = np.percentile(dataIn, [75 ,25])
    iqr = quant3 - quant1
    iqrSigma = iqr/1.34896
    medData = np.median(dataIn)
    dataOut = [ x for x in dataIn if ( (x > medData - factor* iqrSigma) and (x < medData + factor* iqrSigma) ) ] 
    return(dataOut)
于 2019-09-09T16:10:20.413 に答える
1

非常に多くの回答がありますが、作成者や他のユーザーにも役立つ新しい回答を追加しています。

ハンペルフィルターを使用できます。ただし、を使用する必要がありますSeries

ハンペルフィルターは外れ値のインデックスを返します。次に、それらをから削除してから、Seriesに戻すことができListます。

ハンペルフィルターを使用するには、次のコマンドでパッケージを簡単にインストールできますpip

pip install hampel

使用法:

# Imports
from hampel import hampel
import pandas as pd

list_d = [2, 4, 5, 1, 6, 5, 40]

# List to Series
time_series = pd.Series(list_d)

# Outlier detection with Hampel filter
# Returns the Outlier indices
outlier_indices = hampel(ts = time_series, window_size = 3)

# Drop Outliers indices from Series
filtered_d = time_series.drop(outlier_indices)

filtered_d.values.tolist()

print(f'filtered_d: {filtered_d.values.tolist()}')

そして、出力は次のようになります。

Filtered_d:[2、4、5、1、6、5]

ここで、tsはパンダSeriesオブジェクトでありwindow_size、は合計ウィンドウサイズはとして計算され2 * window_size + 1ます。

このシリーズwindow_sizeでは、値を設定しました3

Seriesを使用することのすばらしい点は、グラフィックを生成できることです。

# Imports
import matplotlib.pyplot as plt

plt.style.use('seaborn-darkgrid')

# Plot Original Series
time_series.plot(style = 'k-')
plt.title('Original Series')
plt.show()
    
# Plot Cleaned Series
filtered_d.plot(style = 'k-')
plt.title('Cleaned Series (Without detected Outliers)')
plt.show()

そして、出力は次のようになります。

ここに画像の説明を入力してください ここに画像の説明を入力してください

ハンペルフィルターの詳細については、次の読み方をお勧めします。

于 2021-10-27T20:10:23.453 に答える
0

外れ値のインデックス位置を取得したい場合は、idx_listそれを返します。

def reject_outliers(data, m = 2.):
        d = np.abs(data - np.median(data))
        mdev = np.median(d)
        s = d/mdev if mdev else 0.
        data_range = np.arange(len(data))
        idx_list = data_range[s>=m]
        return data[s<m], idx_list

data_points = np.array([8, 10, 35, 17, 73, 77])  
print(reject_outliers(data_points))

after rejection: [ 8 10 35 17], index positions of outliers: [4 5]
于 2020-04-19T17:25:56.990 に答える
0

一連の画像(各画像には3次元があります)の場合、使用した各ピクセルの外れ値を拒否したいと思います。

mean = np.mean(imgs, axis=0)
std = np.std(imgs, axis=0)
mask = np.greater(0.5 * std + 1, np.abs(imgs - mean))
masked = np.multiply(imgs, mask)

次に、平均を計算することができます。

masked_mean = np.divide(np.sum(masked, axis=0), np.sum(mask, axis=0))

(バックグラウンド減算に使用します)

于 2020-06-30T06:31:41.473 に答える
0

ここで、外れ値を見つけて、xそれらを周囲の点(win)のウィンドウの中央値に置き換えます(Benjamin Bannierから取得して中央値偏差に答えます)

def outlier_smoother(x, m=3, win=3, plots=False):
    ''' finds outliers in x, points > m*mdev(x) [mdev:median deviation] 
    and replaces them with the median of win points around them '''
    x_corr = np.copy(x)
    d = np.abs(x - np.median(x))
    mdev = np.median(d)
    idxs_outliers = np.nonzero(d > m*mdev)[0]
    for i in idxs_outliers:
        if i-win < 0:
            x_corr[i] = np.median(np.append(x[0:i], x[i+1:i+win+1]))
        elif i+win+1 > len(x):
            x_corr[i] = np.median(np.append(x[i-win:i], x[i+1:len(x)]))
        else:
            x_corr[i] = np.median(np.append(x[i-win:i], x[i+1:i+win+1]))
    if plots:
        plt.figure('outlier_smoother', clear=True)
        plt.plot(x, label='orig.', lw=5)
        plt.plot(idxs_outliers, x[idxs_outliers], 'ro', label='outliers')                                                                                                                    
        plt.plot(x_corr, '-o', label='corrected')
        plt.legend()
    
    return x_corr

ここに画像の説明を入力してください

于 2020-12-08T13:49:48.790 に答える
0

軸に沿ったnumpy配列の外れ値をトリミングし、この軸に沿った最小値または最大値のいずれか近い方に置き換えます。しきい値はzスコアです。

def np_z_trim(x, threshold=10, axis=0):
    """ Replace outliers in numpy ndarray along axis with min or max values
    within the threshold along this axis, whichever is closer."""
    mean = np.mean(x, axis=axis, keepdims=True)
    std = np.std(x, axis=axis, keepdims=True)
    masked = np.where(np.abs(x - mean) < threshold * std, x, np.nan)
    min = np.nanmin(masked, axis=axis, keepdims=True)
    max = np.nanmax(masked, axis=axis, keepdims=True)
    repl = np.where(np.abs(x - max) < np.abs(x - min), max, min)
    return np.where(np.isnan(masked), repl, masked)
于 2021-06-29T06:15:22.007 に答える
0

私のソリューションは、境界に等しい値を維持しながら、上位パーセンタイルと下位パーセンタイルを削除します。

def remove_percentile_outliers(data, percent_to_drop=0.001):
    low, high = data.quantile([percent_to_drop / 2, 1-percent_to_drop / 2])
    return data[(data >= low )&(data <= high)]
于 2021-10-29T13:57:06.940 に答える