Métodos para solucionar el problema de la falta de datos en el aprendizaje automático

15

Prácticamente cualquier base de datos que queremos hacer predicciones utilizando algoritmos de aprendizaje automático encontrará valores faltantes para algunas de las características.

Existen varios enfoques para abordar este problema, para excluir líneas que tienen valores faltantes hasta que se llenen con los valores medios de las características.

Me gustaría utilizar un enfoque algo más robusto, que básicamente ejecutaría una regresión (u otro método) donde la variable dependiente (Y) sería cada una de las columnas que tienen valores faltantes pero solo con las filas de la tabla que contienen todos los datos y predicen los valores faltantes con este método, complete la tabla junto a la tabla y avance a la siguiente 'columna' con valores faltantes y repita el método hasta que todo esté lleno.

Pero eso me da algunas dudas.

¿Por qué comienza cualquier columna? Creo que el que tiene los valores perdidos más pequeños hasta el que tiene más

¿Hay algún umbral de valores perdidos que no valga la pena intentar completar? (por ejemplo, si esta característica solo tiene el 10% de los valores rellenados, ¿no sería más interesante excluirla?)

¿Existe algún tipo de implementación en paquetes tradicionales u otros métodos que sean robustos para las faltas?

sn3fru
fuente
3
El término de arte que está buscando es "imputación", de los cuales la imputación múltiple es una opción popular y moderna. Tenga en cuenta que excluir las observaciones con observaciones faltantes o reemplazar las observaciones faltantes con la media puede sesgar los datos. Un lugar para comenzar es Gelman et al, Bayesian Data Analysis 3rd Edition, "Capítulo 18: Modelos para datos faltantes".
Sycorax dice Reinstate Monica
Gracias por el consejo, buscaré con ese término y miraré el cap18. Eliminar líneas puede sesgar mucho el modelo (si las faltas no son aleatorias, lo cual es muy probable) y colocar el promedio puede colocar una fuerte 'carga de inercia' alrededor de la media, también dependiendo de la exogeneidad de las faltas de datos. Mi gran pregunta es el mejor enfoque para manejar esto y mi sugerencia sería ejecutar pre-regresiones para completar los datos antes de la regresión principal (¿hay algún paquete que haga esto o debería crear uno?)
sn3fru
La imputación múltiple moderna estima un modelo de datos faltantes y no faltantes uno al lado del otro. La idea bayesiana de los datos faltantes es estimar una distribución sobre los datos faltantes, condicional a los datos observados y al modelo de falta. El software estadístico en python deja mucho que desear. Para datos TSCS, Amelia IIen R es una opción sólida. O podrías rodar tu propio uso stan.
Sycorax dice Reinstate Monica

Respuestas:

9

La técnica que describe se llama imputación por regresiones secuenciales o imputación múltiple por ecuaciones encadenadas. La técnica fue pionera por Raghunathan (2001) y se implementó en un paquete R que funciona bien llamado mice(van Buuren, 2012).

Un artículo de Schafer y Graham (2002) explica bien por qué la imputación mala y la eliminación por listas (lo que llama exclusión de línea) generalmente no son buenas alternativas a las técnicas mencionadas anteriormente. Principalmente, la imputación media no es condicional y, por lo tanto, puede sesgar las distribuciones imputadas hacia la media observada. También reducirá la variación, entre otros impactos no deseados en la distribución imputada. Además, la eliminación por listas solo funcionará si los datos faltan completamente al azar, como al lanzar una moneda. También aumentará el error de muestreo, ya que se reduce el tamaño de la muestra.

Los autores citados anteriormente generalmente recomiendan comenzar con la variable que presenta los valores que faltan menos. Además, la técnica generalmente se aplica de forma bayesiana (es decir, una extensión de su sugerencia). Las variables se visitan con mayor frecuencia en el procedimiento de imputación, no solo una vez. En particular, cada variable se completa mediante sorteos de su distribución predictiva posterior condicional, comenzando con la variable que presenta los valores que faltan menos. Una vez que se han completado todas las variables en un conjunto de datos, el algoritmo nuevamente comienza en la primera variable y luego se repite hasta la convergencia. Los autores han demostrado que este algoritmo es Gibbs, por lo tanto, generalmente converge a la distribución multivariada correcta de las variables.

Por lo general, debido a que hay algunos supuestos no comprobables involucrados, en particular faltan datos aleatorios (es decir, si los datos se observan o no, depende solo de los datos observados y no de los valores no observados). Además, los procedimientos pueden ser parcialmente incompatibles, por lo que se les ha llamado PIGS (muestra de Gibbs parcialmente incompatible).

En la práctica, la imputación múltiple bayesiana sigue siendo una buena manera de lidiar con problemas de datos perdidos no monótonos multivariados. Además, las extensiones no paramétricas, como la comparación predictiva de medias, ayudan a relajar los supuestos del modelo de regresión.


Raghunathan, TE, Lepkowski, J., van Hoewyk, J. y Solenberger, P. (2001). Una técnica multivariada para la multiplicación de valores faltantes de imputación utilizando una secuencia de modelos de regresión. Survey Methodology, 27 (1), 85–95.

Schafer, JL y Graham, JW (2002). Datos faltantes: nuestra visión del estado del arte. Métodos psicológicos, 7 (2), 147-177. https://doi.org/10.1037/1082-989X.7.2.147

van Buuren, S. (2012). Imputación flexible de datos faltantes. Boca Raton: CRC Press.

tomka
fuente
1
excelente respuesta, por un lado, me alegro de haber avanzado al menos en la dirección que debo seguir, por otro lado, estoy triste de no tener un enfoque genial que no pensé. En la predicción interactiva de datos faltantes por el método bayes, ¿cómo podría reproducir algo como esto en python? ¿Es una regresión también? y después de predecir todos los datos faltantes posibles, ¿debería revisar el predictor para que los nuevos datos también participen en esa predicción? Muchas gracias por la ayuda, creo que beneficiará a muchos otros.
sn3fru
1
@ sn3fru Bueno, estas preguntas se responden en las referencias, entre otros lugares. No sé si existe una implementación de Python, pero replicarla no debería ser demasiado difícil. Supongo que requeriría estudiar un poco los detalles del algoritmo. En general, cualquier modelo bayesiano se puede utilizar para crear múltiples imputaciones, pero el micealgoritmo usa regresión o coincidencia de predicción media. Inicialmente, completa los datos faltantes mediante sorteos de la distribución observada y luego imputa secuencialmente. Una vez terminado, repite, pero utilizando los valores recién imputados. Los nuevos datos participan, sí
tomka
4

No encontré nada que resolviera mi problema, así que escribí una función que mezcla algunas soluciones para un marco de datos de Pandas con valores numéricos faltantes (con una fantasía) y categórico (con un bosque aleatorio).

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
fuente
Agradable, esto puede ayudar a otros (no lo comprobé); también puede ser interesante para ti contactar al creador de la Rfunción mice, Stef van Buuren. Puede estar interesado en su código de Python y / o señalarle el trabajo de otras personas a este respecto. stefvanbuuren.nl
tomka
No sé si estarían interesados ​​en algo tan simple, solo lo comparto aquí, ya que puede ayudar a otras personas que necesitan resolver la falta en un marco de datos de Pandas.
sn3fru
Bueno, pueden estar interesados ​​en implementarlo en Python en general y pueden saber si alguien ya lo ha hecho. Me he puesto en contacto con Stef antes y él es muy atento y servicial. Si hay una implementación de Python, también puede ser útil compartirla aquí bajo este hilo. Véase, por ejemplo, pypi.python.org/pypi/fancyimpute/0.0.4
tomka