e-Stat API機能で取得した人口移動データをprophetで学習し、2020年の人口移動を予測する


# e-Stat API機能で取得した人口移動データをprophetで学習し、2020年の人口移動を予測する

## 人口移動データ取得


```python
import os
import io
import requests
import pandas as pd
from fbprophet import Prophet

%matplotlib inline
pd.plotting.register_matplotlib_converters()
app_id = os.getenv("E_STAT_API_APP_ID")
```


```python
def get_stats_name_list():
    url = "http://api.e-stat.go.jp/rest/3.0/app/getSimpleStatsList"
    params = {"appId": app_id, "statsNameList": "Y"}
    response = requests.get(url, params=params)
    csv_text = response.text[response.text.find('"TABLE_INF",') :]
    df = pd.read_csv(io.StringIO(csv_text), dtype="object")
    return df
```


```python
df_stats_name = get_stats_name_list().pipe(
    lambda df: df[df.STAT_NAME.str.contains("人口移動")]
)
```


```python
df_stats_name
```




<div>
<style scoped>
    .dataframe tbody tr th:only-of-type {
        vertical-align: middle;
    }

    .dataframe tbody tr th {
        vertical-align: top;
    }

    .dataframe thead th {
        text-align: right;
    }
</style>
<table border="1" class="dataframe">
  <thead>
    <tr style="text-align: right;">
      <th></th>
      <th>TABLE_INF</th>
      <th>STAT_CODE</th>
      <th>STAT_NAME</th>
      <th>GOV_ORG_CODE</th>
      <th>GOV_ORG_NAME</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>17</th>
      <td>00200523</td>
      <td>00200523</td>
      <td>住民基本台帳人口移動報告</td>
      <td>00200</td>
      <td>総務省</td>
    </tr>
  </tbody>
</table>
</div>




```python
stats_code = df_stats_name.TABLE_INF
```


```python
def get_stats_list(stats_code):
    url = "http://api.e-stat.go.jp/rest/3.0/app/getSimpleStatsList"
    params = {"appId": app_id, "statsCode": stats_code}
    response = requests.get(url, params=params)
    csv_text = response.text[response.text.find('"TABLE_INF",') :]
    df = pd.read_csv(io.StringIO(csv_text), dtype="object")
    return df
```


```python
df_stats_list = get_stats_list(stats_code).pipe(
    lambda df: df[
        (df.CYCLE == "月次")
        & (df.TITLE.str.contains("全国"))
        & (df.TITLE.str.contains("2010年1月"))
        & (df.TITLE.str.contains("転入者数"))
    ]
)
```


```python
df_stats_list[["TABLE_INF", "TITLE"]]
```




<div>
<style scoped>
    .dataframe tbody tr th:only-of-type {
        vertical-align: middle;
    }

    .dataframe tbody tr th {
        vertical-align: top;
    }

    .dataframe thead th {
        text-align: right;
    }
</style>
<table border="1" class="dataframe">
  <thead>
    <tr style="text-align: right;">
      <th></th>
      <th>TABLE_INF</th>
      <th>TITLE</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>14</th>
      <td>0003079521</td>
      <td>2010年1月～ 年齢（５歳階級），男女別他都道府県からの転入者数（日本人移動者） 全国，都道府県</td>
    </tr>
  </tbody>
</table>
</div>




```python
stats_data_id = df_stats_list.iloc[0].TABLE_INF
```


```python
def get_meta_info(stats_data_id):
    url = "http://api.e-stat.go.jp/rest/3.0/app/getSimpleMetaInfo"
    params = {"appId": app_id, "statsDataId": stats_data_id}
    response = requests.get(url, params=params)
    csv_text = response.text[response.text.find('"CLASS_OBJ_ID",') :]
    df = pd.read_csv(io.StringIO(csv_text), dtype="object")
    return df
```


```python
df_meta_info = get_meta_info(stats_data_id).dropna(axis=1).drop_duplicates('CLASS_OBJ_ID')
```


```python
df_meta_info
```




<div>
<style scoped>
    .dataframe tbody tr th:only-of-type {
        vertical-align: middle;
    }

    .dataframe tbody tr th {
        vertical-align: top;
    }

    .dataframe thead th {
        text-align: right;
    }
</style>
<table border="1" class="dataframe">
  <thead>
    <tr style="text-align: right;">
      <th></th>
      <th>CLASS_OBJ_ID</th>
      <th>CLASS_OBJ_NAME</th>
      <th>CLASS_CODE</th>
      <th>CLASS_NAME</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>0</th>
      <td>tab</td>
      <td>表章項目</td>
      <td>06</td>
      <td>他都道府県からの転入者数</td>
    </tr>
    <tr>
      <th>1</th>
      <td>cat01</td>
      <td>性別</td>
      <td>0</td>
      <td>総数</td>
    </tr>
    <tr>
      <th>4</th>
      <td>cat02</td>
      <td>年齢（５歳階級）</td>
      <td>000</td>
      <td>総数</td>
    </tr>
    <tr>
      <th>24</th>
      <td>area</td>
      <td>全国・都道府県</td>
      <td>00000</td>
      <td>全国</td>
    </tr>
    <tr>
      <th>72</th>
      <td>time</td>
      <td>時間軸（月次）</td>
      <td>2018001212</td>
      <td>2018年12月</td>
    </tr>
  </tbody>
</table>
</div>




```python
def get_stats_data(stats_data_id, cat01, cat02, area):
    url = "http://api.e-stat.go.jp/rest/3.0/app/getSimpleStatsData"
    params = {
        "appId": app_id,
        "statsDataId": stats_data_id,
        "cdArea": area,
        "cdCat01": cat01,
        "cdCat02": cat02,
    }
    response = requests.get(url, params=params)
    csv_text = response.text[response.text.find('"tab_code",') :]
    df = pd.read_csv(io.StringIO(csv_text), dtype="object")
    return df
```


```python
df_stas_data = get_stats_data(
    stats_data_id,
    **df_meta_info.groupby("CLASS_OBJ_ID")
    .first()
    .CLASS_CODE[["area", "cat01", "cat02"]]
    .to_dict()
)
```


```python
def to_prophet_format(df):
    return df.pipe(
        lambda df: df.assign(ds=pd.to_datetime(df["時間軸（月次）"], format="%Y年%m月"))
    ).pipe(
        lambda df: df[["ds", "value"]]
        .astype({"value": int})
        .rename(columns={"value": "y"})
        .sort_values("ds")
    )
```


```python
df_prophet = df_stas_data.pipe(to_prophet_format)
```


```python
df_prophet.head()
```




<div>
<style scoped>
    .dataframe tbody tr th:only-of-type {
        vertical-align: middle;
    }

    .dataframe tbody tr th {
        vertical-align: top;
    }

    .dataframe thead th {
        text-align: right;
    }
</style>
<table border="1" class="dataframe">
  <thead>
    <tr style="text-align: right;">
      <th></th>
      <th>ds</th>
      <th>y</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>107</th>
      <td>2010-01-01</td>
      <td>126018</td>
    </tr>
    <tr>
      <th>106</th>
      <td>2010-02-01</td>
      <td>137843</td>
    </tr>
    <tr>
      <th>105</th>
      <td>2010-03-01</td>
      <td>478514</td>
    </tr>
    <tr>
      <th>104</th>
      <td>2010-04-01</td>
      <td>398795</td>
    </tr>
    <tr>
      <th>103</th>
      <td>2010-05-01</td>
      <td>150085</td>
    </tr>
  </tbody>
</table>
</div>




```python
df_prophet.tail()
```




<div>
<style scoped>
    .dataframe tbody tr th:only-of-type {
        vertical-align: middle;
    }

    .dataframe tbody tr th {
        vertical-align: top;
    }

    .dataframe thead th {
        text-align: right;
    }
</style>
<table border="1" class="dataframe">
  <thead>
    <tr style="text-align: right;">
      <th></th>
      <th>ds</th>
      <th>y</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>4</th>
      <td>2018-08-01</td>
      <td>158332</td>
    </tr>
    <tr>
      <th>3</th>
      <td>2018-09-01</td>
      <td>129291</td>
    </tr>
    <tr>
      <th>2</th>
      <td>2018-10-01</td>
      <td>163296</td>
    </tr>
    <tr>
      <th>1</th>
      <td>2018-11-01</td>
      <td>124295</td>
    </tr>
    <tr>
      <th>0</th>
      <td>2018-12-01</td>
      <td>127839</td>
    </tr>
  </tbody>
</table>
</div>



## Prophetで学習、予測


```python
prophet_model = Prophet().fit(df_prophet)
future = prophet_model.make_future_dataframe(periods=24, freq='MS')
forecast = prophet_model.predict(future)
```

    INFO:fbprophet:Disabling weekly seasonality. Run prophet with weekly_seasonality=True to override this.
    INFO:fbprophet:Disabling daily seasonality. Run prophet with daily_seasonality=True to override this.


### プロット


```python
prophet_model.plot(forecast);
```


![output_23_0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/473192/8cced0f2-bc9f-5057-e52c-ccf75a46f459.png)



```python
prophet_model.plot_components(forecast);
```


![output_24_0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/473192/d0855c31-5e16-621b-22e2-2c989d70b95a.png)


### 2020年の予測結果


```python
forecast.set_index("ds")["2020-01-01":].yhat.apply(int).reset_index().pipe(
    lambda df: df.assign(ds=df.ds.dt.strftime("%Y年%m月"))
).set_index("ds")
```




<div>
<style scoped>
    .dataframe tbody tr th:only-of-type {
        vertical-align: middle;
    }

    .dataframe tbody tr th {
        vertical-align: top;
    }

    .dataframe thead th {
        text-align: right;
    }
</style>
<table border="1" class="dataframe">
  <thead>
    <tr style="text-align: right;">
      <th></th>
      <th>yhat</th>
    </tr>
    <tr>
      <th>ds</th>
      <th></th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>2020年01月</th>
      <td>123240</td>
    </tr>
    <tr>
      <th>2020年02月</th>
      <td>137012</td>
    </tr>
    <tr>
      <th>2020年03月</th>
      <td>458678</td>
    </tr>
    <tr>
      <th>2020年04月</th>
      <td>393502</td>
    </tr>
    <tr>
      <th>2020年05月</th>
      <td>164402</td>
    </tr>
    <tr>
      <th>2020年06月</th>
      <td>133720</td>
    </tr>
    <tr>
      <th>2020年07月</th>
      <td>156698</td>
    </tr>
    <tr>
      <th>2020年08月</th>
      <td>159363</td>
    </tr>
    <tr>
      <th>2020年09月</th>
      <td>135871</td>
    </tr>
    <tr>
      <th>2020年10月</th>
      <td>158294</td>
    </tr>
    <tr>
      <th>2020年11月</th>
      <td>123974</td>
    </tr>
    <tr>
      <th>2020年12月</th>
      <td>125429</td>
    </tr>
  </tbody>
</table>
</div>




```python
forecast.set_index('ds')['2020-01-01':].yhat.plot();
```


![output_27_0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/473192/4277c3af-39a3-8942-153d-057b9cba8549.png)