kaggle House Pricesをやってみる(データの可視化)

住宅の価格予測コンペ。

概要は以下
https://trueman-developer.blogspot.com/2019/08/kaggle-house-prices.html


その他の初心者向けコンペは以下
タイタニック生存予測
https://trueman-developer.blogspot.com/2019/07/keras.html

手書き画像認識
https://trueman-developer.blogspot.com/2019/07/kaggle-digit-recognizer-keras.html





データの確認



データのタイプや欠損値などを確認する。

https://github.com/ninomae-makoto/kaggle/blob/master/house-prices_visualize.ipynb
がソースコードだがいろいろ描画しているせいかエラーになって確認できない。クローンしてJupyterで確認を推奨。

import pandas as pd

# データ読み込み
origin_train = pd.read_csv("./data/house-prices-advanced-regression-techniques/train.csv")

origin_train.info()
print("-------------------------------------------")
print(origin_train.isnull().sum())
print("-------------------------------------------")
print(origin_train.isnull().sum())
print("-------------------------------------------")


NA の項目については欠損値として扱われるようだようだ。




SalesPriceとの関連をグラフで表示




import matplotlib.pyplot as plt
corrmat = origin_train.corr()
f, ax = plt.subplots(figsize=(12, 9))
sns.heatmap(corrmat, vmax=.8, square=True)

heatmap



データの分布確認 分類ごとに分かれている項目



import seaborn as sns
sns.countplot(x='Exterior2nd', data = origin_train)

xに列名を指定すれば様々なデータが確認できる。

棒グラフ


データの分布確認 数値を持つ項目



import seaborn as sns
train2 = origin_train.copy()
test2 = origin_test.copy()

sns.distplot(train2.LotArea.dropna())

LotAreaを任意の列名に変更すれば様々なデータが確認できる。

グラフ




欠損値について



以上からそれぞれの列の取り扱いを決める。

MSZoning
RLで埋める。
Cではなく"C (all)"のようだ。

LotFrontage
中央値で埋める。

Alley
別途値を設定する。

Neighborhood
NAmesという想定外の値が入っている。

BldgType
Twnhs, Duplex, 2fmCon といった項目がある。
data_discriptionnの記述が誤りのようだ。

Utilities
ほぼAllPubしかない(流石に電気ガス水道どれか欠けてる物件はまずないだろう)
除外する。

Exterior1st
VinylSdで埋める。

Exterior2nd
VinylSdで埋める。
"Wd Shng", CmentBd, Cmn, "Brk Cmn" など想定外の値が入っている。
Brk CmnはBrkCommへ寄せる。
CmentBdはCemntBdへ寄せる。
他はイマイチ判断がつかない。数があるので別途分ける。

MasVnrType
欠損があるがNoneという項目もある。
一番多いのでNoneで埋める。

MasVnrArea
数値だが0が多く平均だと正しくない気がする。
0で埋める。

BsmtQual
別途値を設定する。

BsmtCond
別途値を設定する。

BsmtExposure
別途値を設定する。

BsmtFinType1
別途値を設定する。

BsmtFinSF1
0を設定する。

BsmtFinType2
別途値を設定する。

BsmtFinSF2
0を設定する。

BsmtUnfSF
0が多いが全体的に分布しているため中央値を設定。
他の項目によって0になる条件があるはずだがどう処理していいかわからない。

TotalBsmtSF
中央値を設定。
こっちがあればBsmtUnfSFはいらないような気がするが。

Electrical
SBrkrで埋める。
9割程度SBrkrなので除外するか微妙なライン。

BsmtFullBath
ほとんど0か1で0が多い。
0を設定する。

BsmtHalfBath
ほとんど0か1で0が多い。
0を設定する。

KitchenQual
TAで埋める。

Functional
Typで埋める。

FireplaceQu
別途値を設定する。

GarageType
別途値を設定する。

GarageYrBlt
「車庫が何年に建てられたか」なので少しずつ増えていくものと考えられるが1980年代ごろのデータだけが異様に少ない。
何かあったのか。
0で埋める。本当はGarageTypeがNaNだったら0それ以外は平均値としたほうがいいのだろうが処理するのが面倒。
またテストデータに未来の年が入っている。これはあからさまにエラー。
1132番目のデータが2207年になっている。テストデータを消すわけにもいかないので平均値で置き換える。

GarageFinish
別途値を設定する。

GarageCars
「何台車が入るか」らしい。0~4.
欠損値はテストデータ1件なのでデータを直接確認する。
test2[test2['GarageCars'].isnull()]
1116行目,Id2577
おそらく車庫がない。0を設定する。

GarageArea
上記と同じデータが欠損している
0を設定する。

GarageQual
別途値を設定する。

GarageCond
別途値を設定する。

PoolQC
別途値を設定する。

Fence
別途値を設定する。

MiscFeature
別途値を設定する。

SaleType
1件のみ欠損。
判断方法がわからないので一番多いWDで埋める。


以下対応まとめ
これで良いかは専門家でないので自身がない。

A. 平均値を設定。
B. もっとも多い項目を設定。
C. 0を設定。
D. データごと削除。
E. 別途値を設定。
F. 対象外
G. 個別に処理

### train
- A LotFrontage 259
- E Alley 1369
- B MasVnrType 8
- C MasVnrArea 8
- B BsmtQual 37
- E BsmtCond 37
- E BsmtExposure 38
- E BsmtFinType1 37
- E BsmtFinType2 38
- B Electrical 1
- E FireplaceQu 690
- E GarageType 81
- C GarageYrBlt 81
- C GarageFinish 81
- E GarageQual 81
- E GarageCond 81
- E PoolQC 1453
- E Fence 1179
- E MiscFeature 1406

### test
- B MSZoning 4
- A LotFrontage 227
- E Alley 1352
- F Utilities 2
- B Exterior1st 1
- B Exterior2nd 1
- B MasVnrType 16
- C MasVnrArea 15
- B BsmtQual 44
- E BsmtCond 45
- E BsmtExposure 44
- E BsmtFinType1 42
- C BsmtFinSF1 1
- E BsmtFinType2 42
- C BsmtFinSF2 1
- A BsmtUnfSF 1
- A TotalBsmtSF 1
- B BsmtFullBath 2
- B BsmtHalfBath 2
- B KitchenQual 1
- B Functional 2
- E FireplaceQu 730
- E GarageType 76
- CG GarageYrBlt 78
- CG GarageFinish 78
- G GarageCars 1
- G GarageArea 1
- E GarageQual 78
- E GarageCond 78
- E PoolQC 1456
- E Fence 1169
- E MiscFeature 1408
- B SaleType 1

以下のようなソースコードになる(ボリュームがあるのでtrainのみ)

train = origin_train.copy()
test = origin_test.copy()

del train['Id']
del train['Utilities']

del test['Id']
del test['Utilities']


    
train.MSSubClass = train.MSSubClass.replace([20, 30, 40, 45, 50, 60, 70, 75, 80, 85, 90, 120, 150, 160 , 180, 190], [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15])
train.MSZoning = train.MSZoning.replace(['A', 'C (all)', 'FV', 'I', 'RH', 'RL', 'RP', 'RM'], [0, 1, 2, 3, 4, 5, 6, 7])
train.LotFrontage = train.LotFrontage.fillna(train.LotFrontage.median())
train.Street = train.Street.replace(['Grvl', 'Pave'], [0, 1])
train.Alley = train.Alley.fillna('NA').replace(['Grvl', 'Pave', 'NA'], [0, 1, 2])
train.LotShape = train.LotShape.replace(['Reg', 'IR1', 'IR2', 'IR3'], [0, 1, 2, 3])
train.LandContour = train.LandContour.replace(['Lvl', 'Bnk', 'HLS', 'Low'], [0, 1, 2, 3])
train.LotConfig = train.LotConfig.replace(['Inside', 'Corner', 'CulDSac', 'FR2', 'FR3'], [0, 1, 2, 3, 4])
train.LandSlope = train.LandSlope.replace(['Gtl', 'Mod', 'Sev'], [0, 1, 2])
train.Neighborhood = train.Neighborhood.replace(
    ['Blmngtn', 'Blueste', 'BrDale', 'BrkSide', 'ClearCr', 'CollgCr', 'Crawfor', 'Edwards', 'Gilbert', 'IDOTRR', 'MeadowV', 'Mitchel', 'Names', 'NoRidge', 'NPkVill', 'NridgHt', 'NWAmes', 'OldTown', 'SWISU', 'Sawyer', 'SawyerW', 'Somerst', 'StoneBr', 'Timber', 'Veenker', 'NAmes'],
    [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25])
train.Condition1 = train.Condition1.replace(['Artery', 'Feedr', 'Norm', 'RRNn', 'RRAn', 'PosN', 'PosA', 'RRNe', 'RRAe'], [0, 1, 2, 3, 4, 5, 6, 7, 8])
train.Condition2 = train.Condition2.replace(['Artery', 'Feedr', 'Norm', 'RRNn', 'RRAn', 'PosN', 'PosA', 'RRNe', 'RRAe'], [0, 1, 2, 3, 4, 5, 6, 7, 8])
train.BldgType = train.BldgType.replace(['1Fam', '2fmCon', 'Duplex', 'Twnhs', 'TwnhsE'], [0, 1, 2, 3, 4])
train.HouseStyle = train.HouseStyle.replace(['1Story', '1.5Fin', '1.5Unf', '2Story', '2.5Fin', '2.5Unf', 'SFoyer', 'SLvl'], [0, 1, 2, 3, 4, 5, 6, 7])
train.RoofStyle = train.RoofStyle.replace(['Flat', 'Gable', 'Gambrel', 'Hip', 'Mansard', 'Shed'], [0, 1, 2, 3, 4, 5])
train.RoofMatl = train.RoofMatl.replace(['ClyTile', 'CompShg', 'Membran', 'Metal', 'Roll', 'Tar&Grv', 'WdShake', 'WdShngl'], [0, 1, 2, 3, 4, 5, 6, 7])
train.Exterior1st = train.Exterior1st.replace(
    ['AsbShng', 'AsphShn', 'BrkComm', 'BrkFace', 'CBlock', 'CemntBd', 'HdBoard', 'ImStucc', 'MetalSd', 'Other', 'Plywood', 'PreCast', 'Stone', 'Stucco', 'VinylSd', 'Wd Sdng', 'WdShing'], 
    [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16])
train.Exterior2nd = train.Exterior2nd.replace(['Brk Cmn', 'CmentBd'], ['BrkComm', 'CemntBd']).replace(
    ['AsbShng', 'AsphShn', 'BrkComm', 'BrkFace', 'CBlock', 'CemntBd', 'HdBoard', 'ImStucc', 'MetalSd', 'Other', 'Plywood', 'PreCast', 'Stone', 'Stucco', 'VinylSd', 'Wd Sdng', 'WdShing', 'Wd Shng', 'CmentBd', 'Cmn'], 
    [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19])
train.MasVnrType = train.MasVnrType.fillna('None').replace(['BrkCmn', 'BrkFace', 'CBlock', 'None', 'Stone'], [0, 1, 2, 3, 4])
train.MasVnrArea = train.MasVnrArea.fillna(0)
train.ExterQual = train.ExterQual.replace(['Ex', 'Gd', 'TA', 'Fa', 'Po'], [0, 1, 2, 3, 4])
train.ExterCond = train.ExterCond.replace(['Ex', 'Gd', 'TA', 'Fa', 'Po'], [0, 1, 2, 3, 4])
train.Foundation = train.Foundation.replace(['BrkTil', 'CBlock', 'PConc', 'Slab', 'Stone', 'Wood'], [0, 1, 2, 3, 4, 5])
train.BsmtQual = train.BsmtQual.fillna('NA').replace(['Ex', 'Gd', 'TA', 'Fa', 'Po', 'NA'], [0, 1, 2, 3, 4, 5])
train.BsmtCond = train.BsmtCond.fillna('NA').replace(['Ex', 'Gd', 'TA', 'Fa', 'Po', 'NA'], [0, 1, 2, 3, 4, 5])
train.BsmtExposure = train.BsmtExposure.fillna('NA').replace(['Gd', 'Av', 'Mn', 'No', 'NA'], [0, 1, 2, 3, 4])
train.BsmtFinType1 = train.BsmtFinType1.fillna('NA').replace(['GLQ', 'ALQ', 'BLQ', 'Rec', 'LwQ', 'Unf', 'NA'], [0, 1, 2, 3, 4, 5, 6])
train.BsmtFinType2 = train.BsmtFinType2.fillna('NA').replace(['GLQ', 'ALQ', 'BLQ', 'Rec', 'LwQ', 'Unf', 'NA'], [0, 1, 2, 3, 4, 5, 6])
train.Heating = train.Heating.replace(['Floor', 'GasA', 'GasW', 'Grav', 'OthW', 'Wall'], [0, 1, 2, 3, 4, 5])
train.HeatingQC = train.HeatingQC.replace(['Ex', 'Gd', 'TA', 'Fa', 'Po'], [0, 1, 2, 3, 4])
train.CentralAir = train.CentralAir.replace(['N', 'Y'], [0, 1])
train.Electrical = train.Electrical.fillna('SBrkr')
train.Electrical = train.Electrical.replace(['SBrkr', 'FuseA', 'FuseF', 'FuseP', 'Mix'], [0, 1, 2, 3, 4])
train.KitchenQual = train.KitchenQual.replace(['Ex', 'Gd', 'TA', 'Fa', 'Po'], [0, 1, 2, 3, 4])
train.Functional = train.Functional.replace(['Typ', 'Min1', 'Min2', 'Mod', 'Maj1', 'Maj2', 'Sev', 'Sal'], [0, 1, 2, 3, 4, 5, 6, 7])
train.FireplaceQu = train.FireplaceQu.fillna('NA').replace(['Ex', 'Gd', 'TA', 'Fa', 'Po', 'NA'], [0, 1, 2, 3, 4, 5])
train.GarageType = train.GarageType.fillna('NA').replace(['2Types', 'Attchd', 'Basment', 'BuiltIn', 'CarPort', 'Detchd', 'NA'], [0, 1, 2, 3, 4, 5, 6])
train.GarageYrBlt = train.GarageYrBlt.fillna(0)
train.GarageFinish = train.GarageFinish.fillna('NA').replace(['Fin', 'RFn', 'Unf', 'NA'], [0, 1, 2, 3])
train.GarageQual = train.GarageQual.fillna('NA').replace(['Ex', 'Gd', 'TA', 'Fa', 'Po', 'NA'], [0, 1, 2, 3, 4, 5])
train.GarageCond = train.GarageCond.fillna('NA').replace(['Ex', 'Gd', 'TA', 'Fa', 'Po', 'NA'], [0, 1, 2, 3, 4, 5])
train.PavedDrive = train.PavedDrive.replace(['Y', 'P', 'N'], [0, 1, 2])
train.PoolQC = train.PoolQC.fillna('NA').replace(['Ex', 'Gd', 'TA', 'Fa', 'NA'], [0, 1, 2, 3, 4])
train.Fence = train.Fence.fillna('NA').replace(['GdPrv', 'MnPrv', 'GdWo', 'MnWw', 'NA'], [0, 1, 2, 3, 4])
train.MiscFeature = train.MiscFeature.fillna('NA').replace(['Elev', 'Gar2', 'Othr', 'Shed', 'TenC', 'NA'], [0, 1, 2, 3, 4, 5])
train.SaleType = train.SaleType.replace(['WD', 'CWD', 'VWD', 'New', 'COD', 'Con', 'ConLw', 'ConLI', 'ConLD', 'Oth'], [0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
train.SaleCondition = train.SaleCondition.replace(['Normal', 'Abnorml', 'AdjLand', 'Alloca', 'Family', 'Partial'], [0, 1, 2, 3, 4, 5])




SalsPriceと関連が大きい項目を抽出



import matplotlib.pyplot as plt
corrmat = train.corr()
# 関連が大きい順に
k = 21 #number of variables for heatmap
cols = corrmat.nlargest(k, 'SalePrice')['SalePrice'].index
cm = np.corrcoef(train[cols].values.T)
sns.set(font_scale=1.25)
plt.figure(figsize=(15, 15))
hm = sns.heatmap(cm, cbar=True, annot=True, square=True, fmt='.2f', annot_kws={'size': 10}, yticklabels=cols.values, xticklabels=cols.values)
plt.show()
cols

heatmap


上記は欠損値などを補正した後の上位20項目(上位10項目なら未加工と変わらない)

['SalePrice', 'OverallQual', 'GrLivArea', 'GarageCars', 'GarageArea',
'TotalBsmtSF', '1stFlrSF', 'FullBath', 'TotRmsAbvGrd', 'YearBuilt',
'YearRemodAdd', 'MasVnrArea', 'Fireplaces', 'BsmtFinSF1', 'Foundation',
'LotFrontage', 'WoodDeckSF', '2ndFlrSF', 'OpenPorchSF', 'SaleCondition',
'HalfBath']
を使用することにする。




今回は1つずつ見ていったが面倒なので自動である程度イイ感じなるようにしておきたい。


2019年8月8日木曜日