Methoden, um das Problem fehlender Daten beim maschinellen Lernen zu umgehen

15

Nahezu jede Datenbank, die wir mithilfe von Algorithmen für maschinelles Lernen vorhersagen möchten, findet für einige der Merkmale fehlende Werte.

Es gibt verschiedene Ansätze, um dieses Problem zu lösen und Zeilen mit fehlenden Werten auszuschließen, bis sie mit den Mittelwerten der Merkmale gefüllt sind.

Ich würde gerne einen etwas robusteren Ansatz wählen, bei dem im Grunde genommen eine Regression (oder eine andere Methode) ausgeführt wird, bei der die abhängige Variable (Y) jede der Spalten ist, in denen Werte fehlen, aber nur die Zeilen der Tabelle die alle Daten enthalten und die fehlenden Werte mit dieser Methode vorhersagen, vervollständigen Sie die Tabelle tabellarisch und gehen Sie zur nächsten 'Spalte' mit fehlenden Werten über und wiederholen Sie die Methode, bis alles gefüllt ist.

Aber das gibt mir einige Zweifel.

Warum startet eine Spalte? Ich glaube, dass der mit den kleinsten fehlenden Werten bis der mit den meisten fehlt

Gibt es einen Schwellenwert für fehlende Werte, dessen Vervollständigung es nicht wert ist? (Wenn dieses Merkmal beispielsweise nur 10% der Werte enthält, wäre es nicht interessanter, es auszuschließen.)

Gibt es irgendeine Art von Implementierung in traditionellen Paketen oder anderen Methoden, die unempfindlich gegen Ausfälle sind?

sn3fru
quelle
3
Der Begriff der Kunst, den Sie suchen, ist "Imputation", von der multiple Imputation eine beliebte, moderne Wahl ist. Beachten Sie, dass das Ausschließen von Beobachtungen mit fehlenden Beobachtungen oder das Ersetzen fehlender Beobachtungen durch den Mittelwert die Daten stark beeinflussen kann. Ein Ansatzpunkt ist Gelman et al., Bayesian Data Analysis 3rd Edition, "Kapitel 18: Modelle für fehlende Daten".
Sycorax sagt Reinstate Monica
Danke für den Tipp, ich suche mit diesem Begriff und schaue mir den cap18 an. Das Löschen von Linien kann das Modell stark verzerren (wenn die Fehlzeiten nicht zufällig sind, was sehr wahrscheinlich ist), und das Platzieren des Durchschnitts kann eine starke Trägheitslast um den Mittelwert verursachen, auch abhängig von der Exogenität der Datenfehlzeiten. Meine große Frage ist der beste Ansatz, um damit umzugehen, und mein Vorschlag wäre, Vor-Regressionen
durchzuführen
Die moderne multiple Imputation schätzt ein Modell für fehlende und nicht fehlende Daten nebeneinander. Die Bayes'sche Annahme von fehlenden Daten ist die Schätzung einer Verteilung über die fehlenden Daten, abhängig von den beobachteten Daten und dem Modell für das Fehlen. Statistische Software in Python lässt zu wünschen übrig. Für TSCS-Daten ist Amelia IIR eine gute Wahl. Oder du würfelst deine eigenen mit stan.
Sycorax sagt Reinstate Monica

Antworten:

9

Die von Ihnen beschriebene Technik wird als Imputation durch sequentielle Regressionen oder multiple Imputation durch verkettete Gleichungen bezeichnet. Die Technik wurde von Raghunathan (2001) entwickelt und in ein gut funktionierendes R-Paket namens mice(van Buuren, 2012) implementiert .

Ein Aufsatz von Schafer und Graham (2002) erklärt gut, warum mittlere Imputation und listenweises Löschen (was Sie als Zeilenausschluss bezeichnen) normalerweise keine gute Alternative zu den oben genannten Techniken sind. Grundsätzlich ist die mittlere Imputation nicht bedingt und kann daher die unterstellten Verteilungen auf den beobachteten Mittelwert ausrichten. Es wird auch die Varianz verringern, neben anderen unerwünschten Auswirkungen auf die unterstellte Verteilung. Darüber hinaus funktioniert das listenweise Löschen in der Tat nur, wenn die Daten wie durch einen Münzwurf völlig zufällig fehlen. Außerdem erhöht sich der Stichprobenfehler, da die Stichprobengröße verringert wird.

Die oben genannten Autoren empfehlen in der Regel, mit der Variablen mit den am wenigsten fehlenden Werten zu beginnen. Außerdem wird die Technik normalerweise auf Bayes'sche Weise angewendet (dh als Erweiterung Ihres Vorschlags). Variablen werden im Imputationsverfahren häufiger besucht, nicht nur einmal. Insbesondere wird jede Variable durch Ziehen aus ihrer bedingten posterioren Vorhersageverteilung vervollständigt, beginnend mit der Variablen mit den am wenigsten fehlenden Werten. Sobald alle Variablen in einem Datensatz vervollständigt wurden, beginnt der Algorithmus erneut bei der ersten Variablen und wiederholt sich dann bis zur Konvergenz. Die Autoren haben gezeigt, dass es sich bei diesem Algorithmus um Gibbs handelt, weshalb er normalerweise zur korrekten multivariaten Verteilung der Variablen konvergiert.

In der Regel, weil einige nicht testbare Annahmen vorliegen, insbesondere das Fehlen zufälliger Daten (dh ob Daten beobachtet werden oder nicht, hängt nur von den beobachteten Daten und nicht von den nicht beobachteten Werten ab). Die Prozeduren können auch teilweise inkompatibel sein, weshalb sie als PIGS (teilweise inkompatibler Gibbs-Sampler) bezeichnet wurden.

In der Praxis ist die Bayes'sche multiple Imputation immer noch ein guter Weg, um mit multivariaten, nicht monotonen Problemen mit fehlenden Daten umzugehen. Nichtparametrische Erweiterungen, wie z. B. Predictive Mean Matching, tragen zur Lockerung der Annahmen zur Regressionsmodellierung bei.


TE Raghunathan, J. Lepkowski, J. van Hoewyk & P. ​​Solenberger (2001). Eine multivariate Technik zur Multiplikation der Eingabe fehlender Werte mithilfe einer Folge von Regressionsmodellen. Survey Methodology, 27 (1), 85–95.

Schafer, JL & Graham, JW (2002). Fehlende Daten: Unser Blick auf den Stand der Technik. Psychological Methods, 7 (2), 147–177. https://doi.org/10.1037/1082-989X.7.2.147

van Buuren, S. (2012). Flexible Anrechnung fehlender Daten. Boca Raton: CRC Press.

Tomka
quelle
1
Hervorragende Resonanz. Einerseits bin ich froh, zumindest die Richtung vorangebracht zu haben, der ich folgen muss. Andererseits bin ich traurig, keinen genialen Ansatz zu haben, den ich nicht gedacht habe. Wie könnte ich bei der interaktiven Vorhersage fehlender Daten mit der Bayes-Methode so etwas in Python reproduzieren? Ist es auch eine Regression? und nachdem ich alle möglichen fehlenden Daten vorhergesagt habe, sollte ich den Prädiktor durchgehen, damit die neuen Daten auch an dieser Vorhersage teilnehmen? Vielen Dank für die Hilfe, ich glaube, es wird vielen anderen zugute kommen.
sn3fru
1
@ sn3fru Nun, diese Fragen werden unter anderem in den Referenzen beantwortet. Mir ist nicht bekannt, ob eine Python-Implementierung vorhanden ist, aber die Replikation sollte nicht allzu schwierig sein. Ich nehme an, es würde erfordern, die Details des Algorithmus ein wenig zu studieren. Im Allgemeinen kann ein beliebiges Bayes'sches Modell verwendet werden, um mehrere Eingaben zu erstellen. Der miceAlgorithmus verwendet jedoch entweder Regression oder prädiktiven Mittelwertabgleich. Sie vervollständigen die fehlenden Daten zunächst durch Ziehungen aus der beobachteten Verteilung und setzen sie dann nacheinander um. Sobald Sie fertig sind, wiederholen Sie dies, verwenden jedoch die neu eingegebenen Werte. Die neuen Daten nehmen teil, ja
Tomka
4

Ich habe nichts gefunden, was mein Problem gelöst hätte. Deshalb habe ich eine Funktion geschrieben, die einige Lösungen für einen Pandas-Datenrahmen mit fehlenden numerischen Werten (mit ausgefallenen Impulsen) und kategorialen Werten (mit zufälligen Gesamtstrukturen) mischt.

import pandas as pd
import numpy as np
from sklearn.ensemble import RandomForestClassifier
import fancyimpute as fi

def separe_numeric_categoric(df):
    numerics = ['int16', 'int32', 'int64', 'float16', 'float32', 'float64']
    df_n = df.select_dtypes(include=numerics)
    df_c = df.select_dtypes(exclude=numerics)
    print(f'The DF have {len(list(df_n))} numerical features and {len(list(df_c))} categorical fets')
    return df_n, df_c


def find_missing(df):
    total = df.isnull().sum().sort_values(ascending=False)
    percent = (df.isnull().sum()/df.isnull().count()).sort_values(ascending=False)
    filter(lambda x: x>=minimum, percent)
    return percent


def count_missing(df):
    missing = find_missing(df)
    total_columns_with_missing = 0
    for i in (missing):
        if i>0:
            total_columns_with_missing += 1
    return total_columns_with_missing


def remove_missing_data(df,minimum=.1):
    percent = find_missing(df)
    number = len(list(filter(lambda x: x>=(1.0-minimum), percent)))
    names = list(percent.keys()[:number])
    df = df.drop(names, 1, errors='ignore')
    print(f'{number} columns exclude because haven`t minimium data.')
    return df


def one_hot(df, cols):
    for each in cols:
        dummies = pd.get_dummies(df[each], prefix=each, drop_first=False)
        df = pd.concat([df, dummies], axis=1)
    df = df.drop(cols, axis=1)
    return df



def impute_missing_data(df,minimium_data=.1):
    columns_missing = count_missing(df)
    print(f'Total columns with missing values: {count_missing(df)} of a {len(list(df))} columns in df')

    # remove features without minimium size of information
    df = remove_missing_data(df,minimium_data)

    numerical_df, categorical_df = separe_numeric_categoric(df)

    # Autocomplete using MICE for numerical features.
    try:
        df_numerical_complete = fi.MICE(verbose=False).complete(numerical_df.values)
        n_missing = count_missing(df)
        print(f'{columns_missing-n_missing} numerical features imputated')

        # Complete the columns name.
        temp = pd.DataFrame(columns=numerical_df.columns, data=df_numerical_complete)

        # df temp com os dados numericos completados e os categóricos.
        df = pd.concat([temp, categorical_df], axis=1)

    except Exception as e:
        print(e)
        print('Without Missing data in numerical features')

    missing = find_missing(df)
    names = missing.keys()
    n = 0
    for i, c in enumerate(missing):
        if c > 0:
            col = names[i]
            print(f'Start the prediction of {col}')
            clf = RandomForestClassifier()
            le = LabelEncoder()
            ## inverter a ordem da predição das categóricas pode melhorar a precisao.
            categorical_train = list(categorical_df.loc[:,categorical_df.columns != col])

            temp = one_hot(df,categorical_train)
            df1 = temp[temp[col].notnull()]
            df2 = temp[temp[col].isnull()]
            df1_x = df1.loc[:, df1.columns != col]
            df2_x = df2.loc[:, df1.columns != col]

            df1_y = df1[col]
            le.fit(df1_y)
            df1_y = le.transform(df1_y)
            clf.fit(df1_x, df1_y)
            df2_yHat = clf.predict(df2_x)
            df2_yHat = le.inverse_transform(df2_yHat)
            df2_yHat = pd.DataFrame(data=df2_yHat, columns=[col])
            df1_y = le.inverse_transform(df1_y)
            df1_y = pd.DataFrame(data=df1_y,columns=[col])

            df2_x.reset_index(inplace=True)   
            result2 = pd.concat([df2_yHat, df2_x], axis=1)
            try:
                del result2['index']
            except:
                pass

            df1_x.reset_index(inplace=True)
            result1 = pd.concat([df1_y, df1_x], axis=1)
            try:
                del result1['index']
            except:
                pass

            result = pd.concat([result1, result2])
            result = result.set_index(['Id'])
            df.reset_index()            
            try:
                df.set_index(['Id'],inplace=True)
            except:
                pass
            df[col] = result[col]

            n += 1

    print(f'Number of columns categorical with missing data solved: {n}')

    return df


df = impute_missing_data(df)
sn3fru
quelle
Schön, das kann anderen helfen (ich habe es nicht überprüft) - es kann auch interessant für Sie sein, mit dem Ersteller der RFunktion mice, Stef van Buuren , Kontakt aufzunehmen . Er ist möglicherweise an Ihrem Python-Code interessiert und / oder weist Sie auf die diesbezügliche Arbeit anderer Personen hin. stefvanbuuren.nl
tomka
Ich weiß nicht, ob sie sich für etwas so Einfaches interessieren würden. Ich teile es hier nur, da es anderen Menschen helfen kann, die das Lösen von Fehlern in einem Pandas-Datenframe benötigen.
sn3fru
Nun, sie könnten daran interessiert sein, es allgemein in Python zu implementieren, und sie könnten wissen, ob jemand es bereits getan hat. Ich habe Stef schon einmal kontaktiert und er ist sehr aufmerksam und hilfsbereit. Wenn es eine Python-Implementierung gibt, kann es auch nützlich sein, sie hier unter diesem Thread zu teilen. Siehe z. B. pypi.python.org/pypi/fancyimpute/0.0.4
tomka