क्या एक सूची से आउटलेर्स को अस्वीकार करने के लिए एक सुस्पष्ट बिलिन है


100

क्या निम्न की तरह कुछ करने के लिए एक सुपीरियर बिल्डिन है? यही है, एक सूची ले लो dऔर filtered_dमें अंक के कुछ ग्रहण किए गए वितरण के आधार पर हटाए गए किसी भी बाहरी तत्वों के साथ एक सूची लौटाएं d

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मैंने यहां उपयोग किया है)।


संबंधित: scipy.stats स्पष्ट बाहरी लोगों की पहचान और मुखौटा कर सकता है? , हालांकि यह सवाल अधिक जटिल परिस्थितियों से निपटने के लिए लगता है। आपके द्वारा वर्णित सरल कार्य के लिए, एक बाहरी पैकेज ओवरकिल लगता है।
स्वेन मार्नाच

मैं सोच रहा था कि मुख्य सुकुमार पुस्तकालय में बिल्डरों की संख्या को देखते हुए यह अजीब था कि ऐसा करने के लिए कुछ भी नहीं था। यह कच्चे, शोर डेटा के साथ करने के लिए काफी आम बात की तरह लगता है।
ऐरन

जवाबों:


103

यह विधि आपके लिए लगभग समान है, बस अधिक संख्या में (केवल संख्यात्मक सरणियों पर भी काम कर रही है):

def reject_outliers(data, m=2):
    return data[abs(data - np.mean(data)) < m * np.std(data)]

3
यदि विधि mपर्याप्त रूप से बड़ी है (उदाहरण के लिए m=6), तो यह विधि काफी अच्छी है , लेकिन इस तरह के छोटे मूल्यों के mलिए इसका मतलब यह है कि विचरण मजबूत संवाहक नहीं है।
बेंजामिन बैनियर

30
हालांकि यह वास्तव में विधि के बारे में कोई शिकायत नहीं है, लेकिन एक 'बाहरी' की अस्पष्ट धारणा के बारे में एक शिकायत है
ईल्को हुगेंडोर्नो

आप एक मीटर का चयन कैसे करते हैं?
जॉन ktejik

1
मुझे यह काम करने के लिए नहीं मिला है। केवल पूर्णांक अदिश सरणियों एक अदिश सूचकांक में बदला जा सकता है या यह सिर्फ मेरा कार्यक्रम जमा: लेखन त्रुटि - मैं एक त्रुटि वापसी डेटा [<मीटर * np.std (डेटा) पेट (np.mean (डेटा) डेटा)] बार आ रही है
जॉन ktejik

@johnktejik data arg को एक सुस्पष्ट सरणी होना चाहिए।
सेंडर वैन लीउवेन

181

जब आउटलेर्स के साथ काम करना महत्वपूर्ण होता है, तो अनुमान लगाने वालों को यथासंभव मजबूत बनाने की कोशिश करनी चाहिए। वितरण का मतलब आउटलेर्स द्वारा पक्षपाती होगा लेकिन उदाहरण के लिए माध्यिका बहुत कम होगी।

यूमिरो के उत्तर पर निर्माण:

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एक संख्यात्मक सरणी होना चाहिए।


5
itl.nist.gov/div898/handbook/eda/section3/eda35h.htm यह मूल रूप से संशोधित Z- स्कोर यहाँ संदर्भित है, लेकिन एक अलग सीमा के साथ। यदि मेरा गणित सही है, तो वे मी की सिफारिश करते हैं 3.5 / .6745 ~= 5.189(वे s.6745 से गुणा करते हैं और m3.5 की एक निर्दिष्ट करते हैं ... भी लेते हैं abs(s))। किसी को भी एम की पसंद की व्याख्या कर सकते हैं? या यह कुछ ऐसा है जिसे आप अपने विशेष डेटासेट से पहचानेंगे?
चार्ली जी

2
@BenjaminBannier: क्या आप m"शुद्धता और दक्षता के परस्पर क्रिया" जैसे भुलक्कड़ बयानों के बजाय एक मूल्य चुनने के लिए कुछ ठोस स्पष्टीकरण प्रदान कर सकते हैं ?
stackoverflowuser2010

1
@ stackoverflowuser2010: जैसा मैंने कहा, यह आपकी विशिष्ट आवश्यकताओं पर निर्भर करता है, अर्थात, हमें नमूना (झूठा सकारात्मक) होने के लिए सिग्नल को कितना साफ करना होगा, या सिग्नल को साफ रखने के लिए हम कितने सिग्नल माप सकते हैं (गलत नकारात्मक) । एक निश्चित उपयोग के मामले के लिए एक विशिष्ट उदाहरण मूल्यांकन के लिए, उदाहरण के लिए, desy.de/~blist/notes/whyeffpur.ps.gz देखें
बेंजामिन बनिएर

2
जब मैं फ़ंक्शन को फ़्लोट्स की सूची के साथ कॉल करता हूं, तो मुझे निम्न त्रुटि मिलती है:TypeError: only integer scalar arrays can be converted to a scalar index
वासिलिस

2
@Charlie, यदि आप itl.nist.gov/div898/handbook/eda/section3/eda356.htm#MAD को देखते हैं, तो आप देखेंगे कि जब सामान्य वितरण (जो वास्तव में ऐसा नहीं है, तो आपको इसकी आवश्यकता नहीं होगी) SD = 1 के साथ संशोधित z- स्कोर), आपके पास MAD ~ 0.68 है, जो स्केलिंग कारक की व्याख्या करता है। एम = 3.5 का विकल्प इसलिए तात्पर्य है कि आप 0.05% डेटा को छोड़ना चाहते हैं।
फतो 39

13

बेंजामिन बैनियर के उत्तर में पास-थ्रू पैदावार होती है जब मध्यिका से दूरी का अंतर 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)

9

बेंजामिन के निर्माण, उपयोग pandas.Series, और IQR के साथ MAD की जगह :

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इसलिए, अधिक आउटलेयर शामिल किए जाएंगे।


4

एक विकल्प मानक विचलन (गाऊसी सांख्यिकी मानकर) का एक मजबूत अनुमान लगाना है। ऑनलाइन कैलकुलेटर की तलाश में, मैं देखता हूं कि 90% प्रतिशत 1.2815 the से मेल खाती है और 95% 1.645ass ( 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

मुझे पता नहीं है कि कौन सा दृष्टिकोण अधिक प्रभावशाली / मजबूत है


3

मैं इस उत्तर में दो तरीके प्रदान करना चाहूंगा, "z स्कोर" के आधार पर समाधान और "IQR" पर आधारित समाधान।

इस उत्तर में प्रदान किया गया कोड एकल डिम numpyसरणी और मल्टीपल numpyएरे दोनों पर काम करता है ।

सबसे पहले कुछ मॉड्यूल आयात करते हैं।

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

z स्कोर आधारित विधि

यदि तीन मानक विचलन के बाहर संख्या गिरती है तो यह विधि परीक्षण करेगी। इस नियम के आधार पर, यदि मान अधिक है, तो विधि सही लौटेगी, यदि नहीं, तो गलत लौटेंगी।

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चयनकर्ता का उपयोग करें ।

आपका दिन शुभ हो।


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)

क्षमा करें, मैंने इस बात की अनदेखी की कि ऊपर पहले से ही एक IQR सुझाव है। क्या मुझे इस उत्तर को वैसे भी कम कोड के कारण छोड़ देना चाहिए या इसे हटा देना चाहिए?
। Foe

1

मैं कुछ ऐसा ही करना चाहता था, डेटा से हटाने के बजाय NaN को संख्या निर्धारित करने के अलावा, यदि आप इसे हटाते हैं तो आप लंबाई को बदलते हैं जो प्लॉटिंग को गड़बड़ कर सकता है (यानी यदि आप केवल तालिका में एक स्तंभ से आउटलेर निकाल रहे हैं , लेकिन आपको इसे अन्य स्तंभों के समान रहने की आवश्यकता है ताकि आप उन्हें एक-दूसरे के खिलाफ साजिश कर सकें)।

ऐसा करने के लिए मैंने सुन्न के मास्किंग कार्यों का उपयोग किया :

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

आप आयाम रखने के लिए उन्हें न्यूनतम और अधिकतम अनुमत मानों के लिए np.clip भी कर सकते हैं।
एंडी आर

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]

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))

(मैं इसे पृष्ठभूमि घटाव के लिए उपयोग करता हूं)

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.