自分のキャリアをあれこれ考えながら、Pythonで様々なデータを分析していくブログです

(その4-2) エイムズの住宅価格を重回帰分析で予測してみた

Data Analytics
Data Analytics

今回はみんな大好き重回帰分析を行いと思います。

結果が分かりやすく企画側のメンバーにも説明しやすいので私は好んで使っています。

精度はXgBoostなどのアルゴリズムには敵わないと思いますが、係数や切片さえ出してしまえばシステムにも組み込みやすく(SQLだけでもスコアが出せる)、結果の解釈のしやすいとても優秀な手法だと思います。

スポンサーリンク

評価指標

住宅IdごとのSalePrice(販売価格)を予測するコンペです。

評価指標は予測SalePriceと実測SalePriceの対数を取ったRoot-Mean-Squared-Error(RMSE)の値のようです。

House Prices - Advanced Regression Techniques | Kaggle
Predict sales prices and practice feature engineering, RFs, and gradient boosting
スポンサーリンク

重回帰分析

分析用データの準備

事前に欠損値処理や特徴量エンジニアリングを実施してデータをエクスポートしています。

本記事と同じ結果にするためには事前に下記記事を確認してデータを用意してください。

(その3-2) エイムズの住宅価格のデータセットのデータ加工①

(その3-3) エイムズの住宅価格のデータセットのデータ加工②

学習用データとスコア付与用データの読み込み

import pandas as pd
import numpy as np
# エイムズの住宅価格のデータセットの訓練データとテストデータを読み込む
df = pd.read_csv("/Users/hinomaruc/Desktop/blog/dataset/ames/ames_train.csv")
df_test = pd.read_csv("/Users/hinomaruc/Desktop/blog/dataset/ames/ames_test.csv")
df.head()
Out[0]

Id LotFrontage LotArea LotShape Utilities LandSlope OverallQual OverallCond MasVnrArea ExterCond ... SaleType_New SaleType_Oth SaleType_WD SaleCondition_Abnorml SaleCondition_AdjLand SaleCondition_Alloca SaleCondition_Family SaleCondition_Normal SaleCondition_Partial SalePrice
0 1 65.0 8450 3.0 3.0 2.0 7 5 196.0 2.0 ... 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 208500
1 2 80.0 9600 3.0 3.0 2.0 6 8 0.0 2.0 ... 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 181500
2 3 68.0 11250 2.0 3.0 2.0 7 5 162.0 2.0 ... 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 223500
3 4 60.0 9550 2.0 3.0 2.0 7 5 0.0 2.0 ... 0.0 0.0 1.0 1.0 0.0 0.0 0.0 0.0 0.0 140000
4 5 84.0 14260 2.0 3.0 2.0 8 5 350.0 2.0 ... 0.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 250000

5 rows × 335 columns

# 描画設定
from IPython.display import HTML
import seaborn as sns
from matplotlib import ticker
import matplotlib.pyplot as plt
sns.set_style("whitegrid")
from matplotlib import rcParams
rcParams['font.family'] = 'Hiragino Sans' # Macの場合
#rcParams['font.family'] = 'Meiryo' # Windowsの場合
#rcParams['font.family'] = 'VL PGothic' # Linuxの場合
rcParams['xtick.labelsize'] = 12       # x軸のラベルのフォントサイズ
rcParams['ytick.labelsize'] = 12       # y軸のラベルのフォントサイズ
rcParams['axes.labelsize'] = 18        # ラベルのフォントとサイズ
rcParams['figure.figsize'] = 18,8      # 画像サイズの変更(inch)

重回帰に使用する変数を選ぶ

ステップワイズ法など色々方法はありますが、今回も前回の単回帰分析のときと同じ目的変数と相関が高い変数を選びたいと思います。

エイムズのデータセットの相関係数を色々なパターンで確認した結果がありますので、詳細は(その3-3) エイムズの住宅価格のデータセットのデータ加工②をご参照ください。

SalePriceとNeighborhood、YearBuiltがそこそこ高い値になっていますが、これはNeighborhoodもしくはYearBuiltごとにSalePriceに違いがありそうという意味になるのではないかと思っています。

SalePriceとの相関比が高かったNeighborhoodを説明変数に採用しようと思います。(地理的情報も欲しいので)

後は相関係数がSalePriceと高かった下記変数も採用します。

'TotalLivArea'
,'OverallQual'
,'TotalBathRms'
,'GarageCars'
,'BsmtQual'
,'FullBath'
,'GarageFinish'
,'FireplaceQu'
,'TotRmsAbvGrd'

重回帰で学習を実施

# 説明変数
ana_cols=[
  'TotalLivArea'
, 'OverallQual'
, 'TotalBathRms'
, 'GarageCars'
, 'BsmtQual'
, 'FullBath'
, 'GarageFinish'
, 'FireplaceQu'
, 'TotRmsAbvGrd'
#, 'Neighborhood_Blmngtn' avoid multi-correlation
, 'Neighborhood_Blueste'
, 'Neighborhood_BrDale'
, 'Neighborhood_BrkSide'
, 'Neighborhood_ClearCr'
, 'Neighborhood_CollgCr'
, 'Neighborhood_Crawfor'
, 'Neighborhood_Edwards'
, 'Neighborhood_Gilbert'
, 'Neighborhood_IDOTRR'
, 'Neighborhood_MeadowV'
, 'Neighborhood_Mitchel'
, 'Neighborhood_NAmes'
, 'Neighborhood_NPkVill'
, 'Neighborhood_NWAmes'
, 'Neighborhood_NoRidge'
, 'Neighborhood_NridgHt'
, 'Neighborhood_OldTown'
, 'Neighborhood_SWISU'
, 'Neighborhood_Sawyer'
, 'Neighborhood_SawyerW'
, 'Neighborhood_Somerst'
, 'Neighborhood_StoneBr'
, 'Neighborhood_Timber'
, 'Neighborhood_Veenker'
]
# 説明変数と目的変数を指定
X_train = df[ana_cols]
Y_train = df["SalePrice"] # 販売価格
# pipelineでデータを標準化してモデリングをする
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LinearRegression
pipeline = make_pipeline(StandardScaler(), LinearRegression())

# fitする
fit_pipeline = pipeline.fit(X_train,Y_train)
# モデルパラメータ一覧
fit_pipeline.get_params()
Out[0]

    {'memory': None,
     'steps': [('standardscaler', StandardScaler()),
      ('linearregression', LinearRegression())],
     'verbose': False,
     'standardscaler': StandardScaler(),
     'linearregression': LinearRegression(),
     'standardscaler__copy': True,
     'standardscaler__with_mean': True,
     'standardscaler__with_std': True,
     'linearregression__copy_X': True,
     'linearregression__fit_intercept': True,
     'linearregression__n_jobs': None,
     'linearregression__normalize': 'deprecated',
     'linearregression__positive': False}

# stepsから重回帰モデルの部分を抽出
model_pipeline = fit_pipeline.named_steps["linearregression"] # or pipeline.steps[1][1]
# モデル部分のパラメーターを確認。
model_pipeline.get_params()
Out[0]

    {'copy_X': True,
     'fit_intercept': True,
     'n_jobs': None,
     'normalize': 'deprecated',
     'positive': False}

重回帰結果の確認

# 説明変数の係数を確認
coef = pd.DataFrame()
coef["features"] = fit_pipeline.feature_names_in_
coef["coef"] = model_pipeline.coef_
coef["coef_pct"] = np.abs(coef["coef"]) / np.abs(coef["coef"]).sum()
HTML(coef.sort_values(by="coef_pct",ascending=False).to_html())
Out[0]

features coef coef_pct
0 TotalLivArea 22464.525511 0.125844
1 OverallQual 20364.588506 0.114080
24 Neighborhood_NridgHt 15854.404547 0.088815
23 Neighborhood_NoRidge 12645.355971 0.070838
30 Neighborhood_StoneBr 9725.537216 0.054482
2 TotalBathRms 8839.926197 0.049520
3 GarageCars 8204.538135 0.045961
29 Neighborhood_Somerst 7360.293267 0.041232
14 Neighborhood_Crawfor 7178.199611 0.040212
13 Neighborhood_CollgCr 7132.226311 0.039954
12 Neighborhood_ClearCr 5229.469167 0.029295
31 Neighborhood_Timber 5088.466379 0.028505
20 Neighborhood_NAmes 4797.936931 0.026878
7 FireplaceQu 4376.854466 0.024519
8 TotRmsAbvGrd 4363.487602 0.024444
32 Neighborhood_Veenker 4050.878743 0.022693
11 Neighborhood_BrkSide 3871.312478 0.021687
6 GarageFinish 3642.730978 0.020406
27 Neighborhood_Sawyer 3268.357349 0.018309
28 Neighborhood_SawyerW 3242.540578 0.018164
19 Neighborhood_Mitchel 2443.801094 0.013690
16 Neighborhood_Gilbert 2401.716704 0.013454
4 BsmtQual 2280.411070 0.012775
15 Neighborhood_Edwards 2089.149708 0.011703
5 FullBath -1415.309722 0.007928
22 Neighborhood_NWAmes 1182.566236 0.006625
10 Neighborhood_BrDale -908.328878 0.005088
25 Neighborhood_OldTown 895.071543 0.005014
17 Neighborhood_IDOTRR 882.738396 0.004945
9 Neighborhood_Blueste -771.641440 0.004323
21 Neighborhood_NPkVill -638.344959 0.003576
18 Neighborhood_MeadowV 530.240067 0.002970
26 Neighborhood_SWISU 369.783933 0.002071
model_pipeline.intercept_
Out[0]

    180921.19589041095

TotalLivAreaとOverallQualのモデルへの寄与度が高くなっているので想定通りです。

モデルを適用し、SalePriceの予測をする

df_test["SalePrice"] = fit_pipeline.predict(df_test[ana_cols])
df_test[["Id","SalePrice"]]
Out[0]

Id SalePrice
0 1461 101790.595660
1 1462 152801.604799
2 1463 168658.886147
3 1464 185152.822065
4 1465 253677.152032
... ... ...
1454 2915 69415.163313
1455 2916 87164.482335
1456 2917 153543.604803
1457 2918 104717.547211
1458 2919 232089.359360

1459 rows × 2 columns

予測できていそうです。

スポンサーリンク

Kaggleにスコア付与結果をアップロード

df_test[["Id","SalePrice"]].to_csv("ames_submission.csv",index=False)
!/Users/hinomaruc/Desktop/blog/my-venv/bin/kaggle competitions submit -c house-prices-advanced-regression-techniques -f ames_submission.csv -m "#2 multiple regression"
Out[0]

    100%|██████████████████████████████████████| 33.6k/33.6k [00:03<00:00, 9.90kB/s]
    Successfully submitted to House Prices - Advanced Regression Techniques
Out[0]
#2 multiple regression
0.21305

単回帰より若干スコアが向上しました。

スポンサーリンク

使用ライブラリのバージョン

pandas Version: 1.4.3
numpy Version: 1.22.4
scikit-learn Version: 1.1.1
seaborn Version: 0.11.2
matplotlib Version: 3.5.2

スポンサーリンク

まとめ

それほど劇的に精度が良くなるということはありませんでした。

説明変数の組み合わせを変えることによってもう少し精度は上がるかも知れませんが、他のモデルを試してみようと思います。

次は多項式回帰を試してみようと思います。多項式回帰は欠損値を推定するのに実業務で使ったことがあります。

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