Phát hiện và loại trừ các ngoại lệ trong khung dữ liệu Pandas


197

Tôi có một khung dữ liệu gấu trúc với vài cột.

Bây giờ tôi biết rằng các hàng nhất định là các ngoại lệ dựa trên một giá trị cột nhất định.

Ví dụ

cột 'Vol' có tất cả các giá trị xung quanh 12xxvà một giá trị là 4000(ngoại lệ).

Bây giờ tôi muốn loại trừ những hàng có Volcột như thế này.

Vì vậy, về cơ bản, tôi cần đặt một bộ lọc vào khung dữ liệu sao cho chúng ta chọn tất cả các hàng trong đó các giá trị của một cột nhất định nằm trong khoảng 3 độ lệch chuẩn so với giá trị trung bình.

Một cách thanh lịch để đạt được điều này là gì?

Câu trả lời:


213

Nếu bạn có nhiều cột trong khung dữ liệu của mình và muốn xóa tất cả các hàng có ngoại lệ trong ít nhất một cột, biểu thức sau sẽ thực hiện điều đó trong một lần chụp.

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

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

sự miêu tả:

  • Đối với mỗi cột, đầu tiên, nó tính điểm Z của từng giá trị trong cột, liên quan đến giá trị trung bình của cột và độ lệch chuẩn.
  • Sau đó, lấy điểm Z tuyệt đối vì hướng đi không quan trọng, chỉ khi nó ở dưới ngưỡng.
  • tất cả (trục = 1) đảm bảo rằng đối với mỗi hàng, tất cả các cột đều thỏa mãn ràng buộc.
  • Cuối cùng, kết quả của điều kiện này được sử dụng để lập chỉ mục khung dữ liệu.

6
Bạn có thể giải thích những gì mã này đang làm? Và có lẽ cung cấp một ý tưởng làm thế nào tôi có thể loại bỏ tất cả các hàng có ngoại lệ trong một cột được chỉ định? Sẽ hữu ích. Cảm ơn.
samthebrand

17
Đối với mỗi cột, đầu tiên, nó tính điểm Z của từng giá trị trong cột, liên quan đến giá trị trung bình của cột và độ lệch chuẩn. Sau đó, lấy điểm Z tuyệt đối vì hướng đi không quan trọng, chỉ khi nó ở dưới ngưỡng. .all (trục = 1) đảm bảo rằng đối với mỗi hàng, tất cả các cột đều thỏa mãn ràng buộc. Cuối cùng, kết quả của điều kiện này được sử dụng để lập chỉ mục khung dữ liệu.
rafaelvalle

4
Làm thế nào bạn sẽ xử lý tình huống khi có Nulls / Nans trong các cột. Làm thế nào chúng ta có thể bỏ qua chúng?
asimo

6
Làm thế nào để chúng ta đối phó với các cột str cho giải pháp này? Nếu một số cột không phải là số và chúng tôi muốn xóa các ngoại lệ dựa trên tất cả các cột số.
ssp

6
Gặp lỗi: "TypeError: loại toán hạng không được hỗ trợ cho /: 'str' và 'int'"
sak

142

Sử dụng booleanlập chỉ mục như bạn sẽ làm trongnumpy.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

Đối với một loạt nó là tương tự:

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

6
họ cũng là một DataFrame.abs()FYI, cũng vậyDataFrame.clip()
Jeff

7
Trong trường hợp của clip()Jeff, các phác thảo không bị xóa: df.SOME_DATA.clip(-3std,+3std)gán các phác thảo cho + 3std hoặc -3std
CT Zhu

1
Điều đó gần như giống nhau, @AMM
CT Zhu

1
Làm thế nào chúng ta có thể làm điều tương tự nếu khung dữ liệu gấu trúc của chúng ta có 100 cột?
DreamerP

1
Tuyệt vời, cảm ơn vì câu trả lời đó @CTZhu. @DreamerP bạn chỉ có thể áp dụng nó cho toàn bộ DataFrame với : df_new = df[np.abs(df - df.mean()) <= (3 * df.std())]. Nhưng ngược lại với việc áp dụng nó cho Sê-ri hoặc một cột, điều này sẽ thay thế các ngoại lệ bằng np.nanvà giữ hình dạng của Khung dữ liệu, do đó có thể cần phải nội suy để điền vào các giá trị còn thiếu.
Scotty1-

93

Đối với mỗi cột khung dữ liệu của bạn, bạn có thể nhận được định lượng với:

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

và sau đó lọc với:

df[df["col"] < q]

Nếu một người cần loại bỏ các ngoại lệ thấp hơn và cao hơn, hãy kết hợp điều kiện với câu lệnh AND:

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
Bài viết này đưa ra một cái nhìn tổng quan rất tốt của outlier kỹ thuật loại bỏ machinelearningmastery.com/...
user6903745

2
điều này có thể loại bỏ các ngoại lệ chỉ từ giới hạn trên .. không thấp hơn?
không chuyên nghiệp

1
@indolentdeveloper bạn đúng, chỉ cần đảo ngược bất đẳng thức để loại bỏ các ngoại lệ thấp hơn hoặc kết hợp chúng với toán tử OR.
dùng6903745

4
Ý tưởng của bình luận là cập nhật các câu trả lời;). Vì ai đó có thể bỏ lỡ điểm này.
không chuyên nghiệp

@ user6903745 VÀ câu lệnh "HOẶC"?
AB

38

Câu trả lời này tương tự như câu trả lời được cung cấp bởi @tanemaki, nhưng sử dụng lambdabiểu thức thay vì 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)]

Để lọc Khung dữ liệu trong đó chỉ có MỘT cột (ví dụ: 'B') nằm trong ba độ lệch chuẩn:

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

Xem ở đây để biết cách áp dụng điểm z này trên cơ sở cán: Điểm Z được áp dụng cho khung dữ liệu gấu trúc


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

Tôi nhận được thông báo lỗi "ValueError: Không thể chỉ số với phím đa chiều" trong dòng "df_out = df_in.loc [(df_in [col_name]> fence_low) & (df_in [col_name] <fence_high)]" Will bạn giúp đỡ
Imran Ahmad Ghazali

18

Đối với mỗi chuỗi trong khung dữ liệu, bạn có thể sử dụng betweenquantilexóa các ngoại lệ.

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

3
Ở đây bạn chỉ chọn dữ liệu trong phạm vi liên dải (IQR), nhưng hãy nhớ rằng có thể có các giá trị ngoài phạm vi này không nằm ngoài phạm vi.
BCArg

2
Tôi chọn ví dụ 0,1 và 0,9 sẽ khá an toàn. Sử dụng giữa và các lượng tử như thế này là một cú pháp đẹp.
PascalVKooten

18

Vì tôi chưa thấy câu trả lời nào liên quan đến các thuộc tính sốkhông số , nên đây là câu trả lời bổ sung.

Bạn có thể muốn bỏ các ngoại lệ chỉ trên các thuộc tính số (biến phân loại khó có thể là ngoại lệ).

Định nghĩa hàm

Tôi đã mở rộng đề xuất của @ tanemaki để xử lý dữ liệu khi có các thuộc tính không phải là số:

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)

Sử dụng

drop_numerical_outliers(df)

Thí dụ

Hãy tưởng tượng một tập dữ liệu dfvới một số giá trị về nhà ở: hẻm, đường viền đất, giá bán, ... Ví dụ: Tài liệu dữ liệu

Đầu tiên, bạn muốn trực quan hóa dữ liệu trên biểu đồ phân tán (với z-points Thresh = 3):

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

Trước - Gr Liv Area Versus Saleprice

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

Sau - Gr Liv Area Versus Saleprice


2
Giải pháp tuyệt vời! Vì reduce=Falseđã hết hạn từ pandasphiên bản 0.23.0
RK1

Thay thế result_type='reduce'cho reduce=False.
Ekaba Bisong

8

scipy.statscó các phương pháp trim1()trimboth()để cắt các ngoại lệ thành một hàng duy nhất, theo xếp hạng và tỷ lệ phần trăm được giới thiệu của các giá trị bị xóa.


1
trimbothlà dễ nhất đối với tôi.
lời giới thiệu

6

Một tùy chọn khác là chuyển đổi dữ liệu của bạn để ảnh hưởng của các ngoại lệ được giảm thiểu. Bạn có thể làm điều này bằng cách chiến thắng dữ liệu của bạn.

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

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

Dữ liệu gốc

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

Dữ liệu Winsorized


6

Nếu bạn thích chuỗi phương thức, bạn có thể lấy điều kiện boolean của mình cho tất cả các cột số như thế này:

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

Mỗi giá trị của mỗi cột sẽ được chuyển đổi True/Falsedựa trên việc có ít hơn ba độ lệch chuẩn so với giá trị trung bình hay không.


Điều này nên được le(3)kể từ khi loại bỏ các ngoại lệ. Bằng cách này bạn có được Truecho các ngoại lệ. Bên cạnh đó +1 và câu trả lời này sẽ cao hơn
Erfan

2

Bạn có thể sử dụng mặt nạ boolean:

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

đầu ra:

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

1

Vì tôi đang ở giai đoạn đầu của hành trình khoa học dữ liệu của mình, tôi đang đối xử với các ngoại lệ với mã dưới đây.

#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

Lấy phần trăm thứ 98 và thứ 2 làm giới hạn của các ngoại lệ của chúng tôi

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

một ví dụ đầy đủ với dữ liệu và 2 nhóm sau:

Nhập khẩu:

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

Ví dụ dữ liệu với 2 nhóm: G1: Nhóm 1. G2: Nhóm 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
""")

Đọc dữ liệu văn bản vào khung dữ liệu gấu trúc:

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

Xác định các ngoại lệ bằng độ lệch chuẩn

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

Xác định các giá trị dữ liệu được lọc và các ngoại lệ:

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

In kết quả:

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

Chức năng của tôi để thả ngoại lệ

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

Tôi thích clip hơn là thả. sau đây sẽ clip tại chỗ ở pecentiles thứ 2 và 98.

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

Xóa và bỏ các ngoại lệ tôi tin là sai về mặt thống kê. Nó làm cho dữ liệu khác với dữ liệu gốc. Cũng làm cho dữ liệu có hình dạng không đồng đều và do đó cách tốt nhất là giảm hoặc tránh ảnh hưởng của các ngoại lệ bằng cách chuyển đổi nhật ký dữ liệu. Điều này làm việc cho tôi:

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

3
Không thể đưa ra giả định về lý do tại sao OP muốn làm điều gì đó.
RajeshM
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.