機械学習で欠落データの問題を回避する方法


15

機械学習アルゴリズムを使用して予測したい事実上のデータベースは、いくつかの特性の欠損値を見つけます。

この問題に対処するには、欠損値を持つ行を特性の平均値で埋めるまで除外するいくつかのアプローチがあります。

私はやや堅牢なアプローチに使用したいと思います。これは基本的に回帰(または別の方法)を実行し、従属変数(Y)は欠損値を持つ各列ですが、テーブルの行のみであるすべてのデータを含み、このメソッドで欠損値を予測し、テーブルごとにテーブルを完成させ、欠損値のある次の「列」に移動し、すべてが満たされるまでメソッドを繰り返します。

しかし、それは私にいくつかの疑問を与えます。

なぜ列が始まるのですか?欠損値が最小のものは、最大値を持つものまで

完了しようとする価値のない欠損値のしきい値はありますか?(たとえば、この特性が満たされている値の10%しか持っていない場合、それを除外することはもっと面白くないでしょう)

従来のパッケージや、欠落に強い他の方法での実装の種類はありますか?


3
あなたが探している芸術の用語は「帰属」であり、複数の帰属は人気のある現代的な選択肢です。観測値が欠落している観測値を除外したり、欠落している観測値を平均値に置き換えたりすると、データに大きな偏りが生じる可能性があることに注意してください。開始する1つの場所は、Gelman et al、Bayesian Data Analysis 3rd Edition、 "Chapter 18:Models for Missing Data。"です。
Sycoraxは回復モニカ言う

ヒントをありがとう、その用語で検索してcap18を見ていきます。行を削除すると、モデルに多くのバイアスがかかる可能性があり(欠損値がランダムでない場合は非常に可能性が高い)、平均値を配置すると、データ欠損値の外生性にも応じて、平均の周りに強い「慣性負荷」をかけることができます 私の大きな質問は、これを処理するための最良のアプローチであり、私の提案は、メイン回帰の前にデータを完了するために事前回帰を実行することです(これを行うパッケージはありますか、それを作成する必要がありますか?)
sn3fru

最新の多重代入は、欠損データと欠損データのモデルを並べて推定します。欠損データに対するベイジアンの考え方は、欠損データの分布を推定することであり、観測データと欠損のモデルを条件とします。Pythonの統計ソフトウェアには、多くの要望があります。TSCSデータの場合Amelia II、Rは確実な選択です。または、を使用して独自のロールを作成できますstan
シコラックスは、モニカーを復活させる

回答:


9

説明する手法は、逐次回帰による代入、または連鎖方程式による多重代入と呼ばれます。この手法はRaghunathan(2001)によって開拓され、よく機能するRパッケージmice(van Buuren、2012)で実装されました。

Schafer and Graham(2002)の論文は、平均補完とリストごとの削除(行の除外と呼ばれる)が通常、上記の手法の優れた代替手段ではない理由をよく説明しています。主に平均代入は条件付きではないため、代入分布を観測平均に偏らせることができます。また、帰属する分布への望ましくない影響の中でも、分散を縮小します。さらに、リストワイズ削除は、コインの裏返しなど、データが完全にランダムに欠落している場合にのみ機能します。また、サンプルサイズが小さくなると、サンプリングエラーが増加します。

上記で引用した著者は、通常、最小欠損値を特徴とする変数から始めることを推奨しています。また、この手法は通常、ベイジアン方式(つまり、提案の拡張)で適用されます。変数は、1回だけではなく、代入手順でより頻繁にアクセスされます。特に、各変数は、条件付き事後予測分布からの描画によって完成し、最小欠損値を特徴とする変数から始まります。データセット内のすべての変数が完了すると、アルゴリズムは最初の変数から再び開始し、収束するまで繰り返します。著者は、このアルゴリズムがギブスであることを示しているため、通常、変数の正しい多変量分布に収束します。

通常、いくつかのテスト不可能な仮定が含まれているため、特にランダムデータの欠落(つまり、データが観測されるかどうかは観測されたデータのみに依存し、非観測値には依存しません)。また、プロシージャは部分的に互換性がない場合があるため、PIGS(部分的に互換性のないGibbsサンプラー)と呼ばれています。

実際には、ベイズの多重代入は、まだ多変量の非単調な欠損データの問題に対処するための良い方法です。また、予測平均マッチングなどのノンパラメトリック拡張は、回帰モデリングの仮定を緩和するのに役立ちます。


ラグナタン、TE、レプコウスキー、J。、ヴァンホーウィック、J。、およびソレンバーガー、P(2001)。回帰モデルのシーケンスを使用して欠損値を代入する多変量手法。調査方法、27(1)、85–95。

シェーファー、JL、およびグラハム、JW(2002)。欠落データ:最先端の私たちの見解。心理学的方法、7(2)、147–177。https://doi.org/10.1037/1082-989X.7.2.147

ヴァンビューレン、S。(2012)。欠落データの柔軟な代入。ボカラトン:CRC Press。


1
優れた対応、一方で私は少なくとも従わなければならない方向に進んだことをうれしく思います。他方では、私が考えていなかった穏やかなアプローチを持っていないことを悲しいです。ベイズ法による欠損データのインタラクティブな予測では、このようなものをPythonでどのように再現できますか?それも回帰ですか?すべての可能性のある欠落データを予測した後、新しいデータもその予測に参加するように予測子を調べる必要がありますか?助けてくれてありがとう、他の多くの人にとっても有益だと思います。
sn3fru

1
@ sn3fruさて、これらの質問は他の場所の中でも参考文献で回答されています。Python実装が存在するかどうかはわかりませんが、それを複製するのはそれほど難しくないはずです。アルゴリズムの詳細を少し調べる必要があると思います。一般に、ベイジアンモデルを使用して複数の代入を作成できますが、miceアルゴリズムは回帰または予測平均マッチングを使用します。最初に、観測された分布から描画することにより欠落データを完成させ、その後順次計算します。終了したら、繰り返しますが、新しく代入された値を使用します。新しいデータが参加します。はい
トムカ

4

私は問題を解決するものを見つけられなかったので、パンダのデータフレームに対するいくつかのソリューションと、欠損値(fancyimpute)とカテゴリ(ランダムフォレスト)を組み合わせた関数を作成しました。

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

彼らがとてもシンプルなものに興味があるかどうかはわかりませんが、パンダのデータフレームの欠落を解決する必要がある他の人々を助けることができるので、ここで共有しています。
sn3fru

まあ、彼らは一般的にPythonでそれを実装することに興味があるかもしれません、そして、彼らは誰かがすでにそれをしたかどうか知っているかもしれません。私は以前にStefに連絡しましたが、彼は非常に反応がよく親切です。Python実装がある場合は、このスレッドの下でここで共有することも有用です。例えば参照pypi.python.org/pypi/fancyimpute/0.0.4
tomka

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.