自動車の燃費を予測してみた。【signate練習問題】その１

# pythonを使って自動車の燃費を予測してみました。


　こちらの記事をご覧いただきありがとうございます。

　この度は、機械学習を勉強し始めておよそ3か月の私が、勉強したことの実践として、signateにある自動車の燃費予測を機械学習を用いて行ってみました。
　記事を書く目的は私自身のアウトプットですが、ご覧いただいた皆様にも何か学びがあれば幸いです。


## データの確認
　使用するデータは以下の変数を持ちます。

* `cylinders` : 使用されているシリンダーの種類
* `displacement` : 排気量
* `weight` : 車の重量
* `horsepower` : 馬力
* `acceralation` : 加速度
* `model year` : 年式
* `origin` : 起源
* `car name` : 車名
* `mpg` : 燃費（mile per gallon）

　mpgが目的変数になります。それ以外の8つの変数を用いて、mpgの値を予測します。
　データサンプル数は199です。


## まずはサンプルデータについて知る

　最初にサンプルデータの各変数にどんな値が入っているか調べました。

* `cylinders` : 3~8のint。3と5はサンプル1個のみ。7はない。
* `displacement` : 71~454のfloat。平均は約183。
* `weight` : 1613~5140のfloat。平均は約2883。
* `horsepower` : object。中身は小数の数字データがほとんどだが、一部`?`が入っている。おそらく欠損値。
* `acceralation` : 8~23のfloat。平均は
* `model year` : 70~82のint。70とは1970を表すものと思われる。
* `origin` : 1~3のint。
* `car name` : object。アルファベットで車名が表記されている。`toyota~`とか知っている文字列もあった。

この時点でいくらか思うことが出てきました。
* `cylinders`と`origin` はカテゴリの違いを整数で表しているっぽい(label encoding)
* 速さと重さの関係って高校で習った気がする（運動エネルギー？）
* 車の時代背景が分かれば`model year`も役に立てやすそう
* `origin`がカテゴリだとして何を表しているのか？
* 車名にメーカーが乗っているのでうまく取り出せば役に立つかも


## ドメイン知識を調べる
　変数の中身を見て、数字の意味をよく理解できたほうが良いと感じたので、車について調べてみました。

* シリンダーとはエンジンの重要なパーツのこと。`cylinders`はそのパーツの種類を表してそうなことを感じた。
* 馬力とはエンジンの出せる力の大きさ（意訳なので語弊がありそう）。重い車ほど強そう。
* 1970年代は車からの排気ガスによる大気汚染があり、対策が進められていた。また1973年にはオイルショックがありガソリン価格が急騰、低燃費化がすすめられた。時代に沿って車の技術進歩があるのはよくある発想だとして、時代背景からしても70～82の間に大きな性能の向上がありそう。
* $ \vec p = m \vec v$ という、運動量と質量、速さの関係式がある。もしくは、$ E = \frac{1}{2}mv $という、運動エネルギーと質量、速さの関係式がある。車の燃費がどちらと関係が深いのかはよくわからなかった（詳しく調べればわかりそうではある）。


　ほかにも調べたことはありますが、変数名から察せられたこととおおよそ同じだったので割愛します（高校物理をまあまあ真面目に勉強しておいてよかった）。


## データを可視化する

　基本的な可視化手段を使って特徴量やそれらの関係性について確認しました。先に調べたドメイン知識の確認のほか、後のモデル分析にも役に立つはずです。

　可視化する前に、`horsepower`の欠損値への対応をします。とりあえず小数値として扱えるように、`?`の列を取り除いた後にfloat型に変換します。
```python: ?を取り除く
import copy
df_train_nn = copy.copy(df_train.query('horsepower != "?"'))
df_train_nn['horsepower'] = df_train_nn['horsepower'].astype(float)
```

### 変数の相関を確認する

 まずは各変数の相関を確認します。
```python: 相関のヒートマップ
import seaborn as sns

plt.figure(figsize=(6,5))
sns.heatmap(df_train_nn.corr(),annot=True)
plt.show()
```

　__出力結果__
<img width=400 alt='変数の相関.png' src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2774344/73184032-db61-a21f-4b9b-6db2d61ed012.png'>

 `cylinders`,`displacement`,`horsepower`,`weight`の4つは正の相関が高く、またそれらは`mpg`と強めの負の相関を持っているようです。最悪説明変数が`weight`だけでもそこそこ再現できそうですね。
　また使用するモデルによっては多重共線性(変数同士の相関が高いと起こる問題)を考慮する必要があります。
　`model year`や`origin`も`mpg`それなりの相関があります。

　このあたりで、`cylinders`,`displacement`,`horsepower`,`weight`と`mpg`の5つの変数の関連性が高いことから、一つの仮説を考え始めました。その仮説が、「車の使用目的に合わせて設計するなら5つの変数は似たような値になりそう」ということです。
　例えば、長距離運送用のトラックを作ることを考えたときに、大量の荷物を運べるように車体を大きくして必然的に重くなります。同時に、重い荷物をそれなりの速さで運べるようにするために馬力を高める必要があります。高い馬力を得るためには高出力のエンジン(シリンダー)を使う必要もあります。重いものを軽いものを運ぶ時と同じ速さで運ぶなら、重い分だけ多くの燃料を消費する(燃費が悪くなる)のも自然な考えだと思います。そして、燃料の消費量に伴って排気量も多くなる、と想定できます。
　つまり、__先の5変数は車両の使用目的によっておおよそ決定する__ ものと考えられます。もちろん他の要素もいろいろかかわってくると思いますが、この5変数はかなり関係性が高そうです。

### 変数の特徴や変数ごとの関係を調べる

　変数ごとのヒストグラムや散布図も確認します。あらゆるパターンを乗せると数が多いので、私が注目したものを取り上げます。


#### 相関の高い変数同士の関係は？

　まず確認したかった点が、相関の高い変数同士の関係性。相関が高いんだから右肩上がりか右肩下がりになるだろうって思わなくもないですが、それを確認しておくのも大事なことだと思います。

```python:散布図の作成
sns.relplot(data=df_train_nn,x='displacement',y='mpg', hue='cylinders')
plt.show()
```
__mpg、displacement、cylinderの関係性__
<img width="300" alt="mpg-displacement-cylinders.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2774344/e793e6e5-fcf4-71d1-7eb6-ad52e617e80a.png">

　これを見ると、`displacement`と`mpg`に強い負の相関があるのも納得します。`cylinders`によって色分けしていますが、シリンダー8は排気量が多く燃費が悪い、シリンダー4は排気量が少なく燃費が良い、シリンダー6はその中間、という傾向が確認できます。

　同じような散布図を載せます。

__mpg、horsepower、cylinderの関係性__
<img width="300" alt="mpg-horsepower-cylinders.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2774344/7c3aac1b-e271-e523-c483-922b33e1e01d.png">

__mpg、weight、cylinderの関係性__
<img width="300" alt="mpg-weight-cylinders.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2774344/bb76cc1e-fb2d-d8b3-a160-88feadd28413.png">

　これを見ると、`horsepower`や`weight`にも`displacement`と同様の傾向が見られます。このことから、さっき考えていた仮説「車の使用目的に合わせて設計するなら5つの変数は似たような値になりそう」も割と確信を持てそうな気がしています。
　シリンダー8は重い、排気多い、馬力高い、の特徴があり、トラックとかの長距離運送とか、もしくは悪路を走るためにパワーが欲しいとか、そんな可能性を感じます。
　シリンダー4は軽い、排気少ない、馬力低い、の特徴があり、整備された道路を走るならこんなもんかなーとか思ったりしました。


#### model year によって性能はどの程度変わるのか？

　70~82年代に低燃費化が進んだことを先に述べましたが、実際にどの程度のものなのか確認できる範囲で見てみました。

__model year, mpg, cylinders の関係性__
<img width="300" alt="mpg-model_year-cylinders.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2774344/eaa632e1-ee0f-825b-7430-177b24ff9bb4.png">

　これを見ると確かに、全体的に右肩上がりになっているので、時代が進むにつれて燃費が向上しているような印象がありますね。
　`cylinders`との関係性も見れるように、`cylinders`の違いで色分けをしています。シリンダー4が白寄り、シリンダー8が黒寄りの色付けがされています。
　シリンダー8（黒）は80年以降あまり使われなくなっているようです。時代の変化とともに燃費の悪いものは使われなくなったみたいですね。交通網が整備されたからか、高い馬力が必要な場面がほとんどなくなった、というのが私の予想です。

　箱ひげ図も描いてみました。多分こっちのほうがわかりやすいような気がします。
<img width="300" alt="mpg-model_year-cylinders-boxplot.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2774344/f7862fcc-cbb8-79ab-ecd3-e2cbcfff6580.png">

　特にシリンダー6は80年以降かなり燃費が向上しているようですね。シリンダー8は80年以降ほとんど使われなくなったこともわかります。


　他の散布図も見てみましょう。

__model year, mpg, displacement の関係性__
<img width="300" alt="mpg-displacement-model_year.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2774344/52112db0-62b7-9003-3a36-3d1a3a0ebb29.png">

__model year, mpg, horsepower の関係性__
<img width="300" alt="mpg-horsepower-model_year.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2774344/38d49e1e-b7d1-0b4e-030f-8280c8fa9022.png">

__model year, mpg, weight の関係性__
<img width="300" alt="mpg-weight-model_year.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2774344/46b579f3-9095-03c6-3987-e3b8a22272eb.png">

　今度は`model year`によって色分けをしています。70年が白寄りで、時代が進むにつれて黒くなっていき、82年が黒になっています。
　`displacement`と`horsepower`と`weight`の3つはいずれも同じような散らばり方をしていますが、`model year`を含めても同じ傾向になるようですね。白い点の古い車は下に集まっていて、黒い点の新しい車が上に集まっています。また、黒い点が左側に集まっていることから、時代が進んで重い、排気多い、馬力高い、の車があまり作られなくなったようです。低燃費化が進んでいるのは間違いなさそうですが、さらに時代の流れでそもそも馬力の高い車が必要なくなったと考えられます。


#### origin とは何者なのか

　`origin`という変数名と1～3という中身だけではイマイチ何を表しているのかよくわからなかったので、これも可視化によって何か情報が得られないかとヒストグラムや散布図を作成しましたが、それでもイマイチよくわかりませんでした。
　この`origin`が何者か気づいたのは、`car name`を眺めていた友人でした。`car name`に`toyota`の文字列が含まれているのは、`origin`が3のデータだけという発見をしてくれました。実際に確認した結果が以下です。

```python:'toyota'を含むデータを表示
df_train[df_train['car name'].str.contains('toyota')]
```
__toyotaとorigin__
<img width=300 alt='origin-toyota.png' src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2774344/acfb5841-ced9-03d0-25b5-9eb0bc2fb629.png'>


　確かに、`toyota`を持つデータは全て`origin`が3ですね。同じように、`car name`に`honda`を含むデータはどうだろうかと思って確認しました。

__hondaとorigin__
<img width='300' alt='origin-honda.png' src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2774344/c207d877-0bed-3f65-65c5-481c808130ef.png'>

　こちらも全て`origin`が3でした。この結果を見て、`origin`は車のメーカーを表しているのでは？という仮説が生まれたので、検証します。
　`car name`の文字列のうち、最初の1単語はメーカーを表す単語っぽいので、まずはそこだけを取り出すことを考えました。うまく取り出せたので、それを`maker`変数として用意します。各メーカーがどのくらいあるのかを確認しました。

```python:メーカーを取り出す
# 単語を空白で切り分けて、最初の単語を取り出してmaker変数とする
df_train_mk = copy.copy(df_train)
for id, name in enumerate(df_train_mk.loc[:,'car name'].str.split()):
    df_train_mk.loc[id,'maker'] = name[0]
# 各メーカーがどのくらいあるのか確認
df_train_mk.sort_values('maker').groupby('origin')['maker'].value_counts(sort=False)
```
__メーカーごとのデータ数__
<img width=300 alt='maker一覧.png' src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2774344/701a9cd0-ad21-0a8c-5342-7a865e917598.png'>

　メーカー名を検索してどこの国か確認しましたが、`origin`が1のメーカーはアメリカで、2はヨーロッパ、3は日本で間違いなさそうです。

　メーカーごとに燃費の違いがあるか確認してみました。
```python:メーカーと燃費の確認
sns.boxplot(data=df_train_mk, x='origin', y='mpg', hue='maker')
plt.legend().remove()
plt.show()
```
__makerごとの箱ひげ図__
<img width=500 alt='maker-mpg.png' src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2774344/15ad6085-7da8-de76-776b-862b4ee4c138.png'>

　`origin`が2ならメーカーごとに燃費の差があると言ってもよさそうですね。ヨーロッパの地域差によるものでしょうか？　対して、`origin`が1と3だとメーカーによる差があるとは言いにくそうです。そもそも母数が少ないメーカーもあるので、モデルに学習させるときにメーカー変数はあまり活躍しないような気がします…。

## モデルによる予測は次の記事にします

　変数について個人的に気になったことはだいたい調べ終わったので、いよいよモデルで回帰予測…にしようと思いましたが、記事がかなり長くなりそうなのでここで区切ります。
　ここまでご覧いただいた皆様、ありがとうございました。

　次回の記事はこちらです。

https://qiita.com/tomyu/items/a9321657349fc6da4bef


## signate の問題はこちらから
※練習問題に関する内容の公開は問題ないっぽいですが、何か問題があれば記事ごと削除します。


https://signate.jp/competitions/121