初心者がAWS色々使って電力予測システム作ってみた

## はじめに
　機械学習の勉強をまず本を読んで始めてみたのですが本だけでは実際にどうすればいいのかわからないということで何か形にあるものを作ろうと思いました(去年の夏に)。その第一弾として消費電力予測システムを作ってみました(去年の夏に)。
※この記事をあげる前にsageMakerの記事あげてたりで時系列がおかしいため **去年の夏に** 作ったことを強調しておきます。(念のため)
そして今回の記事ではタイトル的にsageMakerとかAmazon MLとか使ってそうですが **全く** 使っていませんのでその辺を使った記事を探している方にはごめんなさい。

## とりあえず完成形

<img width="1405" alt="消費電力予測 - Vivaldi 2018-11-07 13-29-14.png" src="https://qiita-image-store.s3.amazonaws.com/0/192406/a1a8bf5e-3dd6-7a9f-f016-39ee47e71309.png">


こんな感じのページ作りました。精度を示すための実測値と予測値の比較グラフと先5日間の電力予報を載せています。このページ作成ではgo言語のBuffaloというフレームワークを使っており、グラフ描画にはchart.jsを使っています。本記事はページ作成ではなくシステムの作成をメインにしているのでページ作成部分は割愛します。

## システム全体の流れ
今回作成したシステムのおおまかな流れは以下の図のようになっています。Open Weather Mapの天気予報が3時間ごとであるためlambdaも3時間ごとにキックしています。Dynamoには月や曜日などの予測電力を出力するために必要な値と予測消費電力、実際の消費電力を同一テーブルに入れています。webページに接続するとdynamoに入っている時刻と予測値・実測値を取得しその値を使ってグラフ描画をする、といった形です。実際の消費電力は1日1回(今回は午前9時)前日の値を[東京電力電力供給状況API](http://tepco-usage-api.appspot.com/)を使って取得しています。また、予測消費電力はHerokuを使って作成したAPIを使って取得しています。
![電力予測流れ.png](https://qiita-image-store.s3.amazonaws.com/0/192406/7c48bdf9-8693-d9b8-1090-a1ee75f2c8af.png "電力予測流れ.png")


## 学習方法
今回はランダムフォレストという手法を使って予測をしています。
入力する値(説明変数)は図に示すような項目となっています。曜日や天気は元々のデータが文字列のため数字に変換しています。そして出力する値(目的変数)は消費電力です。
![電力学習.png](https://qiita-image-store.s3.amazonaws.com/0/192406/5f78d3a1-f3a8-3ee2-1911-8abe349d9faa.png "電力学習.png")

### ランダムフォレスト？
ランダムフォレストとは、すごく簡単にいうと「決定木がいっぱい集まったやつ」です
### 決定木？
じゃあ決定木ってなんだよ？っていうと
決定木は目的変数に属する確率を複数の説明変数の組み合わせで算出する方法です。以下の図のように色んな条件の組み合わせを考えて出力が3000万kwになる確率、4000万kwになる確率...を学習していきます。ただこれが一つだけだと天気から考え始めた時、時刻から考え始めた時などを考慮できないためそれらを考慮した決定木も用意します。このように複数の決定木を集合させて学習させる方法をランダムフォレストと言います。
![決定木.png](https://qiita-image-store.s3.amazonaws.com/0/192406/000710a6-0869-72e3-619a-f3d6eae22d99.png "決定木.png")

## 学習データについて
今回消費電力を予測するのに使用した情報は月、曜日、時刻、天気、気温の5種類です。機械学習に投げるデータは数字である必要があるので曜日、天気は数字に変換しました

例.
月曜日 → 1
晴れ → 0、雨 → 2

今回は学習データとして[気象庁](http://www.data.jma.go.jp/gmd/risk/obsdl/index.php)の東京の過去データ、東京電力の過去データから2012~2014,2016年のものを使用しました。(2015年に関しては東京電力のデータがなかったため含めていません)
東京電力の過去データについては下記URLの数字部分を取得したい年にすることで取得できます。
> http://www.tepco.co.jp/forecast/html/images/juyo-2017.csv


|MONTH | WEEK | TIME | TEMP | WEATHER | ELECTRIC |
|:-----|-----:|-----:|-----:|--------:|:--------:|
|1     |3     |3     |3.5   |0        |2455      |     
|1     |3     |6     |7.2   |0        |2477      |
|1     |3     |9     |9.4   |0        |2687      |
|...   |...   |...   |...   |...      |...       |
上記のような感じでcsvファイルを作成しました

## APIの作成
今回Herokuに作ったAPI(flask使用)に月などの条件を投げると予測消費電力をjsonで返す、という形にしました。(本当はEC2を使いたかったのですが諸事情によりHerokuに...)
Herokuの中には先ほど準備したcsvを使って作ったモデルをあらかじめ置いています。予測するために必要なデータがPOSTされたらそのモデルを使って算出した予測値をjson形式で返す。といった形です。

## これだけ！
簡単な説明でしたがざっくり言うとこれだけで予測システムが作れました。モデル作成時も用意された関数を使ったら数行で作れてしまうのでお手軽ですね!
これでひたすらdynamoDBに予測値を溜め込んでいくだけです！
実測値に関しては先ほども述べたように[東京電力電力供給状況API](http://tepco-usage-api.appspot.com/)から取って来てdynamoにupdateしています。

## でも...もっと精度を上げたい！
ただこの状態だと最初に入れた学習データだけで今後ずっと予測していくことになります。学習は気象庁のデータですが予測にはopenweathermapの情報を使っています。情報源が異なるもので予測をしているので正確な予測をするにはもっと学習データを豊富にする必要があります。

## 精度を上げるためにやったこと
予測するのにopenweathermapの情報を使っているならそれの学習データを追加して行ったらもっと精度が上がるのでは？！と思ったので、今度はS3とHerokuのスケジューラ機能を使って改良してみました。
![電力予測改.png](https://qiita-image-store.s3.amazonaws.com/0/192406/ea9e5f9f-2d70-43f3-02cc-16420199f83f.png "電力予測改.png")

概略図は上のような感じです。今まで実測値をdynamoにしか入れていませんでしたが、csvにしてどんどん追記したものをS3に保存しておきます。これによって、今までの学習データに加えて新しい学習データを使ってモデルを作ることができます。Herokuの中で1日1回モデルを更新するためにS3から最新データが追加されたcsvを取得してモデルを更新して、最新のモデルで予測値を返していきます。ここで先ほどのheroku schedulerを使ってます。これを実装することで何もしなくても勝手に学習データが増えて、それを使ったモデルを使って電力の予測をしてくれる！というわけです！

## さいごに
機械学習初心者でもここまで形になるとは正直びっくりでした。
東京電力が電力予測コンテストみたいなの開催してるのを知って(去年の夏に)、応募しよーって思ったらもう締め切り過ぎてたのは悲し過ぎた...
今回はコードを見ながら、ではなく処理の流れをざっくり解説だったのでコードもお見せしながら解説の記事もかけたらいいなぁぁと思ったり思わなかったり...
情報に誤りがありましたらぜひ教えてください。