Métodos para solucionar o problema de falta de dados no aprendizado de máquina

15

Praticamente qualquer banco de dados que desejamos fazer previsões usando algoritmos de aprendizado de máquina encontrará valores ausentes para algumas das características.

Existem várias abordagens para resolver esse problema, para excluir linhas que possuem valores ausentes até que sejam preenchidas com os valores médios das características.

Gostaria de usar para uma abordagem um pouco mais robusta, que basicamente executaria uma regressão (ou outro método) em que a variável dependente (Y) seria cada uma das colunas com valores ausentes, mas apenas com as linhas da tabela que contêm todos os dados e prevêem os valores ausentes com esse método, preencha a tabela pela tabela e vá para a próxima 'coluna' com valores ausentes e repita o método até que tudo esteja preenchido.

Mas isso me dá algumas dúvidas.

Por que qualquer coluna começa? Eu acredito que aquele com os menores valores ausentes até aquele com os mais

Existe algum limite de valores ausentes que não vale a pena tentar concluí-lo? (por exemplo, se essa característica tiver apenas 10% dos valores preenchidos, não seria mais interessante excluí-la)

Existe algum tipo de implementação em pacotes tradicionais ou outros métodos que são robustos a erros?

sn3fru
fonte
3
O termo da arte que você procura é "imputação", cuja imputação múltipla é uma escolha popular e moderna. Observe que excluir observações com observações ausentes ou substituir observações ausentes pela média pode influenciar muito os dados. Um ponto de partida é Gelman et al., Bayesian Data Analysis 3rd Edition, "Capítulo 18: Modelos para dados ausentes".
Sycorax diz Restabelecer Monica
Obrigado pela dica, vou procurar com esse termo e olhar para o cap18. Excluir linhas pode influenciar muito o modelo (se as perdas não são aleatórias, o que é muito provável) e colocar a média pode colocar uma forte 'carga inercial' em torno da média, também dependendo da exogeneidade das perdas de dados. Minha grande questão é a melhor abordagem para lidar com isso e minha sugestão seria a de executar pré-regressões para completar os dados antes da regressão principal (há quaisquer pacotes que fazem isso ou eu deveria criar um?)
sn3fru
A imputação múltipla moderna estima um modelo para dados ausentes e não ausentes lado a lado. A abordagem bayesiana dos dados ausentes é estimar uma distribuição sobre os dados ausentes, condicional aos dados observados e ao modelo de falta. O software estatístico em python deixa muito a desejar. Para dados TSCS, Amelia IIem R é uma escolha sólida. Ou você pode usar o seu próprio stan.
Sycorax diz Restabelecer Monica

Respostas:

9

A técnica que você descreve é ​​chamada imputação por regressões seqüenciais ou imputação múltipla por equações encadeadas. A técnica foi pioneira em Raghunathan (2001) e implementada em um pacote R que funcionava bem mice(van Buuren, 2012).

Um artigo de Schafer e Graham (2002) explica bem por que a imputação média e a exclusão listwise (o que você chama de exclusão de linha) geralmente não são boas alternativas para as técnicas mencionadas acima. Principalmente a imputação média não é condicional e, portanto, pode influenciar as distribuições imputadas em relação à média observada. Também reduzirá a variação, entre outros impactos indesejáveis ​​na distribuição imputada. Além disso, a exclusão listwise, de fato, só funcionará se os dados estiverem faltando completamente ao acaso, como o toque de uma moeda. Além disso, aumentará o erro de amostragem, pois o tamanho da amostra é reduzido.

Os autores citados acima geralmente recomendam começar com a variável que apresenta os valores menos ausentes. Além disso, a técnica é geralmente aplicada de maneira bayesiana (ou seja, uma extensão da sua sugestão). As variáveis ​​são visitadas com mais frequência no procedimento de imputação, não apenas uma vez. Em particular, cada variável é completada com base em sua distribuição preditiva posterior condicional, começando com a variável que apresenta menos valores ausentes. Depois que todas as variáveis ​​em um conjunto de dados são concluídas, o algoritmo inicia novamente na primeira variável e depois reitera até a convergência. Os autores mostraram que esse algoritmo é Gibbs, portanto, geralmente converge para a distribuição multivariada correta das variáveis.

Geralmente, porque existem algumas suposições não testáveis ​​envolvidas, em particular faltando dados aleatórios (ou seja, se os dados são observados ou não, depende apenas dos dados observados e não dos valores não observados). Os procedimentos também podem ser parcialmente incompatíveis, motivo pelo qual foram chamados de PIGS (amostrador de Gibbs parcialmente incompatível).

Na prática, a imputação múltipla bayesiana ainda é uma boa maneira de lidar com problemas de dados ausentes não monótonos e multivariados. Além disso, extensões não paramétricas, como correspondência preditiva média, ajudam a relaxar as suposições da modelagem de regressão.


Raghunathan, TE, Lepkowski, J., van Hoewyk, J. e Solenberger, P. (2001). Uma técnica multivariada para multiplicar valores ausentes de imputação usando uma sequência de modelos de regressão. Survey Methodology, 27 (1), 85–95.

Schafer, JL e Graham, JW (2002). Dados ausentes: nossa visão do estado da arte. Psychological Methods, 7 (2), 147-177. https://doi.org/10.1037/1082-989X.7.2.147

van Buuren, S. (2012). Imputação flexível de dados ausentes. Boca Raton: CRC Press.

tomka
fonte
1
excelente resposta, por um lado, fico feliz por ter avançado pelo menos na direção que devo seguir; por outro, fico triste por não ter uma abordagem genial que não pensava. Na previsão interativa de dados ausentes pelo método bayes, como eu poderia reproduzir algo assim em python? Também é uma regressão? e depois de prever todos os possíveis dados ausentes, devo revisar o preditor para que os novos dados também participem dessa previsão? Muito obrigado pela ajuda, acredito que irá beneficiar muitos outros.
sn3fru
1
@ sn3fru Bem, essas perguntas são respondidas nas referências, entre outros lugares. Não sei se existe uma implementação em Python, mas replicá-la não deve ser muito difícil. Suponho que seria necessário estudar um pouco os detalhes do algoritmo. Em geral, qualquer modelo bayesiano pode ser usado para criar múltiplas imputações, mas o micealgoritmo usa regressão ou correspondência preditiva média. Inicialmente, você preenche os dados ausentes com base na distribuição observada e, em seguida, imputa sequencialmente. Depois de concluído, repita, mas usando os valores recém-imputados. Os novos dados participam, sim
tomka 18/09/17
4

Como não encontrei nada que resolvesse meu problema, escrevi uma função que mistura algumas soluções para um dataframe do Pandas com valores numéricos ausentes (com valor fantasia) e categórico (com uma floresta aleatória).

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
fonte
Bom, isso pode ajudar outras pessoas (não verifiquei) - também pode ser interessante entrar em contato com o criador da Rfunção mice, Stef van Buuren. Ele pode estar interessado no seu código Python e / ou apontar o trabalho de outras pessoas a esse respeito. stefvanbuuren.nl
tomka
Eu não sei se eles estariam interessados ​​em algo tão simples, estou apenas compartilhando aqui, pois isso pode ajudar outras pessoas que precisam resolver a falta de um dataframe do Pandas.
sn3fru
Bem, eles podem estar interessados ​​em implementá-lo no Python em geral e podem saber se alguém já o fez. Entrei em contato com Stef antes e ele é muito responsivo e útil. Se houver uma implementação em Python, também pode ser útil compartilhá-la aqui neste tópico. Veja, por exemplo, pypi.python.org/pypi/fancyimpute/0.0.4
tomka