Pandalar veri çerçevesindeki aykırı değerleri algılama ve hariç tutma


199

Birkaç sütun ile bir pandalar veri çerçevesi var.

Şimdi, belirli satırların belirli bir sütun değerine göre aykırı olduğunu biliyorum.

Örneğin

'Vol' sütunu tüm değerlere sahiptir 12xxve bir değer 4000(aykırı değer ) şeklindedir.

Şimdi böyle bir Volsütunu olan satırları hariç tutmak istiyorum.

Bu nedenle, veri çerçevesine, belirli bir sütunun değerlerinin dahil olduğu tüm satırları, örneğin ortalama 3 standart sapmayı seçtiğimiz şekilde bir filtre koymam gerekiyor.

Bunu başarmanın zarif bir yolu nedir?

Yanıtlar:


215

Veri çerçevenizde birden çok sütun varsa ve en az bir sütunda aykırı değerleri olan tüm satırları kaldırmak istiyorsanız, aşağıdaki ifade bunu tek çekimde yapar.

df = pd.DataFrame(np.random.randn(100, 3))

from scipy import stats
df[(np.abs(stats.zscore(df)) < 3).all(axis=1)]

açıklama:

  • Her sütun için, ilk önce kolon ortalaması ve standart sapmaya göre kolondaki her bir değerin Z-puanını hesaplar.
  • O zaman Z-skorunun mutlak değerini alır çünkü yön önemli değildir, sadece eşiğin altındaysa.
  • all (eksen = 1), her satır için tüm sütunun kısıtlamayı karşılamasını sağlar.
  • Son olarak, bu koşulun sonucu veri çerçevesini indekslemek için kullanılır.

6
Bu kodun ne yaptığını açıklayabilir misiniz? Ve belki bir belirtilmiş tek bir sütunda aykırı olan tüm satırları nasıl kaldırabilirim? Yardımcı olur. Teşekkürler.
samthebrand

17
Her sütun için, önce sütun ortalaması ve standart sapmaya göre sütundaki her bir değerin Z-puanını hesaplar. Sonra Z-skorunun mutlak değerini alır çünkü yön önemli değildir, sadece eşiğin altındaysa. .all (axis = 1), her satır için tüm sütunun kısıtlamayı karşılamasını sağlar. Son olarak, bu koşulun sonucu veri çerçevesini indekslemek için kullanılır.
rafaelvalle

4
Sütunlarda Boş / Nans olduğunda durumu nasıl ele alırsınız? Onları nasıl görmezden gelebiliriz?
asimo

6
bu çözüm için str sütunlarıyla nasıl başa çıkabiliriz? Bazı sütunlar sayısal değilse ve tüm sayısal sütunları temel alan aykırı değerleri kaldırmak istiyoruz.
ssp

6
Hata var: "TypeError: /: 'str' ve 'int' için desteklenmeyen işlenen tür (ler)"
sak

144

booleanDizinlemeyi, yaptığınız gibi kullanınnumpy.array

df = pd.DataFrame({'Data':np.random.normal(size=200)})
# example dataset of normally distributed data. 

df[np.abs(df.Data-df.Data.mean()) <= (3*df.Data.std())]
# keep only the ones that are within +3 to -3 standard deviations in the column 'Data'.

df[~(np.abs(df.Data-df.Data.mean()) > (3*df.Data.std()))]
# or if you prefer the other way around

Bir seri için benzer:

S = pd.Series(np.random.normal(size=200))
S[~((S-S.mean()).abs() > 3*S.std())]

6
onların da bir DataFrame.abs()FYI, ayrıcaDataFrame.clip()
Jeff

7
clip()Jeff durumunda , ana hatlar kaldırılmaz: ana hatları df.SOME_DATA.clip(-3std,+3std)+ 3std veya -3std'ye atayın
CT Zhu

1
Bu neredeyse aynı, @ AMM
CT Zhu

1
Panda veri çerçevemizin 100 sütunu varsa aynı şeyi nasıl yapabiliriz?
DreamerP

1
Harika, bu cevap için teşekkürler @ CTZhu. @DreamerP sadece ile tüm DataFrame uygulayabilirsiniz: df_new = df[np.abs(df - df.mean()) <= (3 * df.std())]. Ancak bunu bir Seri veya tek bir sütuna uygulamaktan farklı olarak, bu aykırı değerlerin yerine np.nanDataFrame yerleştirilir ve şekli korunur, bu nedenle eksik değerleri doldurmak için enterpolasyon gerekebilir.
Scotty1-

95

Veri çerçevesi sütunlarınızın her biri için aşağıdakilerle nicelik elde edebilirsiniz:

q = df["col"].quantile(0.99)

ve ardından filtreleme:

df[df["col"] < q]

Alt ve üst aykırı değerlerin kaldırılması gerekirse, durumu bir AND ifadesiyle birleştirin:

q_low = df["col"].quantile(0.01)
q_hi  = df["col"].quantile(0.99)

df_filtered = df[(df["col"] < q_hi) & (df["col"] > q_low)]

3
Bu makale Aykırı kaldırma teknikleri çok iyi bir genel bakış sağlar machinelearningmastery.com/...
user6903745

2
bu aykırı değerleri sadece üst sınırdan çıkarabilir .. alt değil mi?
indolentdeveloper

1
@indolentdeveloper haklısınız, daha düşük aykırı değerleri kaldırmak veya bir OR operatörü ile birleştirmek için eşitsizliği tersine çevirmek yeterlidir.
user6903745

4
Yorum fikri cevapları güncellemekti;). Çünkü birisi bu noktayı kaçırabilir.
indolentdeveloper

@ user6903745 AND ifadesi veya "VEYA"?
AB

38

Bu cevap @tanemaki tarafından verilene benzer, ancak lambdayerine bir ifade kullanır scipy stats.

df = pd.DataFrame(np.random.randn(100, 3), columns=list('ABC'))

df[df.apply(lambda x: np.abs(x - x.mean()) / x.std() < 3).all(axis=1)]

Yalnızca bir sütunun (örneğin 'B') üç standart sapma içinde olduğu DataFrame'e filtre uygulamak için:

df[((df.B - df.B.mean()) / df.B.std()).abs() < 3]

Bu z-puanının sürekli olarak nasıl uygulanacağını görmek için buraya bakın: Pandalar veri çerçevesine uygulanan yuvarlanan Z-puanı


22
#------------------------------------------------------------------------------
# accept a dataframe, remove outliers, return cleaned data in a new dataframe
# see http://www.itl.nist.gov/div898/handbook/prc/section1/prc16.htm
#------------------------------------------------------------------------------
def remove_outlier(df_in, col_name):
    q1 = df_in[col_name].quantile(0.25)
    q3 = df_in[col_name].quantile(0.75)
    iqr = q3-q1 #Interquartile range
    fence_low  = q1-1.5*iqr
    fence_high = q3+1.5*iqr
    df_out = df_in.loc[(df_in[col_name] > fence_low) & (df_in[col_name] < fence_high)]
    return df_out

Ben hata "ValueError: çok boyutlu anahtarla Can endeksleyemez" alıyorum satırına "df_out = df_in.loc [([COL_NAME df_in]> fence_low) & (df_in [COL_NAME] <fence_high)]" Size Will yardım
İmran Ahmed Gazali

20

Sayısal ve sayısal olmayan özellikler ile ilgili bir cevap görmediğim için , burada bir tamamlayıcı cevap var.

Aykırı değerleri yalnızca sayısal özniteliklere bırakmak isteyebilirsiniz (kategorik değişkenler aykırı olamaz).

İşlev tanımı

Sayısal olmayan özellikler de mevcut olduğunda verileri işlemek için @ tanemaki'nin önerisini genişlettim:

from scipy import stats

def drop_numerical_outliers(df, z_thresh=3):
    # Constrains will contain `True` or `False` depending on if it is a value below the threshold.
    constrains = df.select_dtypes(include=[np.number]) \
        .apply(lambda x: np.abs(stats.zscore(x)) < z_thresh, reduce=False) \
        .all(axis=1)
    # Drop (inplace) values set to be rejected
    df.drop(df.index[~constrains], inplace=True)

kullanım

drop_numerical_outliers(df)

Misal

dfEvler hakkında bazı değerleri olan bir veri kümesi düşünün : sokak, arazi konturu, satış fiyatı, ... Örn: Veri Belgeleri

İlk olarak, verileri bir dağılım grafiğinde görselleştirmek istiyorsunuz (z-skoru Thresh = 3 ile):

# Plot data before dropping those greater than z-score 3. 
# The scatterAreaVsPrice function's definition has been removed for readability's sake.
scatterAreaVsPrice(df)

Satış Öncesi - Gr Liv Bölgesi ve Satış Fiyatı

# Drop the outliers on every attributes
drop_numerical_outliers(train_df)

# Plot the result. All outliers were dropped. Note that the red points are not
# the same outliers from the first plot, but the new computed outliers based on the new data-frame.
scatterAreaVsPrice(train_df)

Satış Sonrası - Gr Liv Bölgesi ve Satış Fiyatı


2
Harika bir çözüm! Bir kafaları yukarı şöyle reduce=Falsezamandan beri kullanılmadığından pandassürüm 0.23.0
RK1

Değiştirin result_type='reduce'için reduce=False.
Ekaba Bisong

18

Veri çerçevesindeki her seri için, aykırı değerleri kaldırmak betweenve kullanmak quantileiçin kullanabilirsiniz .

x = pd.Series(np.random.normal(size=200)) # with outliers
x = x[x.between(x.quantile(.25), x.quantile(.75))] # without outliers

3
Burada yalnızca kartlararası aralık (IQR) içindeki verileri seçiyorsunuz, ancak bu aralığın dışında aykırı olmayan değerler olabileceğini unutmayın.
BCArg

2
Örneğin 0.1 ve 0.9'u seçmek oldukça güvenli olacaktır. Bunun ve arasındaki miktarları kullanmak oldukça güzel bir sözdizimidir.
PascalVKooten

8

scipy.statsyöntemlere trim1()ve trimboth()aykırı değerlerin sıralamaya ve tanıtılan kaldırılan değerlerin yüzdesine göre tek bir satırda kesilmesi vardır .


1
trimbothbenim için en kolay olanıydı.
sözler

6

Başka bir seçenek de verilerinizi, aykırı değerlerin etkisini azaltmak için dönüştürmektir. Bunu verilerinizi zayıflatarak yapabilirsiniz.

import pandas as pd
from scipy.stats import mstats
%matplotlib inline

test_data = pd.Series(range(30))
test_data.plot()

Orjinal veri

# Truncate values to the 5th and 95th percentiles
transformed_test_data = pd.Series(mstats.winsorize(test_data, limits=[0.05, 0.05])) 
transformed_test_data.plot()

Kazanılmış veri


6

Yöntem zincirlemeyi seviyorsanız, aşağıdaki gibi tüm sayısal sütunlar için boole koşulunuzu alabilirsiniz:

df.sub(df.mean()).div(df.std()).abs().lt(3)

Her bir sütunun her bir değeri, True/Falseüçten daha az standart sapmasının ortalamadan uzak olup olmamasına göre dönüştürülecektir .


Bu olmalı le(3)onun beri kaldırarak aykırı. Bu şekilde Trueaykırı değerlere ulaşırsınız. Bunun yanı sıra +1 ve bu cevap daha yüksek olmalı
Erfan

2

Boole maskesini kullanabilirsiniz:

import pandas as pd

def remove_outliers(df, q=0.05):
    upper = df.quantile(1-q)
    lower = df.quantile(q)
    mask = (df < upper) & (df > lower)
    return mask

t = pd.DataFrame({'train': [1,1,2,3,4,5,6,7,8,9,9],
                  'y': [1,0,0,1,1,0,0,1,1,1,0]})

mask = remove_outliers(t['train'], 0.1)

print(t[mask])

çıktı:

   train  y
2      2  0
3      3  1
4      4  1
5      5  0
6      6  0
7      7  1
8      8  1

1

Veri bilimi yolculuğumun çok erken bir aşamasında olduğum için aykırı değerleri aşağıdaki kodla tedavi ediyorum.

#Outlier Treatment

def outlier_detect(df):
    for i in df.describe().columns:
        Q1=df.describe().at['25%',i]
        Q3=df.describe().at['75%',i]
        IQR=Q3 - Q1
        LTV=Q1 - 1.5 * IQR
        UTV=Q3 + 1.5 * IQR
        x=np.array(df[i])
        p=[]
        for j in x:
            if j < LTV or j>UTV:
                p.append(df[i].median())
            else:
                p.append(j)
        df[i]=p
    return df

1

Aykırı değerlerin limiti olarak 98. ve 2. yüzdelik dilimi alın

upper_limit = np.percentile(X_train.logerror.values, 98) 
lower_limit = np.percentile(X_train.logerror.values, 2) # Filter the outliers from the dataframe
data[‘target’].loc[X_train[‘target’]>upper_limit] = upper_limit data[‘target’].loc[X_train[‘target’]<lower_limit] = lower_limit

0

veri ve 2 grup içeren tam bir örnek:

İthalat:

from StringIO import StringIO
import pandas as pd
#pandas config
pd.set_option('display.max_rows', 20)

2 gruplu veri örneği: G1: Grup 1. G2: Grup 2:

TESTDATA = StringIO("""G1;G2;Value
1;A;1.6
1;A;5.1
1;A;7.1
1;A;8.1

1;B;21.1
1;B;22.1
1;B;24.1
1;B;30.6

2;A;40.6
2;A;51.1
2;A;52.1
2;A;60.6

2;B;80.1
2;B;70.6
2;B;90.6
2;B;85.1
""")

Panda verilerini veri çerçevesine metin verilerini okuyun:

df = pd.read_csv(TESTDATA, sep=";")

Standart sapmaları kullanarak aykırı değerleri tanımlayın

stds = 1.0
outliers = df[['G1', 'G2', 'Value']].groupby(['G1','G2']).transform(
           lambda group: (group - group.mean()).abs().div(group.std())) > stds

Filtrelenmiş veri değerlerini ve aykırı değerleri tanımlayın:

dfv = df[outliers.Value == False]
dfo = df[outliers.Value == True]

Sonucu yazdırın:

print '\n'*5, 'All values with decimal 1 are non-outliers. In the other hand, all values with 6 in the decimal are.'
print '\nDef DATA:\n%s\n\nFiltred Values with %s stds:\n%s\n\nOutliers:\n%s' %(df, stds, dfv, dfo)

0

Aykırı değerleri bırakma işlevim

def drop_outliers(df, field_name):
    distance = 1.5 * (np.percentile(df[field_name], 75) - np.percentile(df[field_name], 25))
    df.drop(df[df[field_name] > distance + np.percentile(df[field_name], 75)].index, inplace=True)
    df.drop(df[df[field_name] < np.percentile(df[field_name], 25) - distance].index, inplace=True)

0

Bırakmak yerine kırpmayı tercih ederim. Aşağıdakiler 2. ve 98. pecentillerde yerinde klipslenecek.

df_list = list(df)
minPercentile = 0.02
maxPercentile = 0.98

for _ in range(numCols):
    df[df_list[_]] = df[df_list[_]].clip((df[df_list[_]].quantile(minPercentile)),(df[df_list[_]].quantile(maxPercentile)))

-2

Aykırı değerleri silmek ve bırakmak istatistiksel olarak yanlış olduğuna inanıyorum. Verileri orijinal verilerden farklı kılar. Ayrıca verileri eşit olmayan bir şekilde şekillendirir ve bu nedenle en iyi yol, verileri günlüğe dönüştürerek aykırı değerlerin etkisini azaltmak veya önlemektir. Bu benim için çalıştı:

np.log(data.iloc[:, :])

3
OP'nin neden bir şey yapmak istediğine dair varsayımlar yapılamıyor.
RajeshM
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.