KaggleのHouse Pricesで回帰分析(Feature Engineering編)

今回も、kaggleの入門者向けチュートリアルコンペ「住宅価格予測」を解いてみます。

House Prices: Advanced Regression Techniques

各種指標を用いて住宅の価格を予測する分析問題です。

データ分析のプロセスとして、CRISP-DM(CRoss Industry Standard Process for Data Mining)というものがあります。

モデリングより前のステップである「ビジネスの理解」「データの理解(Exploratory Data Analysis)」「データの準備(Feature Engineering)」のステップが大半を占めます。

今回はタイタニックに続いて二度目の「データの準備(Feature Engineering)」という位置付けです。

Python命名規則一覧

PEP8でPython命名規則が次のように定められています。

対象 ルール
パッケージ 全小文字 なるべく短くアンダースコア非推奨 tqdm, requests …
モジュール 全小文字 なるべく短くアンダースコア可 sys, os,…
クラス 最初大文字 + 大文字区切り MyFavoriteClass
例外 最初大文字 + 大文字区切り MyFuckingError
型変数 最初大文字 + 大文字区切り MyFavoriteType
メソッド 全小文字 + アンダースコア区切り my_favorite_method
関数 全小文字 + アンダースコア区切り my_favorite_funcion
変数 全小文字 + アンダースコア区切り my_favorite_instance
定数 全大文字 + アンダースコア区切り MY_FAVORITE_CONST

前回、行列を「X_test」と表したので全小文字を守ってませんが、それ以外は従って記載します。

特徴エンジニアリング(データの準備:前処理)

次のようなことを行います。

  • 外れ値の除去(.drop)
  • 外れ値・多重共線性の変数除去
  • 欠損値の補完または除去(pandasの.fillna())
  • 数値型特徴のカテゴリ変数化
  • ダミー化(ラベル&ワンホットエンコーディング)(pandasの.get_dummies())
  • 数値変数をモデルに適した形式へ変換(対数変換、BoxCox変換)
  • 数値型特徴の正規化と標準化
  • 次元削減と特徴量抽出
  • 学習データとテストデータをマージする
  • カテゴリ型特徴の組み合わせ特徴生成

データの読み込み

外れ値・多重共線性の変数除去(.drop)

統計学において、他の値から大きく外れた値のことを外れ値と言います。

多重共線性」も除去が必要なため、相関の高い変数をまとめた新変数に対して、外れ値を確認して除去します。

  • OverallQualが10より小さくSalePriceが500000より大きい場合は除去
  • OverallQualが5より小さくSalePriceが200000より大きい場合は除去
  • TotalSF(1stFlrSF+2ndFlrSF+TotalBsmtSF+GrLivArea)が10000より大きく、SalePriceが300000より小さい場合は除去
  • SF(WoodDeckSF+OpenPorchSF+BsmtFinSF1)のSalePriceが500000より大きい場合は除去
  • Garage(GarageCars+GarageArea)のSalePriceが500000より大きい場合は除去
  • Year(YearBuilt+YearRemodAdd)のSalePriceが500000より大きい場合は除去
  • それ以外の変数のSalePriceが600000より大きい場合は除去

物件の大きさ(広さ)の外れ値を除去します。

その上で、散布図を出力してみます。

大きな外れ値は除去されました。

欠損値の補完または除去(pandasの.fillna())

欠損値の除去の手法一覧は次の通りです。

欠損値の補完の手法一覧は次の通りです。

データフレームから特定の行や列を取得する手法一覧は次の通りです。

またlambda(無名関数)を使って「ある変数のカテゴリの中央値で補完する」という柔軟な記載方法もできます。

今回のデータに対してはデータの欠損そのものが情報だと分かっているので、次のような方針で補完します。

  • カテゴリカル変数(object)の欠損:欠損を示す文字列「NA」を補完
  • 数値型変数(float)の欠損「0.0」を補完
  • LotFrontage(隣接した道路の長さ)は、Neighborhood(同じ地区)の他の物件の「中央値」を補完

Neighborhood(Ames市域内の物理的な場所)には、Blmngtn(ブルーミントンハイツ)、Blueste(ブルーステム)、BrDale(ブライアデール)、BrkSide(ブルックサイド)、ClearCr(クリアクリーク)などの値が入っています。

欠損値の補完は次のようになります。

欠損データは無くなりました。

数値型特徴のカテゴリ変数化

データの型は「数値」でも、数値の大きさに意味を持たない(1と10で比較した場合、10倍の違いがない)場合、カテゴリ変数に変換します。

尺度 説明
名義尺度 識別のために数字を与えたもの。例えばID、電話番号など。LabelEncoderで変換される整数値を用いて回帰分析を行うことはできない。1つの変数の離散値として扱う場合は、決定木分析、ランダムフォレストなどの分析と相性が良い
順序尺度 順序を表す数字。例えばランキング、地震の震度、成績表などが。数字の大小に意味はあるが、差や比は意味がない。ラベルと整数を対応させるディクショナリを使って、マッピングを行うことで数値化
間隔尺度 間隔に意味のある数値。例えば℃単位の温度。「夏の最高気温30℃は春の最高気温15℃より2倍大きい」と言うことに意味はないが、「夏の一日の寒暖差(最高気温と最低気温の”間隔”)6℃は、春の寒暖差12℃より2倍小さい」と言うことは可能
比例尺度 四則演算が全て使える数値。温度も絶対温度K(ケルビン)に直せば比例尺度になる。年齢、金額、期間などもこれに属す

機械学習においては数式上で四則演算を行うので、全ての値を比例尺度に変換するのが好ましいです。

データの定義を見てみると、以下の変数は数値変数ではなくカテゴリ変数として扱ったほうが良さそうです。

変数名 説明
MSSubClass: Identifies the type of dwelling involved in the sale 住宅の種類を表す。数値はどの種類に当てはまるかを表すだけで大きさや順序に意味はない
YrSold: Year Sold (YYYY) 販売年。大きさや順序に意味はない
MoSold: Month Sold (MM) 販売月。大きさや順序に意味はない

※最終的には、学習データとして価値が無さそうなので除去しました(以下参照)。

カテゴリカル変数のエンコーディング(ダミー変数)

文字列でカテゴリー分けされた性別などのデータを、男を0, 女を1のように変換したり、多クラスの特徴量をone-hot表現に変換することをエンコーディング(ダミー変数)と呼びます。

次の手法がよく使われています。

  • Label encoding
  • Count encoding (frequency encoding)
  • One-hot encoding
  • Target encoding
  • Lightgbm の categorical feature support
  • Catboost の ordered target encoding

Kaggleではlabel encodingが人形です(one-hot encodingの方がパフォーマンスが高い)。

Label encoding

Label encodingは、決定木ベースのアルゴリズムで有効でカテゴリカル変数をスカラ値(数値)に変換します。

One hot Encoding

一方、One hot Encodingにより、カテゴリカル変数に対して、各要素が該当するなら1、該当しないなら0とするカラムを変数の要素数分作ることができます。

One Hot Encodingであれば決定木ベースや線形回帰やニューラルネットでも有効に作用します。

一般的には「get_dummies」などを利用します。

ラベルエンコーディングでは発生頻度の低い稀なカテゴリなどが取りにくく、重要な変数がうまく取れない場合があるため、One hot encodingはの処理に役立ちます。

ただし、データ量が多い場合にはかなりのメモリ消費を強いられます。

このため、扱うアルゴリズムに応じて適切なEncodingを使わなくてはいけません。

その他のEncoding

各変数の順序関係に従って、エンコーディングする場合は、次のように記載できます。

int64、float64は数値なので、そのままモデルに投げることができます。

ただ、objectは基本的には文字情報で、このままだとモデルに与えることはできません。

まずobject変数を抽出し、それぞれの意味を確認します。

ひとつひとつカラムをラベルエンコーディングで数値化しながら確認します。

順序に意味がない名義尺度では、LabelEncoderで変換される整数値を用いて回帰分析を行うことはできません。

これを、順序尺度の性質を持つように「SalePrice」でエンコーディングしてみます。

今回は、他も同じようにエンコーディングします。

変数の除去(pandasの.drop())

変数の除去の手法一覧は次の通りです。

他の変数は特徴量を減らすため、利用せず除去します。

object変数は除去されました。

数値変数をモデルに適した形式へ変換

数値データは多くの問題を抱えています。

  • スケールが大きく異なる
  • 歪んだ分布をもつ
  • 大小の外れ値を含む
  • 変数間で、線形では表現できないような複雑な関係を持っている
  • 冗長な情報

これらの問題は、回帰か分類かという課題設定に応じて、適用するモデルの種類によって顕在化します。

k近傍法やサポートベクターマシンは、特徴空間上の外れ値の影響を受けやすい性質があります。

一方で、実際の値ではなく順位化されたデータを利用する木ベースのモデルでは外れ値の影響を軽減可能です。

線形回帰モデルでは、出力から得られる値の誤差が正規分布に従うことを仮定します。

そのため正規分布とは異なる形状の分布をもつデータ(例えば離散値)では、その仮定が成立しない可能性があります。

このような状況では部分最小二乗法を用いることで説明変数の相関を無相関化できます。

そのための手法として次のようなものがあります。

変換方法 説明
スケール変換 データが取りうる値のスケールを変換し、一定の範囲に収める処理を行う
対数変換 特徴量のスケールが大きい時はその範囲を縮小し、小さい時は拡大する。分散が大きなデータでは平均値が大きいほど等分散となりやすい傾向がある。0や負値を扱えない(下駄を履かせる必要あり)
Box-Cox変換 データの分布を変えることでデータを正規分布に近づける。0や負値を扱えない(下駄を履かせる必要あり)
Yeo-Johnson変換 (Yeo-Johnson Power Transformations) 0や負値を含んだ特徴量を扱える
ロジット変換 0から1の値を負と正の無限大の間の値に変換。つまり変換後の値は正規分布に近づく

対数変換を利用する場合

対数変換では、変数 x を自然対数 log e_x に変換することを指します。

まずはグラフを再確認します。

歪度が正の値なので、右裾が長い(≒左に偏っている)分布であること、尖度が正の値のため正規分布よりもだいぶ尖った(平均付近にデータが集中している)分布であることがわかります。

次に、logを使って対数変換をすることで正規分布に近づけます。

学習モデルで予測後は、expを使って元のスケールに戻すことを忘れないでください。

Box-Cox変換・Yeo-Johnson変換を利用する場合

同様に大きく歪んだ特徴量は、Box-Cox変換を使って補正することもできます。

Box-Cox変換とは、変数のスケールを変えて分布を正規分布(ガウス分布)の形に変えてくれる変換です。

Box-Cox変換は0以下の値をとる変数には使用できないため、まずは各変数の最小値を確認します。

負の値はないですが、0が含まれる変数が多くあります。

今回はBox-Cox変換ではなく、0以下の値を持つ変数にも適用可能なYeo-Johnson変換を使うことにします。

この変換も奥が深いので、詳細はまた今度調査します。

新たな特徴量の追加

SalesPriceを予測する「Zillow Prize: Zillow’s Home Value Prediction」で、

物件の面積を部屋数で割った1部屋当たりの面積という特徴量を追加したことで精度が上がった

[引用] 新たな特徴量の追加

という記事を見つけたので追加してみます。

数値型特徴の標準化や正規化

木ベースのモデル(決定木、ランダムフォレスト)では、特徴量を入力とする複数のステップ関数(閾値を超えた場合に1, そうでなければ0に変換する)の組み合わせによって構成されるため変数のスケールの影響を受けません。

ロジスティック回帰や部分最小二乗法、リッジ回帰や距離を利用するk-means、主成分分析など、多くのモデルは入力のスケールに敏感で、変数間のスケールを揃える必要があります。

リッジ回帰、主成分分析では入力に用いる変数間のスケールが標準化されていることが前提です。それは特徴量空間におけるデータ間を距離を利用するためです。

そのため、標準化したデータを元に主成分分析を行う必要があります。

手法 内容
標準化 (standardization) とは、平均0、分散(標準偏差)1にすること
正規化 (normalization) 取りうる値の範囲が統一すること

体重や身長など、単位が異なる変数を比較する際に役立ちます。

[EDA] 決定木による相関の強い特徴量チェック(feature_importance_)

欠損値が無くなり数値化されたので、sklearnのランダムフォレストのfeature_importance_を見ることにより、どのFeatureがどれくらい重要か見てみましょう。

【matplotlibの場合】

【seabornの場合】

70以上あるFeatureの中で、SalePriceの予測に大切なのはほんの数個しかない、ということがわかります。

[EDA] 散布図や箱ひげ図を用いた目的変数と、説明変数の関係の可視化

vs SalePriceの上位24変数をプロットしてみます。

線形の関係性が読み取れるものが幾つかあります。

外れ値 (outlier)を再度除去したい場合には、手順を戻って「除去→欠損値の補完」を繰り返します。

学習データとテストデータを統合

最後に学習データとテストデータを統合します。

マージされた「all_data」というリストが作成されました。

次回は、これを使って学習モデルを形成します。

ソースコード

まとめ

前回、方針を決めたにも関わらず、学習データを用意するのに、こんなに苦労するとは思いませんでした。

更に多くのライブラリやlambda(無名関数)式のような記載方法があるため学習が必要です。

しかし、機械学習を始めるまでが本当に長い・・・。

タイトルとURLをコピーしました