তালিকা থেকে আউটলিয়ারদের প্রত্যাখ্যান করার জন্য কি কোনও ন্যূনি অন্তর্নির্মিত আছে?


104

নীচের মতো কিছু করার জন্য কি কোনও নম্র অন্তর্নির্মিত আছে? এটি হল, একটি তালিকা নিন 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 স্পষ্টত outliers সনাক্ত এবং মাস্ক করতে পারেন? যদিও এই প্রশ্নটি আরও জটিল পরিস্থিতি মোকাবেলা করে। আপনার বর্ণনা করা সহজ কাজটির জন্য, বাহ্যিক প্যাকেজটি অতিরিক্ত ওভারকিল বলে মনে হচ্ছে।
সোভেন মারনাচ

আমি ভাবছিলাম যে মূল নম্পটি লাইব্রেরিতে বিল্টিনের সংখ্যা দেওয়া অবাক করা বিষয় ছিল যে এটি করার কিছুই নেই। এটি কাঁচা, গোলমাল সংক্রান্ত ডেটা করার মতো একটি সাধারণ জিনিস বলে মনে হচ্ছে।
অ্যারেন

উত্তর:


108

এই পদ্ধতিটি আপনার প্রায় একইরকম, আরও বেশি নমপিস্ট (কেবলমাত্র নমপি অ্যারেগুলিতেও কাজ করছে):

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

4
যথেষ্ট mপরিমাণে বড় (উদাহরণস্বরূপ m=6) থাকলে এই পদ্ধতিটি যথেষ্ট ভাল কাজ করে তবে এর ক্ষুদ্রতর মানগুলির জন্য mভেরিয়েন্সটি দৃ estima় অনুমানকারী নয়।
বেনজামিন ব্যানিয়ার

32
যদিও এটি পদ্ধতি সম্পর্কে আসলেই কোনও অভিযোগ নয়, তবে কোনও 'আউটলারের' সম্পর্কে অস্পষ্ট ধারণা সম্পর্কে অভিযোগ
ইয়েলকো হিগেনডোরন

4
আপনি কিভাবে একটি এম চয়ন করবেন?
জন ktejik

4
আমি এই কাজ করতে পারেন না। আমি একটি ত্রুটি রিটার্ন ডেটা পেতে চলেছি [অ্যাবস (ডেটা - এনপি.মিয়ান (ডেটা)) <এম * এনপি.এসডিডি (ডেটা)] টাইপ এরর: কেবলমাত্র পূর্ণসংখ্যাকার স্কেলার অ্যারেগুলিকে একটি স্কেলার সূচীতে রূপান্তর করা যেতে পারে বা এটি কেবল আমার প্রোগ্রামকে জমা দেয়
জন ktejik

4
@ জোহঙ্কটিজিক ডেটা আরগের একটি অদ্ভুত অ্যারে হওয়া দরকার।
স্যান্ডার ভ্যান লিউউইন

185

আউটলিয়ারদের সাথে ডিল করার সময় গুরুত্বপূর্ণ কিছু হল সম্ভাব্য হিসাবে যতটা সম্ভব শক্তিশালী হিসাবে ব্যবহার করার চেষ্টা করা উচিত। বিতরণের গড়টি বিদেশী দ্বারা পক্ষপাতদুষ্ট হবে তবে উদাহরণস্বরূপ মাঝারিটি অনেক কম হবে।

ইউরোয়ের উত্তরের ভিত্তিতে:

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অবশ্যই একটি আকাঙ্ক্ষিত অ্যারে হবে।


6
itl.nist.gov/div898/handbook/eda/section3/eda35h.htm এটি মূলত এখানে পরিবর্তিত জেড-স্কোর উল্লেখ করা হয়েছে, তবে আলাদা থ্রোসোল্ড সহ। যদি আমার গণিত সঠিক হয়, তারা একটি মিটার প্রস্তাব দেয় 3.5 / .6745 ~= 5.189(তারা s.6745 দ্বারা গুণ করে এবং m3.5 এর একটি নির্দিষ্ট করে ... এছাড়াও নিন abs(s))। কেউ কি এম এর পছন্দ ব্যাখ্যা করতে পারেন? অথবা এটি এমন কিছু যা আপনি নিজের নির্দিষ্ট ডেটাसेट থেকে সনাক্ত করবেন?
চার্লি জি

4
@ বেঞ্জামিনব্যানিয়েয়ার: আপনি দয়া করে m"বিশুদ্ধতা এবং দক্ষতার আন্তঃপরায়ণতা" এর মতো ফুঁকানো বক্তব্যগুলির চেয়ে মান বাছাইয়ের জন্য কিছু নল ব্যাখ্যা দিতে পারেন?
stackoverflowuser2010

4
@ স্ট্যাকওভারফ্লুউজার2010: যেমনটি আমি বলেছিলাম, এটি আপনার নির্দিষ্ট প্রয়োজনীয়তার উপর নির্ভর করে, যেমন, নমুনা (মিথ্যা ধনাত্মক) হওয়ার জন্য আমাদের কতটা পরিষ্কার দরকার, বা সংকেত পরিষ্কার রাখতে আমরা কতগুলি সংকেত পরিমাপ নিক্ষেপ করতে পারি (মিথ্যা নেতিবাচক) । নির্দিষ্ট ব্যবহারের ক্ষেত্রে সুনির্দিষ্ট উদাহরণ মূল্যায়ন হিসাবে, দেখুন desy.de/~blist/notes/Wyeffpur.ps.gz
বেনিয়ামিন ব্যানিয়ার

4
আমি ফ্লোটগুলির একটি তালিকা সহ ফাংশনটি কল করার সময় আমি নিম্নলিখিত ত্রুটিটি পেয়েছি:TypeError: only integer scalar arrays can be converted to a scalar index
ভাসিলিস

4
@ চার্লি , আপনি যদি itl.nist.gov/div898/andbook/eda/section3/eda356.htm#MAD চিত্রটি দেখেন , আপনি দেখতে পাবেন যে সাধারণ বন্টন নিয়ে কাজ করার সময় (যা বাস্তবে আপনার প্রয়োজন হবে না এসডি = 1 দিয়ে জেড-স্কোরগুলি সংশোধন করা হয়েছে), আপনার এমএডি ~ 0.68 রয়েছে, যা স্কেলিং ফ্যাক্টরটি ব্যাখ্যা করে। মি = 3.5 এর পছন্দটি এর ফলে বোঝায় যে আপনি 0.05% ডেটা বাতিল করতে চান।
ফ্যাটো 39

14

মিডিয়াম থেকে দূরত্বের মাঝারি 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)

10

বেনিয়ামিনের উপর বিল্ডিং, ব্যবহার pandas.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সুতরাং আরও বহিরাগতদের অন্তর্ভুক্ত করা হবে।


4

একটি বিকল্প হ'ল স্ট্যান্ডার্ড বিচ্যুতি (গাউসিয়ান পরিসংখ্যান অনুমান করে) এর একটি দৃ esti় অনুমান করা। অনলাইন ক্যালকুলেটরগুলি অনুসন্ধান করে, আমি দেখতে পাচ্ছি যে 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

আমার কোন ধারণা নেই যে কোন পদ্ধতিটি আরও কার্যকর / শক্তিশালী


3

আমি এই উত্তরে দুটি পদ্ধতি সরবরাহ করতে চাই, "জেড স্কোর" ভিত্তিক সমাধান এবং "আইকিউআর" ভিত্তিক সমাধান।

এই উত্তরের প্রদত্ত কোডটি একক ম্লান 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

আইকিউআর ভিত্তিক পদ্ধতি

মানটি তার চেয়ে কম q1 - 1.5 * iqrবা বেশি হলে এটি পরীক্ষা করবে q3 + 1.5 * iqrযা এসপিএসএসের প্লট পদ্ধতির অনুরূপ।

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

বিবেচনা করুন যে বিশাল আউটলিয়ারের কারণে যখন আপনার মানক বিচ্যুতি খুব বড় হয়ে যায় তখন উপরের সমস্ত পদ্ধতি ব্যর্থ হয়।

( গড় শনাক্তকরণ হিসাবে সিমালার ব্যর্থ হয় এবং এটি মিডিয়েনাকে ক্যালক্লেট করা উচিত Though যদিও, গড়টি "স্টাডিডিভি'র মতো ত্রুটির পক্ষে আরও প্রবণ" ))

আপনি পুনরাবৃত্তভাবে আপনার অ্যালগরিদম প্রয়োগ করার চেষ্টা করতে পারেন বা আপনি আন্তঃখণ্ডজ রেঞ্জটি ব্যবহার করে ফিল্টার করেন: (এখানে "ফ্যাক্টর" একটি * সিগমা রেঞ্জের সাথে সম্পর্কিত, তবে কেবল যখন আপনার ডেটা গাউসিয়ান বিতরণ অনুসরণ করে)

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)

দুঃখিত, আমি উপেক্ষা করেছি যে উপরে ইতিমধ্যে একটি আইকিউআর পরামর্শ রয়েছে। সংক্ষিপ্ত কোডের কারণে আমার কি এই উত্তরটি ছেড়ে দেওয়া উচিত বা মুছতে হবে?
কে ফয়ে

1

আমি ডেটা থেকে মুছে ফেলার পরিবর্তে নামটি এনএনে সেট করা ব্যতীত অনুরূপ কিছু করতে চেয়েছিলাম, যেহেতু আপনি এটি সরিয়ে ফেললে আপনি এমন দৈর্ঘ্য পরিবর্তন করতে পারেন যা চক্রান্ত করতে পারে (উদাহরণস্বরূপ যদি আপনি কেবল একটি টেবিলের একটি কলাম থেকে আউটলিয়ারগুলি অপসারণ করছেন) , তবে এটি অন্য কলামগুলির মতো একই থেকে যায় তাই আপনি এগুলি একে অপরের বিরুদ্ধে চক্রান্ত করতে পারেন)।

এটি করার জন্য আমি নমপির মুখোশ ফাংশন ব্যবহার করেছি :

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

আপনি এগুলিকে রাখার জন্য তাদের সর্বনিম্ন এবং সর্বাধিক অনুমোদিত মানগুলিতে এনপ্যাক করুন।
অ্যান্ডি আর

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

(আমি এটি ব্যাকগ্রাউন্ড বিয়োগের জন্য ব্যবহার করি)

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.