What is this? (これは何?)
kaggle の House Priceに取り組みます。
- 狙い
kaggleの初心者向け記事はたくさんありますが、あんまり初心者向けじゃない気がしています。(私のレベルが低すぎて...)
なので、より低レベルな内容に絞った記事(メモ)を作ろうとしました。
What is the skill of writer?(書いた人の技術力はどんなもの?)
記事を書いた人の能力は以下の通り(2021年05月16日時点)
状況が近い人は、何か参考になるものがあるかもしれません
- 学校:文系大卒
-
お仕事:WEBアプリケーションエンジニア歴満4年
その他のエンジニア経歴はなし - 言語:Python:基本的な文法は把握済み/仕事でも利用
-
数学:Ⅲ/Cを習ってない
年代が違う人のために説明すると、微分方程式や行列は習っていない、ということです(年齢がばれる...)
理系の大学を出た人には何の参考にもならないのではないかと思っています...
First step! (はじめの一歩)
0. What do you do?(何する?)
はじめの一歩は、ほぼ全く前処理せずに以下の分析フローを一通り流してみました。
- 1-1. データ取得(読み込み)
- 1-2. 学習データと検証用データの分割
- 1-3. データ整形
分析可能にするための最低限のもののみ - 1-4. モデルを学習させる
手を抜くためにXGBoostを使う - 1-5. 予測してみる
学習させたXGBoostモデルで検証用データに対する予測を行い、成績を確認 - 1-6. submit(提出)
この記事では、とりあえずここまでやりました。
前処理は、本当に何もしてないです。それでも、ものすごいつまづきました。
それでも諦めない(`・ω・´)根性
1. Source cord
1-0. import modules
今回使ったモジュールです
import numpy as np # linear algebra
import pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error
from xgboost import XGBClassifier, XGBRegressor
1-1. get data (データ取得(読み込み))
import os
for dirname, _, filenames in os.walk('/kaggle/input'):
for filename in filenames:
print(os.path.join(dirname, filename))
# kaggleなので、csvファイルがこのpathになってます
train = pd.read_csv('/kaggle/input/house-prices-advanced-regression-techniques/train.csv')
test = pd.read_csv('/kaggle/input/house-prices-advanced-regression-techniques/test.csv')
train.head()
# 処理結果
/kaggle/input/house-prices-advanced-regression-techniques/sample_submission.csv
/kaggle/input/house-prices-advanced-regression-techniques/data_description.txt
/kaggle/input/house-prices-advanced-regression-techniques/train.csv
/kaggle/input/house-prices-advanced-regression-techniques/test.csv
Id MSSubClass MSZoning LotFrontage LotArea Street Alley LotShape LandContour Utilities ... PoolArea PoolQC Fence MiscFeature MiscVal MoSold YrSold SaleType SaleCondition SalePrice
0 1 60 RL 65.0 8450 Pave NaN Reg Lvl AllPub ... 0 NaN NaN NaN 0 2 2008 WD Normal 208500
1 2 20 RL 80.0 9600 Pave NaN Reg Lvl AllPub ... 0 NaN NaN NaN 0 5 2007 WD Normal 181500
2 3 60 RL 68.0 11250 Pave NaN IR1 Lvl AllPub ... 0 NaN NaN NaN 0 9 2008 WD Normal 223500
3 4 70 RL 60.0 9550 Pave NaN IR1 Lvl AllPub ... 0 NaN NaN NaN 0 2 2006 WD Abnorml 140000
4 5 60 RL 84.0 14260 Pave NaN IR1 Lvl AllPub ... 0 NaN NaN NaN 0 12 2008 WD Normal 250000
5 rows × 81 columns
カラムはどうなってるのかな
train.columns
# 結果:こんなにたくさんカラムが...
Index(['Id', 'MSSubClass', 'MSZoning', 'LotFrontage', 'LotArea', 'Street',
.... (略) ....
'SaleCondition', 'SalePrice'],
dtype='object')
欠損値も見ておこう
train.isnull().sum()[train.isnull().sum() > 0].sort_values(ascending=False)
PoolQC 1453
MiscFeature 1406
Alley 1369
Fence 1179
.... (略)
欠損値の確認は、この記事を参考にしました
1-2. 学習データと検証用データの分割
まず、予測したい値(いわゆる目的変数)を分離しておきます。
House Priceの場合は、SalePrice
が予測したい値みたいですね。
proto_x = train.drop('SalePrice', axis=1)
proto_y = train['SalePrice']
proto
というprefixをつけたのは、お試しだからです。
深い意味はないです。
次に、学習に使うデータと、検証(test)に使うデータを分割します
x_train, x_test, y_train, y_test = \
train_test_split(proto_x, proto_y, test_size=0.20, random_state=0)
1-3. データ整形
さーて、試しにこれで学習してみようかなぁああ!!(^ワ^*)
model = XGBRegressor(n_estimators=20, random_state=0)
model.fit(x_train, y_train)
結果...さすがに気が早かったか....
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-36-1c4e8355ea5e> in <module>
1 model = XGBRegressor(n_estimators=20, random_state=0)
----> 2 model.fit(x_train, y_train)
.... (略) ....
ValueError: DataFrame.dtypes for data must be int, float or bool.
Did not expect the data types in fields MSZoning, Street, Alley,
.... (略) ....
PoolQC, Fence, MiscFeature, SaleType, SaleCondition
model.fit()
に渡すDataFrame内の値は、int, float, bool
のうちどれかでなければいけないらしい。
この条件に反するfield名は、 MSZoning, Street, ...., SaleCondition
ということのようだ。
全く前処理しない場合の成績を見てみたかったが、これらのフィールドについては、消すか変換してあげないといけない。
「前処理なし」により近いのは「消す」方かな!(^ワ^*)keshichae!!
ちなみに、これらはどれもobject型なので、object型のカラム名を特定した上で消そう(*^^*)
# NOTE: object型の列を特定
not_expected_type_column_names = x_train.columns[x_train.dtypes == 'object']
# 消えてしまえ!
# _0 というpostfixは、これからたくさんチャレンジするつもりなのでつけてみた
x_train_0 = x_train.drop(not_expected_type_column_names, axis=1)
x_test_0 = x_test.drop(not_expected_type_column_names, axis=1)
x_train_0.head()
# 結果: 81列あったデータが37列まで減った。スッキリ!()
Id MSSubClass LotFrontage LotArea OverallQual OverallCond YearBuilt YearRemodAdd MasVnrArea BsmtFinSF1 ... GarageArea WoodDeckSF OpenPorchSF EnclosedPorch 3SsnPorch ScreenPorch PoolArea MiscVal MoSold YrSold
618 619 20 90.0 11694 9 5 2007 2007 452.0 48 ... 774 0 108 0 0 260 0 0 7 2007
870 871 20 60.0 6600 5 5 1962 1962 0.0 0 ... 308 0 0 0 0 0 0 0 8 2009
92 93 30 80.0 13360 5 7 1921 2006 0.0 713 ... 432 0 0 44 0 0 0 0 8 2009
817 818 20 NaN 13265 8 5 2002 2002 148.0 1218 ... 857 150 59 0 0 0 0 0 7 2008
302 303 20 118.0 13704 7 5 2001 2002 150.0 0 ... 843 468 81 0 0 0 0 0 1 2006
5 rows × 37 columns
1-4. モデルを学習させる
model = XGBRegressor(n_estimators=20, random_state=0)
model.fit(x_train_0, y_train)
# 結果: なんか出たぽよ~
XGBRegressor(base_score=0.5, booster=None, colsample_bylevel=1,
colsample_bynode=1, colsample_bytree=1, gamma=0, gpu_id=-1,
importance_type='gain', interaction_constraints=None,
learning_rate=0.300000012, max_delta_step=0, max_depth=6,
min_child_weight=1, missing=nan, monotone_constraints=None,
n_estimators=20, n_jobs=0, num_parallel_tree=1,
objective='reg:squarederror', random_state=0, reg_alpha=0,
reg_lambda=1, scale_pos_weight=1, subsample=1, tree_method=None,
validate_parameters=False, verbosity=None)
1-5. 予測してみる
# 予測結果の出力
# 学習に使ったデータに対しての予測
predict_result_for_tr_data = model.predict(x_train_0)
# 検証用データに対しての予測
predict_result = model.predict(x_test_0)
結果は以下の通り。
House Priceという課題では、RMSE(Root Mean Squared Error)という指標で成績を評価するらしいので、RMSE
を計算する。
# 学習に使ったデータに対してモデルを適用した場合の誤差
rmse_of_train = np.sqrt(mean_squared_error(predict_result_for_tr_data, y_train))
rmse_of_train
# 結果
>> 9283.227477186625
# 検証用データに対してモデルを適用した場合の誤差
rmse_of_test = np.sqrt(mean_squared_error(predict_result, y_test))
rmse_of_test
# 結果
>> 37010.13476747102
test も train もそうですが、RMSE
値が小さい値になるほど、より正解に近い予測ができているといえるようです。
なので、上記「9283.22..., 37010.13...」よりも小さい値を目指す感じですね(`・ω・´)
1-6 submit
一応提出してみます。
kaggleの点数を上げたいわけではないのですが、どのくらい実力が上がっているのか、後で参考になると思うので、最低ラインの場合の実力を確認。
ここは特に解説しませんが、コードは載せておきます。
# trainデータに対して実施したのと同じ手順で、1-3 ~ 1-4を実施します
# 1-3. データ整形
# NOTE: x_trainでobject型だった列を特定して削除
not_expected_type_column_names = x_train.columns[x_train.dtypes == 'object']
test_proto = test.drop(not_expected_type_column_names, axis=1)
# 1-4. モデル学習
# モデルはさっき学習させたもの(model)を使います!
# 1-5. 予測
predict_proto = model.predict(test_proto)
submission = pd.DataFrame({'Id': test['Id'], 'SalePrice': predict_proto})
submission.to_csv('submission_new.csv', index=False)
なんか、何もしてないのに上位68%に入った...XGBoost
しゅごい...(*´﹃`*)
2. Result (結果と所感)
これが正真正銘の最低ライン。完全に手抜きした(完全に何もしなかった)場合の結果。
ここからどこまで改善できるか。
個人的には、今回試した6ステップを、何も見ずにそらでできるようになるのが、まず最初のステップと捉えています。
結果を出すためには細かい手順も必要なのですが、それらは結局課題によって異なるので、まずはなるべく幅広い課題に使えるものから試しつつ覚えていきたいと思います。
Next step
次回以降は、
- カテゴリ変数を数値化
カテゴリ変数をXGBoostで使えるようにする
pd.get_dummies()
で簡単にできるみたいです - 欠損値の穴埋め
あたりをやってみて、成績が多少変わるかどうか試してみようと思います。
ハイパーパラメータの探索や、他のモデルのお試しなどはもっと先になると思いますが、やってみたいと思います。
ド素人なので、ひとまずはこの課題で上位50パーセント以内に入ることを目指します ( *˙︶˙*)وグッ!
Reference(参考にしたもの)
この本は、様々な手法を広く浅く辞書的に掲載した本になっている気がします。
コードを書きながら1歩1歩学んでいく系の本ではないです。
なので、前から順に読んでいっても、全然書けるようにならないです(´;ω;`)ブワッ
ただ、初心者向けなのか、私レベルの人でもとても理解しやすかったです!
さいごに....
もうちょっと、もうちょっと情報量の少ない記事にしたい...
できれば3~5スクロールで最後まで見える記事がいい....
あ、喋るの好きだからムリかな....(*´﹃`*)
シリーズ一覧
No | New Trial | Score | Link | Note |
---|---|---|---|---|
1 | xgboost | 0.15663 | - | 本記事 |
2 | Label Encoding | 0.15160 | こちら | |
3 | Add and delete column | 0.15140 | こちら | |
4 | Make integer into categorical | 0.14987 | こちら | |
5 | One hot Encoding | 0.14835 | こちら | |
6 | Hyper parameters tuning | 0.13948 | こちら | |
7 | Logarithimic transformation | 0.13347 | 記事未作成 |