欠損値の処理に関するエンドツーエンドの概要

ソースノード: 1121996

この記事は、の一部として公開されました データサイエンスブログソン

概要

データは、将来の出来事を分析し、予測する力を私たちに提供します。 日を追うごとに、予測やクラスタリングなどのデータ サイエンス手法を採用する企業が増えています。 複雑な ML および DL アルゴリズムについて学び続けることは非常に興味深いものですが、重要なアルゴリズムを習得することを忘れてはなりません。 データ前処理。 データ前処理の重要な部分の XNUMX つは、欠損値の処理です。 これは、さまざまな種類の欠落データに対処する方法に関する完全なガイドです。

内容

  1. 欠損値を処理することがなぜ重要なのでしょうか?
  2. 欠損値の背後にある理由
  3. 欠損値の種類
  4. データセット内の欠損値をチェックする
  5. 欠損値の視覚化
  6. 欠損値のある行を削除する
  7. 欠損値のある列の削除
  8. 連続変数の代入
    1. 平均による代入
    2. 中央値による代入
  9. 回帰による欠損値の予測
  10. カテゴリデータの欠損値
  11. 時系列データの欠損値
    1. 欠損値の前方埋め込み
    2. 欠損値を逆方向に埋め込む
    3. 線形補間
  12. 欠損値に対して堅牢なアルゴリズム
  13. まとめ

欠損データを処理することがなぜ重要なのでしょうか?

現実世界のデータには、多くの場合欠損データが存在します。 各値が欠落している理由はさまざまである可​​能性があります。 データの損失または破損が発生している可能性があります。あるいは、特定の理由がある可能性もあります。 データが欠落していると、モデルの予測能力が低下します。 欠損データを含むアルゴリズムを適用すると、パラメーターの推定に偏りが生じます。 欠損データを処理しないと、結果に自信が持てません。

欠損値の背後にある理由

データセット内のデータが欠落している理由について疑問に思ったことはありますか?

データ欠落の背後にある考えられる理由は次のとおりです。

  • データ収集アンケートでは、特定の質問に関する情報は提供されません。 たとえば、自分の給与、飲酒、喫煙習慣に関する情報を共有することに抵抗がある人もいるかもしれません。 これらは人々によって意図的に排除されています
  • 場合によっては、データは直接ではなく、入手可能なさまざまな過去の記録から蓄積されます。 この場合、データの破損が大きな問題となります。 メンテナンスが不十分なため、データの一部が破損し、データが欠落しています。
  • データ収集プロセス中の不正確さも、データ欠損の原因となります。 たとえば、手動でデータを入力する場合、人的ミスを完全に回避することは困難です。
  • 機器の不一致により測定に欠陥が生じ、使用できなくなります。

欠損値の種類

データの欠落はさまざまな理由で発生する可能性があります。 それらは XNUMX つの主なグループに分類できます: ランダムで完全に欠落、ランダムで欠落、ランダムで欠落なし。

1. 完全にランダムに欠落 (MCAR)

欠損データは特定のパターンに従いません。単にランダムです。 これらのデータの欠落は、残りの変数とは無関係または独立しています。 残りの変数データを使用してこれらの値を予測することはできません。 たとえば、データ収集中に、不注意により特定のサンプルが紛失してしまうことがあります。 これは、統計的に分析に偏りがない理想的なケースです。 ただし、これはまれな状況であるため、よほど確実でない限り、MCAR の存在を想定しないでください。

2. ランダムに行方不明 (MAR)

ここでは MCAR とは異なり、特定のサブセット間でデータが欠落しています。 他の機能を利用して、データが存在するかどうかを予測することができます。 ただし、欠損データ自体を予測することはできません。

たとえば、インターネットに費やした時間に関する調査を考えてみましょう。この調査には、Netflix や Amazon プライムなどのプラットフォームに費やした時間に関するセクションがあります。 高齢者(45 歳以上)は若い人よりも満たす可能性が低いことが観察されています。 これはMARの例です。 ここで、「Age」パラメーターは、データが欠落するかどうかを決定します。 MAR は MCAR よりも非常に一般的に発生します。

3. ランダムに欠落しない (NMAR)

これは深刻かつ困難な状況です。 調査の目的がソーシャルメディアの過剰使用/依存症を測定することだとしましょう。 ソーシャルメディアを過度に使用する人が意図的にアンケートに回答しなかった場合、NMAR のケースが発生します。 これはおそらく結果に偏りをもたらすでしょう。 行/列の削除、代入などの通常の方法は機能しません。 これを解決するには、そのドメインに関する深い知識が必要になります。

さまざまなタイプの欠損データを確認したので、それらを処理するさまざまな方法に進みましょう。

欠落している値を確認します

データセットがある場合、最初のステップは、どの列に欠落データがあるのか​​、またその数を確認することです。 データ サイエンスの学習の中で最も有名なデータセット、もちろんタイタニック号の生存者を使用しましょう。 以下に示すように、pandas read_csv 関数を使用してデータセットを読み取ります。

train=pd.read_csv('../input/titanic/train.csv') test=pd.read_csv('../input/titanic/test.csv') print('トレーニング データの形状: ', train.shape ) print('データ形状のテスト: ', test.shape) train.head()

欠損値データ

出典: 著者の Kaggle ノートブックからの画像

これで、タイタニック データのトレーニング データ フレームとテスト データ フレームが完成しました。

データが欠落している列とその数を確認するにはどうすればよいですか?

これには「isnull()」関数が使用されます。 isnull を指定して sum 関数を呼び出すと、各列の欠損データの合計が出力となります。

missing_values=train.isnull().sum() print(missing_values)
乗客 ID 0 生存 0 Pclass 0 名前 0 性別 0 年齢 177 SibSp 0 Parch 0 Ticket 0 Fare 0 Cabin 687 乗り出した 2 dtype: int64

3 つの列に値が欠落していることに注意してください: Age、Cabin、Embarked

各列に欠損している値の数はわかっていますが、合計値に対する欠損値の割合を把握することが重要です。 そこで、これを XNUMX 行のコードで計算してみましょう。

miss_value_percent = 100 * train.isnull().sum() / len(train) print(mis_value_percent)
旅客 ID 0.000000 生存 0.000000 P クラス 0.000000 名前 0.000000 性別 0.000000 年齢 19.865320 SibSp 0.000000 Parch 0.000000 チケット 0.000000 運賃 0.000000 客室 77.104377乗船しました 0.224467 dtype: float64

「キャビン」柱の 77% が欠落していることは明らかであり、これは非常に重要な割合です。 Age では約 19% のデータが欠落していますが、Embarked では 0.2% のみが欠落しています。 これは私たちが持っている欠損データの定量的な分析です。 定性的にはどうでしょうか? 読み続けます!

Missingno を使用した欠損値の視覚化

何だと思う? 特にデータセットの欠落データを視覚化して探索するための Python パッケージがあります。 「Missingno」Python パッケージ。 早速インストールしてみましょう

pip インストールがありません

これを使用すると、ヒート マップ、棒グラフ、マトリックスの形式で視覚化を作成できます。 それらがどのように分布しているかを分析することで、それらが MCAR、MAR、または NMAR のどのカテゴリに分類されるかを結論付けることができます。 欠損値を含む列とターゲット列の相関関係も見つけることができます。

まず、missingno ライブラリの 'bar()' 関数を使用して、null 以外の値の棒グラフを作成します。 pandas データフレームをこの関数に渡しました。

missingno を msno msno.bar(train) としてインポートします

行方不明 | 欠損値出典: 著者の Kaggle ノートブックからの画像

次に、行列の視覚化をプロットできます。 これは、欠損データがデータ全体にどのように分布しているか、つまり欠損データが局在しているのか均等に分散しているのか、あるいは何らかのパターンがあるのか​​など、多くの疑問を知るのに役立ちます。

msno.matrix(列車)
パターンバー

マトリックス プロットでは、欠損データごとに空白行が表示されます。 「Embarked」列には、パターンに従っていないランダムな欠損データが XNUMX つだけあることに注意してください。 おそらくデータ取得中に紛失したと考えられます。 したがって、これはランダムで完全に欠落しているものとして分類できます。

age 列と Cabin 列はおそらく MAR である可能性があります。 ただし、それらの間に相関関係がないことを確認したいと考えています。

どうやってするか?

幸いなことに、missingno パッケージは「ヒートマップ」機能も提供します。 これを使用すると、異なる列の欠損データ間に相関関係があるかどうかを確認できます。

msno.ヒートマップ(トレイン)

出力が表示されました!

ヒートマップ | 欠損値

ヒートマップは、Age 列と Cabin 列の欠損データの間にそれほど強い相関関係がないことを示しています。 したがって、これらの列の欠損データは、MAR またはランダムで欠損として分類できます。

欠損値を分析する方法については理解できたと思います。 次に、これらの欠落データを処理するさまざまな方法について説明します。

欠損値のある行を削除する

これは単純な方法で、特定の列に属する欠損値を持つ行をすべて削除します。 これは簡単ですが、大きな欠点もあります。 データの大部分が失われる可能性があります。 これにより、データセットのサイズが小さくなり、モデルの予測に偏りが生じます。 これは、欠損値の数が非常に少ない場合にのみ使用してください。

たとえば、「Embarked」列には欠損値が 2 つだけあります。 したがって、この列が欠落している行は削除できます。 以下のコードスニペットに従ってください。

print('前のデータセット:', len(train)) train.dropna(subset=['Embarked'],how='any',inplace=True) print('後のデータセット:', len(train)) print( '欠損値 :',train['Embarked'].isnull().sum())
前のデータセット: 891 後のデータセット: 889 欠損値: 0

「年齢」列に対して同じことを行った場合を想像してください。 データの約 77% が失われることになります。

列を削除する

列に大きな欠損値がある場合、入手可能な真のデータが最も少ない値を値に代入しても意味がありません。 したがって、いずれかの列に 80% を超える値が欠落している場合は、その列を分析から削除するだけで済みます。 この例の場合、「Cabin」には 77% のデータが欠落しているため、この列を削除するかどうかを選択できます。

削除された列が分析にとって重要でないことを確認してください。 その場合は、より多くのデータを取得してから、欠損値を代入してみる必要があります。

連続変数の代入

電車['年齢'][:10]
0 22.0 1 38.0 2 26.0 3 35.0 4 35.0 5 NaN 6 54.0 7 2.0 8 27.0 9 14.0 名前: 年齢、dtype: float64
train['年齢']=train['年齢'].replace(np.NaN,train['年齢'].mean()) train['年齢'][:10]
0 22.000000 1 38.000000 2 26.000000 3 35.000000 4 35.000000 5 29.699118 6 54.000000 7 2.000000 8 27.000000 9 14.000000 名前: 年齢、dtype: float64

「NaN」が 29.699 (計算された平均) に置き換えられていることがわかります。

平均代入にはいくつかの欠点があります。 データの分布が非常に不均一で、外れ値が多い場合、平均値はデータの実際の分布を反映しません。 平均は、極端な値や外れ値によって大きく影響されます。 したがって、データに外れ値があまりなく、正規分布に近い場合は、平均補完を使用します。

中央値による代入

連続フィーチャの欠損値は、残りの非 null 値の中央値で埋めることができます。 中央値の利点は、平均値とは異なり、外れ値の影響を受けないことです。 ここで実装してみましょう。

train['年齢']=train['年齢'].replace(np.NaN,train['年齢'].median()) train['年齢'][:10]

平均による代入

NaN 値の代わりに中央値 (28.0) が入力されていることがわかります。

同様に、モード代入も実行できます。 一般に、カテゴリ欠損値の場合、モードを使用した補完が一般的です。 これについては後のセクションで詳しく説明します

回帰による欠損値の予測

すべての場所を単一の平均値または中央値で埋めるのではなく、他の変数を利用してそれらを予測できたらどうなるでしょうか?

はい! NULL 以外の値を持つ特徴を使用して、欠損値を予測できます。 欠損値を予測するために回帰モデルまたは分類モデルを構築できます。 これをタイタニック データセットの「年齢」列に実装してみましょう。

モデルを構築するためにデータを処理できます。 「年齢」特徴がターゲット変数になります。

x_train: 「Age」値が存在するデータセットの行がフィルターされます。 「年齢」が対象です x_テスト: これは、NULL 以外の値が含まれる「年齢」列です。

  y_train データには Age 値が欠落しているため、予測されることになります (y_pred)

import pandas as pd data=pd.read_csv('../input/titanic/train.csv') data = data[["Survived", "Pclass", "Sex", "SibSp", "Parch", "Fare ", "年齢"]] data["性別"] = [x=="男性" の場合は 1、データ ["性別"] の x の場合は 0) test_data = data[データ["年齢"].isnull()] data.dropna(inplace=True) x_train = data.drop("年齢", axis=1) x_test = test_data.drop("年齢", axis=1) y_train = data["年齢"]

線形回帰モデルをこれらのデータに当てはめてみましょう。 ここでは sklearn ライブラリを使用します。

sklearn.linear_model からインポート LinearRegression モデル = LinearRegression() model.fit(X_train, y_train) y_pred = model.predict(X_test)

これで、y_pred で予測された Age 列の NULL 値が得られました。

理解を深めるために、テスト入力と予測される出力の例をいくつか印刷します。

print(x_test[:10])
生存した Pclass 性別 SibSp Parch 運賃 5 0 3 1 0 0 8.4583 17 1 2 1 0 0 13.0000 19 1 3 0 0 0 7.2250 26 0 3 1 0 0 7.2250 28 1 3 0 0 0 7.8792 29 0 3 1 0 0 7.8958 31 1 1 0 1 0 146.5208 32 1 3 0 0 0 7.7500 36 1 3 1 0 0 7.2292 42 0 3 1 0 0 7.8958

これは、入力が回帰モデルに渡される方法です。 予測年齢値を見てみましょう。

print(y_pred[:10])
[29.07080066 30.10833306 22.44685065 29.08927347 22.43705181 29.07922599 32.43692984 22.43898701 22.15615704]

万歳! 値を取得しました。

カテゴリデータの欠損値

ここまでは、数値データが欠落している場合の対処方法を見てきました。 カテゴリ特徴の場合にデータが欠落している場合はどうなりますか? たとえば、タイタニック号データセットの「キャビン」特徴はカテゴリカルです。 ここでは、平均値と中央値を計算できません。 したがって、欠損値をモードまたは最も頻繁に発生するクラス/カテゴリで埋めることができます。

train['Cabin']=train['Cabin'].fillna(train['Cabin'].value_counts().index[0])

欠損値の割合が少ない場合は、この方法が推奨されます。 データの大幅な損失は発生せず、統計的に関連性があります。

ただし、欠損値が多数ある場合、最も頻度の高いクラスで代入することは意味がありません。 代わりに、「不明」や「利用不可」などの欠損値用に別のカテゴリを作成しましょう。 クラス数がXNUMXつ増えます。

欠損値がカテゴリ列 (文字列または数値) からのものである場合、欠損値を最も頻度の高いカテゴリに置き換えることができます。 欠損値の数が非常に多い場合は、新しいカテゴリに置き換えることができます。

train['キャビン']=train['キャビン'].fillna('不明') train['キャビン'][:10]

キャビンロウ | 埋めてください

小規模なデータセットではうまく機能します。 また、独自のカテゴリを追加することで、データの損失も回避します。

時系列データの欠損値を処理するにはどうすればよいですか?

タイムスタンプとともに情報が整然と収集されたデータセットは、時系列データと呼ばれます。 時系列データに欠損値がある場合は、上記で説明したいずれかの方法を試すことができます。 ただし、ここで使用できる具体的な方法もいくつかあります。

アイデアを得るために、単純なダミー データセットを作成します。

time= pd.date_range("1/01/2021", period=10, freq="W") df = pd.DataFrame(index=time); df["販売数"] = [5.0,4.0,np.nan,np.nan,1.0,np.nan,3.0,6.0,np.nan,2.0]; 印刷(df)

販売台数

メソッドに移りましょう

欠損値の前方埋め込み

次の行の値は欠損値を埋めるために使用されます。「ffill」は「forward fill」を表します。 実装は非常に簡単です。 fillna() 関数で「method」パラメータを「ffill」として渡すだけです。

forward_filled=df.fillna(method='ffill') print(forward_filled)

前方埋め込み

欠損値を逆方向に埋め込む

ここでは、前の行の値を使用して欠損値を埋めます。 「bfill」は後方フィルを表します。 ここでは、メソッドパラメータとして「bfill」を渡す必要があります。

backward_filled=df.fillna(method='bfill') print(backward_filled)

背中がいっぱい

上の画像で両方の違いがわかると思います。

線形補間

時系列データにはさまざまなバリエーションがあります。 バックフィルとフォワードフィルを使用した上記の代入方法は、最善の解決策ではありません。 線形補間が助けになります!

ここでは、値は増加または減少する値で埋められます。 これは一種の代入手法であり、データ ポイント間の線形関係をプロットしようとします。 欠落点を計算するために利用可能な非 null 値を使用します。

interpolated=df.interpolate(limit_direction="両方") print(補間)

欠損値の線形補間

これらの値を後方および前方フィルと比較し、どちらが適切であるかを自分で確認してください。

これらは、時系列データの欠損値を処理する基本的な方法です。

欠損値に対して堅牢なアルゴリズム

上記のどれもうまく機能しない場合があります。 ただし、分析を行う必要があります。 次に、欠損値をサポートするアルゴリズムを選択する必要があります。 KNN (K 最近傍) はそのようなアルゴリズムの XNUMX つです。 K 個の最も近い値の大部分を取得することによって、欠損値が考慮されます。 ランダム フォレストは、欠損値のあるカテゴリ データに対しても堅牢です。 XGBoost、Catboost などの多くのデシジョン ツリー ベースのアルゴリズムは、欠損値のあるデータをサポートしています。

まとめ

要約すると、最初のステップはデータを調査し、どの変数に欠損データがあるのか​​、その割合はどれくらいか、そしてそれがどのカテゴリに属しているのかを調べることです。 この後、どのような方法を試せるかについての戦略的なアイデアが得られます。 役立つヒントは、線形回帰モデルとは別に、K 最近傍アルゴリズムを使用した補完を試してみることです。 上記の方法が機能しない場合は、Datawig や Hot-Deck Imputation メソッドを使用するなど、検索できる最新の方法がいくつかあります。

読んで気に入っていただければ幸いです。

次の場所で私と連絡を取ることができます: [メール保護]

LinkedInの: データ前処理

この記事に示されているメディアは、Analytics Vidhyaが所有しておらず、作成者の裁量で使用されています。

出典: https://www.analyticsvidhya.com/blog/2021/10/end-to-end-introduction-to-handling-missing-values/

タイムスタンプ:

より多くの 分析Vidhya