AI競馬で回収率100%越えを目指して

はなむけ競馬場

python プログラム

【1日目】Stacked Regressions to predict House Prices 写経

投稿日:

Stacked Regressions to predict House Pricesの写経をする。

前回の同コンペのNotebookを写経し終えたので、次にVoteが多いものを選出。

住宅の価格を予測するコンペ。

モデリングまで行う。Stackingを最終的にしてくれるので楽しみ。

EDAを行う

前のNotebook同様にデータがどうなっているのか把握する。
ここでも、目的変数と説明変数を散布にして、どう分布しているのか確認する。


import pandas as np
import seaborn as sns
%matplotlib inline
import matplotlib.pyplot as plt  # Matlab-style plotting

train = pd.read_csv('../input/house-prices-advanced-regression-techniques/train.csv')
test = pd.read_csv('../input/house-prices-advanced-regression-techniques/test.csv')

fig,ax = plt.subplots()
ax.scatter(x=train["GrLivArea"],y=train["SalePrice"])
plt.ylabel("SalePrice",fontsize=13)
plt.xlabel("GrLivArea",fontsize=13)
plt.show()

外れ値を探す、削除する。

右側にある二点が外れ値っぽいので、削除する。


#図を見て二点を指定する

train = train.drop(train[(train['GrLivArea']>4000) & (train['SalePrice']<300000)].index)
fig,ax = plt.subplots()
ax.scatter(x=train["GrLivArea"],y=train["SalePrice"])
plt.ylabel("SalePrice",fontsize=13)
plt.xlabel("GrLivArea",fontsize=13)
plt.show()

ここで作者は今回指定したデータ以外にも、トレーニングセット内には外れ値がある可能性を説いている。

外れ値を削除することは重要であると認識しつつも、全ての外れ値を削除することは推奨していない。

なぜなら、テストデータに外れ値がある可能性があるからである。

トレーニングセットの外れ値をすべて削除することで、テストデータの外れ値を検出できなくなる。

モデルの頑健性を担保するために、ある程度の外れ値を許容すること。

 

目的変数の正規性の確認と対数変換

モデル構築には数値が正規分布に従っていることが望ましいので、目的変数がどうなっているかをヒストグラムで把握する。

from scipy.stats import norm, skew #for some statistics</pre>
sns.distplot(train["SalePrice"],fit=norm)

(mu,sigma) = norm.fit(train["SalePrice"])

#平均と分散
print("mu = {:.2f} and sigma = {:.2f}".format(mu,sigma))

#Now plot the distribution
plt.legend(['Normal dist. ($\mu=$ {:.2f} and $\sigma=$ {:.2f} )'.format(mu, sigma)], loc='best')
plt.ylabel('Frequency')
plt.title('SalePrice distribution')

#正規確率プロット
fig = plt.figure()
res = stats.probplot(train["SalePrice"],plot=plt)
plt.show()

#結果的に尖度の高い表となる
#モデルは基本的に正規分布が好まれるので、ばらついたデータを正規化する作業が必要となる
<pre>
ヒストグラムでも正規確率分布でも、正規分布に従っているようには見えないので、目的変数を対数に変換する。

対数変換にただのlog(x)ではなく、log(x+1)にできるnp.log1p()を利用する。



import numpy as np
#対数変換
all_data["PoolQC"] = all_data["PoolQC"].fillna("None")

#確認
sns.distplot(train["SalePrice"],fit=norm)

#正規確率プロット
fig = plt.figure()
res = stats.probplot(train["SalePrice"],plot=plt)
plt.show()

対数による変換で正規分布に従うようになった。

 

特徴量を把握する - 欠損値の補完

前回のNotebookでは、全体の数字が15%以上かけている場合は、その特徴量自体がなかったように削除するというものだった。

一方でこちらの作者は、基本的に残すように取り扱っている。

欠損値であることを他の意味で言い換えて、データを残すようにしている。

カテゴリ変数 - 欠損していることをNoneとする

PoolQCは家にプールがあることを示したデータ。これについては99%が欠損値となっていて、大半の家にはプールがないことを示している。

つまり、空白の箇所をNoneと埋めれば、特に問題なく使えるデータとなる。


all_data["PoolQC"] = all_data["PoolQC"].fillna("None")

 

 

数値データ - 最頻値で埋める(groupbyを利用)

LotFrontageは家に接する道の広さ?的なデータで、ところどころ欠損値がある。

道の広さは微妙に分からないが、近所の家の同LotFrontageの最頻値を用いることで代用した。

all_data["LotFrontage"] = all_data.groupby("Neighborhood")["LotFrontage"].transform(lambda x: x.fillna(x.median()))

数値データ - 0で埋める

シンプルに0で埋める。他の意味があれば、その他の数字で埋めたりすると思う。

for col in ('GarageYrBlt', 'GarageArea', 'GarageCars'):
    all_data[col] = all_data[col].fillna(0)

 

数値データ - 最頻値で埋める(modeを利用)

gourpbyで集計はせず、そのままmodeを使って最頻値を使う。


all_data["MSZoning"] = all_data.fillna(all_data["MSZoning"].mode()[0])

カテゴリ変数- 特定の文字列で埋める

Noneを意味する他の文字がある場合は、Noneを使わずにその文字列で代用する。


all_data["Functional"] = all_data["Functional"].fillna("Typ")

 

数値データをカテゴリ変数に変換する

数字データであるが、カテゴリ変数としての役割がある藻については、文字列に変換する。

100,1000,10000しかない数字データがあれば、もはや三種類の文字列とみなしたほうが良いという考え。


#astpye(str) or apply(str)で文字列に変換

all_data["MSSubClass"] = all_data["MSSubClass"].astype(str)
#Changing OverallCond into a categorical variable
all_data['OverallCond'] = all_data['OverallCond'].astype(str)

#Year and month sold are transformed into categorical features.
all_data['YrSold'] = all_data['YrSold'].astype(str)
all_data['MoSold'] = all_data['MoSold'].astype(str)

 

順序の意味を含んだデータはLabel encodingする

データ内に順序(例えば5が一番よく、1が一番悪いなど)の意味を含んだカテゴリ変数があれば、Label encodingする。

&amp;amp;lt;/pre&amp;amp;gt;
from sklearn.preprocessing import LabelEncoder
cols = ('FireplaceQu', 'BsmtQual', 'BsmtCond', 'GarageQual', 'GarageCond',
'ExterQual', 'ExterCond','HeatingQC', 'PoolQC', 'KitchenQual', 'BsmtFinType1',
'BsmtFinType2', 'Functional', 'Fence', 'BsmtExposure', 'GarageFinish', 'LandSlope',
'LotShape', 'PavedDrive', 'Street', 'Alley', 'CentralAir', 'MSSubClass', 'OverallCond',
'YrSold', 'MoSold')

for c in cols:
lbl = LabelEncoder()
lbl.fit(list(all_data.values))
all_data = lbl.transform(list(all_data.values))

 

 

正規分布していない数値データを対数変換する(boxcox変換)

目的変数だけでなく、説明変数も正規分布が望ましいはずなので、対数変換をする。

その際Boxcox変換を行う。

その前に、正規分布していない数字データを取得するために尖度を計算する。

 

#数字データの特定</pre>
numeric_feats = all_data.dtypes[all_data.dtypes != "object"].index

skewed_feat = all_data[numeric_feats].apply(lambda x: skew(x.dropna())).sort_values(ascending=False)

skewness = pd.DataFrame({"Skew":skewed_feat})
<pre>skewness.head()

 

Skew
MiscVal 21.940
PoolArea 17.689
LotArea 13.109
LowQualFinSF 12.085
3SsnPorch 11.372

boxcox変換は無理やり正規分布に変換するものであるが、負の値がある場合は行うことができない。 負の値があるときはYeo-Johnson変換というのを行う。   また、引数としてラムダが必要であるが、自動で出してくれる機能もあるらしい。作者はlam = 0.15で指定しているが。

#尖度が0.75以上のものを指定している。</pre>
skewness = skewness[abs(skewness) > 0.75]

from scipy.special import boxcox1p

skewed_features = skewness.index
lam = 0.15
for feat in skewd_features:
all_data[feat] = boxcox1p(all_data[feat,lam])
<pre>
 

以上の返還で、全ての数字データが正規分布になり、解析によい結果を与える……らしい。

-python, プログラム

Copyright© はなむけ競馬場 , 2021 All Rights Reserved Powered by AFFINGER5.