Edited at

データサイエンス初心者が自動車の走行距離を予測してみた(その1)

「Kaggleやってみたいよー」

「でも英語は怖いよー」

「敷居を高く感じるよー」

って人(自分含む)向けの記事です。

SIGNATEっていう日本版のKaggleみたいなものに取り組みました。

データサイエンス初心者だけどコンペに参加してみたい!って人を巻き込むために書きました。


SIGNATE

SIGNATEとは、冒頭でも書いたようにKaggleの日本版のような感じです。

アクティブユーザ数やコンペ数はKaggleに劣りますが、

母国語で取り組めるという安心感があるため、個人的にはおすすめです。

英語読める人はKaggleの方がいいかも...。

今回はこのSIGNATEのコンペの1つである、自動車の走行距離予測に取り組んでみます。


自動車の走行距離予測

走行距離予測という日本語だけだとパッとイメージしづらいですが、

いわば燃費予測です。

ガソリン1ガロンあたりに、この車はこのぐらい走るんじゃない?っていう予測をしていく問題です。

会員登録しなくてもコンペ概要のみは見れるようです。

この記事では、とりあえず予測結果を提出するところまでを行います。

精度を高めていくのはその2(今後投稿予定)で行なっていきます。


使用するモデル(回帰木モデル)

今回の予測には回帰木モデルを用います。

回帰木モデルについては、わかりやすく解説してくれている記事があるので、省略します。

[入門]初心者の初心者による初心者のための決定木分析

ざっくり回帰木モデルをまとめると、

「データを段階的に分類していって、分類したグループごとに予測値を決めよう」といった感じです。


ソースベースでざっと解説


パッケージ導入

データサイエンス御用達のパッケージを読み込んでいきます。

各種パッケージに関する詳細はQiita等でも紹介されているので、省略。

pipとかを使って、がんがん入れていきましょう。

# データ処理

import pandas as pd
import numpy as np
# 可視化
import seaborn as sns
import matplotlib.pyplot as plt
from sklearn.tree import export_graphviz
import pydotplus
from IPython.display import Image
# モデル
from sklearn.tree import DecisionTreeRegressor
# 評価
from sklearn.metrics import mean_squared_error


データの読み込み、確認

まずはデータを読み込んで、眺めてみます。

# 訓練,検証用データ

labeled_data = pd.read_csv('train.tsv',
index_col = 'id',
delimiter='\t')

# テストデータ
unlabeled_data = pd.read_csv('test.tsv',
index_col='id',
delimiter='\t')

# 教師データの先頭を確認
labeled_data.head()

教師データ

id
mpg
cylinders
displacement
horsepower
weight
acceleration
model year
origin
car name

0
29.0
4
135.0
84.00
2525.0
16.0
82
1
dodge aries se

3
31.9
4
89.0
71.00
1925.0
14.0
79
2
vw rabbit custom

9
19.0
6
156.0
108.0
2930.0
15.5
76
3
toyota mark ii

mpgはmile per gallonの略称です。

訓練データを学習した上で、テストデータのmpgを予測します。

型と欠損有無(NULL)を確認します。

# 型確認

labeled_data.info()

# <class 'pandas.core.frame.DataFrame'>
# Int64Index: 199 entries, 0 to 396
# Data columns (total 9 columns):
# mpg 199 non-null float64
# cylinders 199 non-null int64
# displacement 199 non-null float64
# horsepower 199 non-null object
# weight 199 non-null float64
# acceleration 199 non-null float64
# model year 199 non-null int64
# origin 199 non-null int64
# car name 199 non-null object
# dtypes: float64(4), int64(3), object(2)
# memory usage: 15.5+ KB

NULLが入っているデータはないようです。

ただ、horsepowergが少しおかしそうですね。

先ほどのデータ確認では明らかに数値が入っていますが、object型になっています。

実際にデータを確認するとobject型になっている理由がわかるのですが、

それは"その2"で行っていきます。


データの分割

実際にモデルに突っ込む前に、データを説明変数と目的変数に分割します。

また、教師データも訓練データ、検証データに分割します。

また、先ほどおかしそうだったhorsepowerですが、このタイミングでデータから除外します。

(モデルに突っ込む際にエラーを吐いてしまうため)

データから除外することで精度は低くなるのですが、とりあえずこの記事では予測結果を提出することが目標ですので除外します。

同様にobject型のcar nameも除外します。

# 説明変数と目的変数に分割

labeled_data_x = labeled_data.drop(['mpg', 'horsepower', 'car name'], axis=1)
labeled_data_y = labeled_data[['mpg']]

# 訓練,検証用に分割(6:4)
threshold_data_separate = round(len(labeled_data) * 0.6)

train_data_x = labeled_data_x[:threshold_data_separate]
validate_data_x = labeled_data_x[threshold_data_separate +1:]
train_data_y = labeled_data_y[:threshold_data_separate]
validate_data_y = labeled_data_y[threshold_data_separate +1:]


モデル作成

訓練データを用いて回帰木モデルを作成します。

回帰木の深さは3とします。

この辺りのパラメータ探索も試行錯誤するべきですが、"その2"で検討していきます。

# モデル作成(深さ=3)

dtree_model_01 = DecisionTreeRegressor(max_depth = 3)
dtree_model_01.fit(train_data_x, train_data_y)

# モデル描画
export_graphviz(dtree_model_01,out_file='figure/dtree_model_01.dot',feature_names=train_data_x.columns)

dtree_model_01_graph = pydotplus.graphviz.graph_from_dot_file('figure/dtree_model_01.dot')
dtree_model_01_graph.write_png('figure/dtree_model_01.png')
Image(dtree_model_01_graph.create_png())

作成した回帰木モデル


評価

ここまででモデルを作成することができました。

検証データで作成したモデルの評価をしていきます。

今回のコンペは評価をRMSEで行うので、同様に評価していきます。

RMSEは回帰モデルの誤差を評価する指標の1つで、精度が高いほど値が小さくなります、

RMSE = \sqrt{\frac{1}{n}\sum_{i=1}^{n}(y_i-\hat{y_i})^2} 

その他指標も含めて、わかりやすく解説してくれています。

いろいろな誤差の意味(RMSE、MAEなど)

# モデルを使って検証データを予測

validate_data_y_01 = validate_data_y
validate_data_y_01 = validate_data_01.assign(pred = dtree_model_01.predict(validate_data_x))

# RMSE
np.sqrt(mean_squared_error(validate_data_y_01['mpg'], validate_data_y_01['pred']))
# 3.8358793178488244

# 誤差をグラフで確認
validate_data_y_01.plot.scatter(x="mpg",y="pred")
plt.plot(np.arange(1000),np.arange(1000), color="r")
plt.xlim(0, 50)
plt.ylim(0, 50)
plt.show()

上記のグラフはモデルの精度を表すものです。

青い点が赤い線に近いほど、モデルの精度が高いということを表します。

なんとなく予測できている気がします。


テストデータの予測

いよいよ最後です。

作成したモデルを元にテストデータの予測を行います。

モデル作成ではhorsepower、car nameを除外していたので、同様に除外します。

# モデル作成時と同様,horsepowerとcar nameを削除

unlabeled_data_01 = unlabeled_data.drop(['horsepower', 'car name'], axis=1)
unlabeled_data_01.head()

# モデルを使ってテストデータを予測
unlabeled_data_01= unlabeled_data_01.assign(pred = dtree_model_01.predict(unlabeled_data_01))

# 提出用に整形して,出力
submit_data = unlabeled_data_01 [['pred']]
submit_data.to_csv('submit.csv', header=False)

テストデータ

id
cylinders
displacement
weight
acceleration
model year
origin

1
6
145.0
3160.0
19.6
81
2

2
6
250.0
3525.0
19.0
77
1

4
4
119.0
2434.0
15.0
80
3

提出データ

id
mpg

1
28.66

2
20.26

4
34.24


データ提出、順位確認

完成したデータはSIGNATEのコンペ詳細で提出できます。

提出後にメールで評価(誤差)を教えてくれます。

コンペ詳細では順位を確認できます。

今回は、

誤差は3.6269278507114433

順位は319チーム中275位

でした。


まとめ

この記事ではコンペ参加から、とりあえずの予測までを行いました。

ここから精度を上げるには、

- データの洗浄、加工

- モデルの選定、調整

が必要になってきます。

"その2"では実際に精度をあげるための作業を行なっています。