解决机器学习中数据丢失问题的方法


15

几乎我们要使用机器学习算法进行预测的任何数据库都会发现某些特征的缺失值。

有几种解决此问题的方法,以排除具有缺失值的线,直到它们填充特征的平均值为止。

我想使用一种更健壮的方法,该方法基本上将运行回归(或其他方法),其中因变量(Y)将是每个缺少值但仅包含表行的列包含所有数据的对象,并使用此方法预测缺失值,按表填写表格并移至具有缺失值的下一个``列'',然后重复该方法直到所有内容都填满。

但这给了我一些疑问。

为什么任何列开始?我相信缺失值最小的那个直到最大的一个

是否有任何缺失值的阈值不值得尝试完成?(例如,如果此特征仅填充了10%的值,将其排除会更有趣)

在传统软件包或其他方法中是否有任何对丢失有鲁棒性的实现?


3
您正在寻找的艺术术语是“输入”,多重插补是一种流行的现代选择。请注意,排除观察值缺失的观察值或用均值替代缺失的观察值会严重偏误数据。一个开始的地方是Gelman等人,贝叶斯数据分析第三版,“第18章:丢失数据的模型”。
Sycorax说恢复莫妮卡的时间

感谢您的提示,我将搜索该术语并查看cap18。删除线可能会使模型产生很大的偏差(如果缺失不是随机的,则很有可能),而放置平均值会在平均值附近施加强大的“惯性负荷”,这也取决于数据缺失的外生性。我的大问题是处理此问题的最佳方法,我的建议是运行主回归以在主回归之前完成数据(是否有任何软件包可以这样做或应该创建一个?)
sn3fru

现代多重插补可以并排估算丢失和不丢失数据的模型。贝叶斯对缺失数据的看法是,以观测数据和缺失模型为条件,估计缺失数据的分布。python中的统计软件还有很多不足之处。对于TSCS数据,Amelia IIR是一个不错的选择。或者,您可以使用自己滚动stan
Sycorax说恢复Monica

Answers:


9

您描述的技术称为按顺序回归的插补或按链式方程式的多重插补。该技术由Raghunathan(2001)率先提出,并在一个运行良好的R包中实现mice(van Buuren,2012)。

Schafer和Graham(2002)的一篇论文很好地解释了为什么均值插补和逐行删除(通常称为行排除)通常不能替代上述技术。原则上,均值插补不是有条件的,因此可以使估算的分布偏向观察到的均值。它还将缩小方差,以及对推算分布的其他不良影响。此外,按列表删除确实仅在数据完全随机丢失(例如通过掷硬币)时才起作用。随着样本数量的减少,也会增加采样误差。

上面引用的作者通常建议从缺失值最少的变量开始。同样,该技术通常以贝叶斯方式应用(即您建议的扩展)。在插补过程中,变量访问更为频繁,而不仅仅是一次。特别是,每个变量都是通过从其条件后验预测分布中抽取变量来完成的,从具有最小缺失值的变量开始。数据集中的所有变量完成后,该算法将再次从第一个变量开始,然后重新迭代直到收敛。作者已经表明,该算法是Gibbs,因此它通常收敛于变量的正确多元分布。

通常,因为涉及一些无法检验的假设,尤其是在随机数据中缺失(即是否观察到数据仅取决于观察到的数据,而不取决于未观测到的值)。这些过程也可能是部分不兼容的,这就是为什么它们被称为PIGS(部分不兼容的Gibbs采样器)的原因。

实际上,贝叶斯多重插补仍然是处理多元非单调缺失数据问题的好方法。同样,非参数扩展(例如预测均值匹配)有助于放宽回归建模假设。


Raghunathan,TE,Lepkowski,J.,van Hoewyk,J。,和Solenberger,P。(2001)。一种使用一系列回归模型乘以插补缺失值的多元技术。调查方法论,27(1),85-95。

Schafer,JL和Graham,JW(2002)。缺少数据:我们对最新技术的看法。心理方法,7(2),147–177。https://doi.org/10.1037/1082-989X.7.2.147

van Buuren,S.(2012年)。灵活估算丢失的数据。博卡拉顿:CRC Press。


1
出色的回应,一方面我很高兴至少提出了我必须遵循的方向,另一方面我很遗憾没有采用我没有想到的和可亲的方法。在通过Bayes方法交互式预测丢失的数据时,如何在python中重现类似的内容?它也是回归吗?在预测所有可能的丢失数据之后,我是否应该遍历预测器,以便新数据也参与该预测?非常感谢您的帮助,我相信它将使其他许多人受益。
sn3fru

1
@ sn3fru好吧,这些问题在参考文献中以及其他地方得到了回答。我不知道是否存在Python实现,但是复制它应该不会太困难。我想这需要研究一下算法的细节。通常,任何贝叶斯模型都可以用于创建多个归因,但是该mice算法使用回归或预测均值匹配。您首先通过从观察到的分布中抽取数据来完成丢失的数据,然后顺序进行估算。完成后,请重复,但要使用新估算的值。新数据参与,是的
-tomka

4

我没有找到能解决问题的任何东西,因此我编写了一个函数,该函数将一些解决方案与缺少数值(带有fancyimpute)和分类(带有随机森林)的Pandas数据框混合在一起。

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)

很好,这可能会对其他人有所帮助(我没有检查)-与R函数创建者miceStef van Buuren 联系可能也很有趣。他可能对您的Python代码感兴趣,并且/或者在这方面将您引向其他人的工作。stefvanbuuren.nl
tomka

我不知道他们是否会对如此简单的东西感兴趣,我只是在这里分享,因为它可以帮助需要解决Pandas数据框中的缺失的其他人。
sn3fru

好吧,他们可能对一般在Python中实现它感兴趣,并且他们可能知道是否有人已经完成了它。我之前已经联系过Stef,他反应迅速且乐于助人。如果有Python实现,则在此线程下在此处共享它可能也很有用。参见例如pypi.python.org/pypi/fancyimpute/0.0.4
tomka

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.