Méthodes pour contourner le problème des données manquantes dans l'apprentissage automatique

15

Presque toutes les bases de données que nous voulons faire des prédictions à l'aide d'algorithmes d'apprentissage automatique trouveront des valeurs manquantes pour certaines caractéristiques.

Il existe plusieurs approches pour résoudre ce problème, pour exclure les lignes qui ont des valeurs manquantes jusqu'à ce qu'elles se remplissent avec les valeurs moyennes des caractéristiques.

Je voudrais utiliser pour une approche un peu plus robuste, qui exécuterait essentiellement une régression (ou une autre méthode) où la variable dépendante (Y) serait chacune des colonnes qui ont des valeurs manquantes mais uniquement avec les lignes du tableau qui contiennent toutes les données et prédisent les valeurs manquantes avec cette méthode, complétez le tableau par le tableau et passez à la «colonne» suivante avec des valeurs manquantes et répétez la méthode jusqu'à ce que tout soit rempli.

Mais cela me donne quelques doutes.

Pourquoi un début de colonne? Je crois que celui avec les plus petites valeurs manquantes jusqu'à celui avec le plus

Y a-t-il un seuil de valeurs manquantes qui ne vaut pas la peine d'être complété? (par exemple, si cette caractéristique n'a que 10% des valeurs renseignées, ne serait-il pas plus intéressant de l'exclure)

Existe-t-il une sorte d'implémentation dans les packages traditionnels ou d'autres méthodes robustes aux manquements?

sn3fru
la source
3
Le terme artistique que vous recherchez est «imputation», dont l'imputation multiple est un choix populaire et moderne. Notez que l'exclusion des observations avec des observations manquantes ou le remplacement des observations manquantes par la moyenne peut fausser considérablement les données. Un point de départ est Gelman et al, Bayesian Data Analysis 3rd Edition, «Chapter 18: Models for Missing Data».
Sycorax dit Réintégrer Monica le
Merci pour l'astuce, je vais chercher avec ce terme et regarder le cap18. La suppression de lignes peut biaiser beaucoup le modèle (si les manquements ne sont pas aléatoires, ce qui est très probable) et le placement de la moyenne peut mettre une forte `` charge inertielle '' autour de la moyenne, également en fonction de l'exogénéité des données manquantes. Ma grande question est la meilleure approche pour gérer cela et ma suggestion serait d'exécuter des pré-régressions pour compléter les données avant la régression principale (y a-t-il des packages qui font cela ou dois-je en créer un?)
sn3fru
L'imputation multiple moderne estime un modèle pour les données manquantes et non manquantes côte à côte. Le point de vue bayésien sur les données manquantes consiste à estimer une distribution sur les données manquantes, conditionnelle aux données observées et au modèle de disparité. Les logiciels statistiques en python laissent beaucoup à désirer. Pour les données TSCS, Amelia IIdans R est un choix solide. Ou vous pouvez rouler le vôtre en utilisant stan.
Sycorax dit Réintégrer Monica le

Réponses:

9

La technique que vous décrivez est appelée imputation par régressions séquentielles ou imputation multiple par équations chaînées. La technique a été lancée par Raghunathan (2001) et mise en œuvre dans un package R fonctionnant bien appelé mice(van Buuren, 2012).

Un article de Schafer et Graham (2002) explique bien pourquoi l'imputation moyenne et la suppression par liste (ce que vous appelez l'exclusion de ligne) ne sont généralement pas de bonnes alternatives aux techniques mentionnées ci-dessus. L'imputation moyenne n'est généralement pas conditionnelle et peut donc biaiser les distributions imputées vers la moyenne observée. Cela réduira également la variance, entre autres effets indésirables sur la distribution imputée. En outre, la suppression par liste ne fonctionnera en effet que si les données manquent complètement de manière aléatoire, comme par le coup d'une pièce. Cela augmentera également l'erreur d'échantillonnage, car la taille de l'échantillon est réduite.

Les auteurs cités ci-dessus recommandent généralement de commencer par la variable présentant le moins de valeurs manquantes. De plus, la technique est généralement appliquée de manière bayésienne (c'est-à-dire une extension de votre suggestion). Les variables sont visitées plus souvent dans la procédure d'imputation, pas une seule fois. En particulier, chaque variable est complétée par des tirages de sa distribution prédictive postérieure conditionnelle, en commençant par la variable présentant le moins de valeurs manquantes. Une fois que toutes les variables d'un ensemble de données sont terminées, l'algorithme recommence à la première variable, puis réitère jusqu'à convergence. Les auteurs ont montré que cet algorithme est de Gibbs, donc il converge généralement vers la distribution multivariée correcte des variables.

Habituellement, car certaines hypothèses non vérifiables sont impliquées, en particulier les données manquantes au hasard (c'est-à-dire si les données sont observées ou non dépendent uniquement des données observées et non des valeurs non observées). Les procédures peuvent également être partiellement incompatibles, c'est pourquoi elles ont été appelées PIGS (échantillonneur Gibbs partiellement incompatible).

Dans la pratique, l'imputation multiple bayésienne est toujours un bon moyen de traiter les problèmes de données manquantes non monotones multivariées. De plus, des extensions non paramétriques telles que l'appariement moyen prédictif aident à assouplir les hypothèses de modélisation de régression.


Raghunathan, TE, Lepkowski, J., van Hoewyk, J., et Solenberger, P. (2001). Une technique multivariée pour multiplier l'imputation des valeurs manquantes à l'aide d'une séquence de modèles de régression. Techniques d'enquête, 27 (1), 85–95.

Schafer, JL et Graham, JW (2002). Données manquantes: Notre vision de l'état de l'art. Psychological Methods, 7 (2), 147–177. https://doi.org/10.1037/1082-989X.7.2.147

van Buuren, S. (2012). Imputation flexible des données manquantes. Boca Raton: CRC Press.

tomka
la source
1
excellente réponse, d'une part je suis heureux d'avoir au moins avancé la direction que je dois suivre, d'autre part je suis triste de ne pas avoir une approche géniale à laquelle je ne pensais pas. Concernant la prédiction interactive des données manquantes par la méthode bayes, comment pourrais-je reproduire quelque chose comme ça en python? Est-ce aussi une régression? et après avoir prédit toutes les données manquantes possibles, dois-je passer en revue le prédicteur afin que les nouvelles données participent également à cette prédiction? Merci beaucoup pour l'aide, je pense que cela profitera à beaucoup d'autres.
sn3fru
1
@ sn3fru Eh bien, ces questions trouvent réponse dans les références, entre autres. Je ne sais pas si une implémentation Python existe, mais sa réplication ne devrait pas être trop difficile. Je suppose qu'il faudrait étudier un peu les détails de l'algorithme. En général, tout modèle bayésien peut être utilisé pour créer plusieurs imputations, mais l' micealgorithme utilise soit une régression, soit une correspondance moyenne prédictive. Vous complétez initialement les données manquantes par des tirages à partir de la distribution observée, puis imputez séquentiellement. Une fois terminé, vous répétez, mais en utilisant les nouvelles valeurs imputées. Les nouvelles données participent, oui
Tomka
4

Je n'ai rien trouvé qui a résolu mon problème, j'ai donc écrit une fonction qui mélange des solutions à une trame de données Pandas avec des valeurs numériques manquantes (avec fancyimpute) et catégorique (avec une forêt aléatoire).

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
la source
Bien, cela peut aider les autres (je ne l'ai pas vérifié) - il peut également être intéressant pour vous de contacter le créateur de la Rfonction mice, Stef van Buuren. Il peut être intéressé par votre code Python et / ou vous indiquer le travail d'autres personnes à cet égard. stefvanbuuren.nl
tomka
Je ne sais pas s'ils seraient intéressés par quelque chose d'aussi simple, je partage juste ici car cela peut aider d'autres personnes ayant besoin de résoudre les manquants dans une trame de données Pandas.
sn3fru
Eh bien, ils peuvent être intéressés à l'implémenter en Python en général et ils peuvent savoir si quelqu'un l'a déjà fait. J'ai déjà contacté Stef et il est très réactif et serviable. S'il existe une implémentation Python, il peut également être utile de la partager ici sous ce fil. Voir par exemple pypi.python.org/pypi/fancyimpute/0.0.4
tomka