it-swarm.com.de

Ausreißer in Pandas-Datenrahmen erkennen und ausschließen

Ich habe einen Pandas-Datenrahmen mit wenigen Spalten.

Jetzt weiß ich, dass bestimmte Zeilen Ausreißer sind, die auf einem bestimmten Spaltenwert basieren.

Zum Beispiel Spalten - 'Vol' hat alle Werte um 12xx und ein Wert ist 4000 (Ausreißer).

Jetzt möchte ich diejenigen Zeilen ausschließen, die die Spalte "Vol" wie folgt haben . Daher muss ich im Wesentlichen einen Filter für den Datenrahmen setzen, sodass wir alle Zeilen auswählen, in denen sich die Werte einer bestimmten Spalte innerhalb von 3 befinden Standardabweichungen vom Mittelwert.

Was ist ein eleganter Weg, um dies zu erreichen. 

111
AMM

Verwenden Sie die boolean-Indizierung wie in numpy.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

Für eine Serie ist es ähnlich:

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

Wenn sich in Ihrem Dataframe mehrere Spalten befinden und Sie möchten alle Zeilen entfernen, die in mindestens einer Spalte Ausreißer enthalten, führt der folgende Ausdruck dies in einer Einstellung aus.

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

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

Beschreibung:

  • Für jede Spalte berechnet sie zuerst den Z-Score jedes Werts in der Spalte Relativ zum Spaltenmittelwert und zur Standardabweichung. 
  • Dann ist der Absolutwert der Z-Bewertung, da die Richtung keine Rolle spielt, nur wenn sie unter dem Schwellenwert liegt.
  • all (Achse = 1) stellt sicher, dass für jede Zeile alle Spalten die Einschränkung von erfüllen. 
  • Das Ergebnis dieser Bedingung wird schließlich zum Indizieren des Datenrahmens verwendet.
110
tanemaki

Für jede Ihrer Dataframe-Spalten könnten Sie Folgendes erhalten:

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

und dann filtern mit:

df[df["col"] < q]
50
user6903745

Diese Antwort ist der von @tanemaki ähnlich, verwendet jedoch einen lambda-Ausdruck anstelle von 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)]

So filtern Sie den DataFrame, wobei nur eine Spalte (z. B. 'B') drei Standardabweichungen aufweist:

df[((df.B - df.B.mean()) / df.B.std()).abs() < 3]
23
Alexander
#------------------------------------------------------------------------------
# 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
10
user2708149

Für jede Serie im Datenrahmen können Sie between und quantile verwenden, um Ausreißer zu entfernen.

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

scipy.stats verfügt über die Methoden trim1() und trimboth(), um die Ausreißer in einer einzigen Zeile nach der Rangfolge und dem eingeführten Prozentsatz der entfernten Werte auszuschneiden.

6

Da ich keine Antwort gefunden habe, die sich mit numerischen und nicht numerischen Attributen befasst, ist hier eine ergänzende Antwort.

Möglicherweise möchten Sie die Ausreißer nur auf numerischen Attributen löschen (kategoriale Variablen können kaum Ausreißer sein).

Funktionsdefinition

Ich habe @ tanemakis Vorschlag erweitert, Daten zu verarbeiten, wenn auch nicht numerische Attribute vorhanden sind:

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)

Verwendung

drop_numerical_outliers(df)

Beispiel

Stellen Sie sich einen Datensatz df mit einigen Werten zu Häusern vor: Gasse, Grundstückskontur, Verkaufspreis, ... ZB Datendokumentation

Zunächst möchten Sie die Daten in einem Streudiagramm visualisieren (mit Z-Score 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)

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

After - Gr Liv Area Versus SalePrice

5
KeyMaker00

Eine andere Möglichkeit besteht darin, Ihre Daten so zu transformieren, dass die Auswirkungen von Ausreißern gemildert werden. Sie können dies tun, indem Sie Ihre Daten verwöhnen. 

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

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

 Original data

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

 Winsorized data

1
mgoldwasser

Wenn Sie die Methodenverkettung mögen, können Sie Ihre boolesche Bedingung für alle numerischen Spalten wie folgt erhalten:

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

Jeder Wert jeder Spalte wird in True/False konvertiert, je nachdem, ob der Standardabweichung weniger als drei Standardabweichungen beträgt oder nicht.

1
Ted Petrou

Meine Funktion zum Ausreißen von Ausreißern

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
luminousmen

Da ich mich in einem sehr frühen Stadium meiner Data Science-Reise befinde, behandle ich Ausreißer mit dem folgenden Code.

#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
0
Arun Gupta

Sie können eine boolesche Maske verwenden:

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

ausgabe:

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

Ermitteln Sie das 98. und 2. Perzentil als Grenzen unserer Ausreißer

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
Dheeraj

ein vollständiges Beispiel mit Daten und 2 Gruppen folgt:

Importe:

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

Datenbeispiel mit 2 Gruppen: G1: Gruppe 1. G2: Gruppe 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
""")

Textdaten in Pandas-Datenrahmen lesen:

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

Definieren Sie die Ausreißer anhand von Standardabweichungen

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

Definieren Sie gefilterte Datenwerte und Ausreißer:

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

Ergebnis ausdrucken:

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
Wagner Cipriano

Ich ziehe es vor zu schneiden anstatt zu fallen. Das folgende wird am 2. und 98. Perzentil fixiert.

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