KaggleのHouse Prices CompetitionのKernelからデータの探り方を学ぶ

pythonmachinelearning

Kaggleの家の売値を予測するCompetitionのKernelからデータの探り方を学ぶ。

Comprehensive data exploration with Python

正規化

予測する値であるSalePriceの分布を出すと、やや左に寄った非対称の分布をしている。

import pandas as pd
import seaborn as sns
df = pd.read_csv('train.csv')
df['SalePrice'].describe()
sns.distplot(df['SalePrice'])
count      1460.000000
mean     180921.195890
std       79442.502883
min       34900.000000
25%      129975.000000
50%      163000.000000
75%      214000.000000
max      755000.000000

SalePriceの分布

scipy.stats.probplot()で 生成できる、2つの分布(今回はSalePriceの分布と正規分布)の同じ分位数の値をプロットしたQ-Q (quantile-quantile) plotを見ても直線で表されている正規分布から外れていることが分かる。 本来のQ-Q plotではこの直線は同じ分位数に同じ値が来るy=xに引かれるが、この関数が生成するプロットはxがスケールされているのでそうなっていない。

from scipy import stats
import matplotlib.pyplot as plt
res = stats.probplot(df['SalePrice'], dist='norm', plot=plt)

SalePriceの分布と正規分布のprobplot()

正規分布であることが望ましいので対数をとって近づけてやる。

import numpy as np
res = stats.probplot(np.log(df['SalePrice']), dist='norm', plot=plt)

SalePriceの分布と正規分布のprobplot()

なお、この変換はBox-Cox transformationのλ=0のときにあたる。

Box-Cox transformationで非正規分布のデータを正規分布に近づける - sambaiz-net

欠損値

欠損率

特徴量の欠損(NA)率を多い順にならべてみると次のようにいくつかはほとんど欠損していることが分かる。

total = df.isnull().sum().sort_values(ascending=False)
percent = (df.isnull().sum()/df.isnull().count()).sort_values(ascending=False)
missing_data = pd.concat([total, percent], axis=1, keys=['Total', 'Percent'])
print(missing_data.head(10))
        Total   Percent
PoolQC         1453  0.995205
MiscFeature    1406  0.963014
Alley          1369  0.937671
Fence          1179  0.807534
FireplaceQu     690  0.472603
LotFrontage     259  0.177397
GarageCond       81  0.055479
GarageType       81  0.055479
GarageYrBlt      81  0.055479
GarageFinish     81  0.055479

パラメータ間の相関

まず各パラメータ間の相関を見てみる。

import matplotlib.pyplot as plt

plt.figure(figsize=(9, 6))
sns.heatmap(df.corr(), square=True, yticklabels=True, cmap="RdBu_r", linecolor="white", linewidths=.2);

各パラメータの相関

色が濃くなっているところが強い相関がある組み合わせで、例えばSalePriceの行を見てみると OverallQual(品質)やGrLivArea(延べ床面積?)の正の相関が比較的強く、 実際OverallQualとSalePriceの相関係数を出すと0.79とかなり高い。箱ひげ図で見ても分かりやすい。

data = pd.concat([df['SalePrice'], df['OverallQual']], axis=1)
f, ax = plt.subplots(figsize=(8, 6))
fig = sns.boxplot(x='OverallQual', y="SalePrice", data=data)
fig.axis(ymin=0, ymax=800000)
print(df['SalePrice'].corr(df['OverallQual'])) # => 0.7909816005838044

OverallQualとSalePriceの箱ひげ図

欠損値の扱い

欠損率があまりに多かったり、他に相関が強く代替できるものがあれば、 取り除いてやったり、ほとんど欠損してない場合は欠損しているレコードだけ取り除くこともできるが、取り除き過ぎると精度が上がらない。 そこでなるべく自然な、連続値であれば中央値や0といった値を埋めて使いたい。ドメイン知識が必要になるところだと思う。

df["PoolQC"].fillna("None")

外れ値

X軸をGrLivArea、Y軸をSalePriceとしてPlotすると右下2点が外れ値になっていることが分かる。

data = pd.concat([df['SalePrice'], df['GrLivArea']], axis=1)
data.plot.scatter(x='GrLivArea', y='SalePrice', ylim=(0,800000));

X軸をGrLivArea、Y軸をSalePriceとしてPlotしたもの

これらに引っ張られないように除去してやる。

df = df.drop(df.sort_values(by = 'GrLivArea', ascending = False)[:2]['Id'].index)
data = pd.concat([df['SalePrice'], df['GrLivArea']], axis=1)
data.plot.scatter(x='GrLivArea', y='SalePrice', ylim=(0,800000));