Masser’s Blog

データサイエンティスト/Kaggle/Python/ADHD/旅行/サンフレ 等語る予定。

KaggleのHouse Pricesに挑戦 その1

今回kaggleの初心者向き課題の一つであるHousingPriceに挑戦しました。とはいいつつも項目数が70以上もあり、参加している人もレベルがかなり高いので前回挑戦したタイタニックに比べればはるかに難しいです。

HousingPriceとは

米国アイオワ州のエイムズという都市の物件価格を予測する問題となります。データは、”築年数”、”設備”、”広さ”、”エリア”、”ガレージに入る車の数”など79個の項目数および1460戸の学習データが与えられます。そのデータをもとに、残りの1459戸の家の価格を予測します。

はじめに

今回課題を取り組むにあたって以下のkernel、ブログを参考にしました。

Stacked Regressions : Top 4% on LeaderBoard | Kaggle

こちらのリンクでは欠損値の埋め方等を参考にしました。

KaggleのHousePrices問題を決定木系のアンサンブルで解く - mirandora.commirandora.com

機械学習3ヶ月の初心者がKaggleHousingPriceに挑戦した(Top29%) 前半 - Qiita

Kaggleの練習問題(Regression)を解いてKagglerになる - Qiita

こちらのサイトではどのアルゴリズムを採用するか、また特徴量の考え方、抽出について非常に参考になりました。

価格の分析

まずそもそもアイオワのエイムズに関して知識もないし、価格も全く分からないので、まずは価格帯についてどうなのか調べました。

train = pd.read_csv('train.csv')
test = pd.read_csv('test.csv')
train['SalePrice'].describe()

count      1460.000000
mean     180921.195890
std       79442.502883
min       34900.000000
25%      129975.000000
50%      163000.000000
75%      214000.000000
max      755000.000000
Name: SalePrice, dtype: float64
sns.distplot(train['SalePrice']);

f:id:masser199:20180222063254p:plain

正規分布になってないので、logを使用して一時的に正規分布になるように変換します。

train_ID = train['Id']
test_ID = test['Id']
y_train = train['SalePrice']
X_train = train.drop(['Id','SalePrice'], axis=1)
X_test = test.drop('Id', axis=1)
ntrain = X_train.shape[0]
ntest = X_test.shape[0]
Xmat = pd.concat((X_train,X_test))
y_train = np.log(y_train)
sns.distplot(y_train);

f:id:masser199:20180222063731p:plain

これで正規分布になりました。もちろん最後には戻す必要があります。

欠損値について

次にデータの中に欠損値があるかどうか調べます。

Xmat_na = (Xmat.isnull().sum() / len(Xmat)) * 100
Xmat_na = Xmat_na.drop(Xmat_na[Xmat_na == 0].index).sort_values(ascending=False)[:30]
Xmat_na_missing_data = pd.DataFrame({'Missing Ratio' :Xmat_na})
Xmat_na_missing_data
Missing Ratio
PoolQC 99.657417
MiscFeature 96.402878
Alley 93.216855
Fence 80.438506
FireplaceQu 48.646797
LotFrontage 16.649538
GarageFinish 5.447071
GarageYrBlt 5.447071
GarageQual 5.447071
GarageCond 5.447071
GarageType 5.378554
BsmtExposure 2.809181
BsmtCond 2.809181
BsmtQual 2.774923
BsmtFinType2 2.740665
BsmtFinType1 2.706406
MasVnrType 0.822199
MasVnrArea 0.787941
MSZoning 0.137033
BsmtFullBath 0.068517
BsmtHalfBath 0.068517
Utilities 0.068517
Functional 0.068517
Exterior2nd 0.034258
Exterior1st 0.034258
SaleType 0.034258
BsmtFinSF1 0.034258
BsmtFinSF2 0.034258
BsmtUnfSF 0.034258
Electrical 0.034258

ここから欠損値がある項目から数値0、文字の場合はNONEを入れます。一部のみ処理を記載します。

for col in ('BsmtFinSF1', 'BsmtFinSF2', 'BsmtUnfSF','TotalBsmtSF', 'BsmtFullBath', 'BsmtHalfBath'):
    Xmat[col] = Xmat[col].fillna(0)
for col in ('BsmtQual', 'BsmtCond', 'BsmtExposure', 'BsmtFinType1', 'BsmtFinType2'):
    Xmat[col] = Xmat[col].fillna('None')

また、Utilitiesの項目はほぼAllPubであり特徴量の解析に寄与しないため削除します。

Xmat = Xmat.drop(['Utilities'], axis=1)

そしてラベルコンバーターよりすべての値を実数にします。

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', 'MSZoning', 'LandContour', 'LotConfig', 'Neighborhood', 'Condition1',
       'Condition2', 'BldgType', 'HouseStyle', 'RoofStyle', 'RoofMatl',
       'Exterior1st', 'Exterior2nd', 'MasVnrType', 'Foundation', 'Heating',
       'Electrical', 'GarageType', 'MiscFeature', 'SaleType', 'SaleCondition')

for c in cols:
    lbl = LabelEncoder() 
    lbl.fit(list(Xmat[c].values)) 
    Xmat[c] = lbl.transform(list(Xmat[c].values))

データはトレーニングデータ、テストデータ含めて加工しましたが、ここでトレーニングデータ、テストデータそれぞれに戻します。

X_train_1 = Xmat[:ntrain]
X_test_1 = Xmat[ntrain:]