Pythonを使って福岡県の人口予測をしてみたので、上手くいったことと上手くいかなかったことを振り返る

#目次
[1.初めに](#1-初めに)
[2.やってみたこと](#2-やってみたこと)
　2-1. 目的
　2-2. プログラムと結果
[3.解説](#3-解説)
　3-1.環境
　3-2.データ諸元
　3-3.予測方法
[4.上手くいったこと](#4-上手くいったこと)
　4-1.google drive,Colaboratoryの利用
　4-2.教師用データとテスト用データの仕分けから制度の高いモデルの表示
　4-3.データの合成、グラフの表示
[5.上手くいかなかったこと](#5-上手くいかなかったこと)
　5-1.予測精度
　5-2.date型の取り扱い
[6.最後に](#6-最後に)


#1. 初めに
このブログではpython初心者である筆者が福岡県の人口予測をpythonを用いて行ってみた結果を示しています。同じようにpythonを勉強する方の参考になれば幸いです。

#2. やってみたこと
　　**2-1. 目的**
　　筆者は仕事の都合で福岡県に住んでますが、「福岡は人が増えた」と以前から住んでいる
　　方は言われます。そこで福岡県の人口がどれくらい増えているのか、そしてpythonで
　　どこまで予測できるのか試してみたいと思いました。
　　

　　**2-2. プログラムと結果**
　　早速以下のプログラムを実行し、結果を見てみたいと思います。青線が実際の人口の
　　増減、赤線がプログラムの実行結果を表しています。
　　ちなみに1995年10月を起点とし、2015年12月までを教師用データ（学習用）とし、
　　2015年12月～2019年12月までをテスト用データ（予測用）とします。

```python:colabの利用
#google colabのマウント
from google.colab import drive
drive.mount('/content/drive')
```


```python:実行プログラム
#モジュールのインポート
import csv
import pandas as pd
from sklearn.linear_model import LinearRegression
from sklearn.linear_model import Lasso
from sklearn.linear_model import Ridge
from sklearn.linear_model import ElasticNet
from sklearn.model_selection import train_test_split
from datetime import datetime as dt
import numpy as np
import matplotlib.pyplot as plt

#googele driveとの連携
data = pd.read_csv('/content/drive/My Drive/pythonblog/fdata3.csv')


# 説明変数
X=data.iloc[:,0]
# 目的変数
y=data.iloc[:,1]
# データを教師用とテスト用に分けます
train_X, test_X, train_y, test_y = train_test_split(X,y,test_size=0.2,shuffle=False)

#LinearRegression
model = LinearRegression()
model.fit(train_X.values.reshape(-1,1),train_y.values.reshape(-1,1))
model.score(test_X.values.reshape(-1,1),test_y.values.reshape(-1,1))
print("Linear regression:{}".format(model.score(test_X.values.reshape(-1,1),test_y.values.reshape(-1,1))))

score_Linear = model.score(test_X.values.reshape(-1,1),test_y.values.reshape(-1,1))
model_Linear = "Linear regression"
score_best = score_Linear
model_best = model_Linear

#LossoRegression
model =  Lasso()
model.fit(train_X.values.reshape(-1,1),train_y.values.reshape(-1,1))
model.score(test_X.values.reshape(-1,1),test_y.values.reshape(-1,1))
print("Lasso regression:{}".format(model.score(test_X.values.reshape(-1,1),test_y.values.reshape(-1,1))))

score_Lasso = model.score(test_X.values.reshape(-1,1),test_y.values.reshape(-1,1))
model_Lasso = "Lasso regression"

if score_best < score_Lasso:
    score_best = score_Lasso
    model_best = model_Lasso

#RidgeRegression
model = Ridge()
model.fit(train_X.values.reshape(-1,1),train_y.values.reshape(-1,1))
model.score(test_X.values.reshape(-1,1),test_y.values.reshape(-1,1))
print("Ridge regression:{}".format(model.score(test_X.values.reshape(-1,1),test_y.values.reshape(-1,1))))

score_Ridge = model.score(test_X.values.reshape(-1,1),test_y.values.reshape(-1,1))
model_Ridge = "Ridge regression"

if score_best < score_Ridge:
    score_best = score_Ridge
    model_best = model_Ridge

#ElasticNetRegression
model =ElasticNet(l1_ratio=0.1)
model.fit(train_X.values.reshape(-1,1),train_y.values.reshape(-1,1))
model.score(test_X.values.reshape(-1,1),test_y.values.reshape(-1,1))
print("ElasticNet regression:{}".format(model.score(test_X.values.reshape(-1,1),test_y.values.reshape(-1,1))))

score_ElasticNet = model.score(test_X.values.reshape(-1,1),test_y.values.reshape(-1,1))
model_ElasticNet = "ElasticNet regression"
if score_best < score_ElasticNet:
    score_best = score_ElasticNet
    model_best = model_ElasticNet
#最もよい評価値を出したモデルを表示します
print("best score is "+ "'" + model_best+ "'" + ":"+str(score_best))


pred_y = model.predict(test_X.values.reshape(-1,1))
pred_y = pred_y.astype(np.int64)


#実データと予測データを表示
pred_y_gr=np.concatenate([train_y,pred_y])

plt.plot(range(291),pred_y_gr,label="Predicted",color="red")
plt.plot(range(291),y,label="Actual",color="blue")
plt.xlabel("month")
plt.ylabel("population")
plt.title("Populations of Fukuoka Prefecture")
plt.grid(True)
plt.legend(loc="upper left")
```
```python:実行結果
Linear regression:-6.209968746815238
Lasso regression:-6.209945449988499
Ridge regression:-6.209911286136033
ElasticNet regression:-6.197976377270067
best score is 'ElasticNet regression':-6.197976377270067
```

![gragh.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2012953/1c45a888-db8b-fa95-2fb7-fe682e554a8c.png)

#3. 解説
　　**3-1. 環境**
　　・Windows 10 Pro
　　・google colaboratory

　　**3-2. データ諸元**
　　福岡県　人口移動調査（時系列データ）について、企画･地域振興部調査統計課
　　（分析班）が作成したデータを下記のURLから取得できます。
　　(2021年9月現在) [福岡県　人口移動調査（時系列データ）](https://ckan.open-governmentdata.org/dataset/401000_jinkouidouchousa-jikeiretsu "福岡県　人口移動調査（時系列データ）")
　　今回利用するデータ（列）は、年月列と人口-総数列になります。
　　
　　**3-3. 予測方法**
　　機械学習の手法は大きく分けると次の3つ
　　・教師あり学習
　　・教師なし学習
　　・強化学習
　　があり、教師あり学習はさらに回帰と分類に分かれ、今回は回帰について取り扱い
　　ます。

#4. 上手くいったこと

　　**4-1.google drive,Colaboratoryの利用**
　　googleColaboratoryはローカルに保存しているファイルを扱うことができず、
　　自分のgoogleアカウントのdriveにcsvファイルを読み込ませる必要があります。

```python:colabの利用
#google colabのマウント
from google.colab import drive
drive.mount('/content/drive')
```
　　上記のプログラムを実行するとアクセス許可を求めるリンクが出るのでリンクに
　　沿ってgoogledriveとのマウントを行います。

```python:csvファイルの場所を指定
#googele driveとの連携
data = pd.read_csv('/content/drive/My Drive/pythonblog/fdata3.csv')
```
　　3-2. データ諸元で取得したcsvファイル(fdata3.csv)を修正してMy Drive配下
　　にpythonblogというフォルダを作成しております。

　　**4-2.教師用データとテスト用データの仕分けから制度の高いモデルの表示**

```データの仕分け
# 説明変数
X=data.iloc[:,0]
# 目的変数
y=data.iloc[:,1]
# データを教師用とテスト用に分けます
train_X, test_X, train_y, test_y = train_test_split(X,y,test_size=0.2,shuffle=False)
```


　　説明変数とは今回のデータでいうところの年月であり、目的変数は予測を行う
　　人口になります。データを教師用データとテスト用データに分け、４つのモデル
　　（線形回帰、リッジ回帰、ロッソ回帰、ElasticNet）から最も評価値の高い
　　モデルを表示させます。

```python:実行結果
Linear regression:-6.209968746815238
Lasso regression:-6.209945449988499
Ridge regression:-6.209911286136033
ElasticNet regression:-6.197976377270067
best score is 'ElasticNet regression':-6.197976377270067
```


　　**4-3.データの合成、グラフの表示**
　　np.concatenate()を用いて教師用データと予測結果を連結し、実データとの
　　差を分かりやすくしております。

#5. 上手くいかなかったこと
　　**5-1.予測精度**
　　予測結果（プログラム中のmodel.score）は1以下の値を取りますが、0.8以上の
　　モデルで精度が高いと判断できますが、今回の手法ではいずれのモデルでも
　　-6付近と決して高い精度とは言えません。これは教師用データの取得期間は
　　一月あたりの増加人数が平均683人に対し、テスト用データの期間は344人と
　　人口増加が鈍化してきているのが原因と考えられます。

　　**5-2.date型の取り扱い**
![gragh.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2012953/1c45a888-db8b-fa95-2fb7-fe682e554a8c.png)
　　横軸のmonthですが、1995年10月を起点として何か月経過したかを記載して
　　おります。もともと諸元データは
            年月       人口
0    1995/10/1  4933393
1    1995/11/1  4935744
2    1995/12/1  4937623
3     1996/1/1  4939518
4     1996/2/1  4939616
..         ...      ...
286   2019/8/1  5109874
287   2019/9/1  5109800
288  2019/10/1  5110113
289  2019/11/1  5112216
290  2019/12/1  5111925
　　このように年月と人口データを読み込ませていたのですが、

```python:エラー
ValueError                                Traceback (most recent call last)
<ipython-input-2-274fab217090> in <module>()
---> 29 model.fit(train_X.values.reshape(-1,1),train_y.values.reshape(-1,1))
3 frames
/usr/local/lib/python3.7/dist-packages/numpy/core/_asarray.py in asarray(a, dtype, order)

---> 83     return array(a, dtype, copy=False, order=order)

ValueError: could not convert string to float: '1995/10/1'
```
　　と上記のようなエラーが発生したため、date型から修正しました。
　　（線形回帰ではdate型は取り込めないようです）

#6. 最後に
pythonを初めて触ってみてデータの取得からoutputまでやってみましたが実データの予測
は難しいことが改めて分かりました。今後は別のデータを触ったりデータのクレンジングも
スマートに出来るよう研鑽していきたいです。