予測モデルにより明日の目覚めを改善する

# はじめに

せっかく[Qiita夏祭り2020](https://qiita.com/official-events/ff7f07f95b9ed2407d1f)なるお祭りの存在に気が付いたので、何か予測モデルを作ってみようと思いました。
ただ残念ながら気づくのが締め切りギリギリとなり、データを収集している時間もありません。

そんなときに重宝するのが自分に関するデータではないでしょうか。
なぜなら…

* データ収集が容易
* ドメインエキスパートが身近にいる（つまり私自身）

データに関しては、グーグル氏が私に代わりせっせと情報を収集し続け、それらデータは [GoogleTakeout](https://takeout.google.com/settings/takeout) から簡単にダウンロードできる状態で常に用意されています。

取得可能な情報はGoogleサービスに関連する以下のようなデータです。

* アクセスしたページや検索キーワード
* YouTubeの再生履歴
* Google Fit のアクティビティデータ（歩数など）


# 何を予測するか

予測対象は「目覚めの気分」です。

私の場合ですが、睡眠時間などは [fitbit](https://www.fitbit.com/jp/home) で日々計測を行い Google Fit に連携して利用しています。
fitbit では睡眠の質を自動採点してくれる機能があるのですが、その点数がいまいち自分の感覚と合わないため、1年ほど前から、朝起きたら「目覚めの気分」を記録するようにしていました。
([DAYLIO](https://daylio.webflow.io/) というスマホアプリを使用して記録)

![daylio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14471/34173cdb-428b-3314-2766-3a2576074012.png)

DAYLIOではその気分の理由を補足する情報も記録可能で、私の場合、前日にお酒を飲んだかどうかだけは記録していました。

当初はもっといろいろ記録していたのですが、面倒かつ記録をつけることに意味があるのかよく分からなくなってきており、今回のモデル作成を口実に、無理やりでも利用してやろうというのが本音です。（役に立たないなら記録をやめる）

なおDAYLIOの記録もエクスポート機能のおかげで簡単に収集する事が出来ました。

これでデータは揃いました。

# 予測モデルの概要

日々のさまざまな行動から、翌朝の「目覚めの気分」を予測するモデルです。

用途対象 | データ内容                                  | 心技体?
----     | ------------------------------------------- | ----
入力     | Youtube (1日の再生時間/再生ビデオ数)        | 心
入力     | 1日の検索キーワード数                       | 技
入力     | Google Fit (歩数/運動時間/睡眠時間など)     | 体
入力     | アルコールの有無(DAYLIOの記録を利用)    | 体
予測対象 | 目覚めの気分(5段階評価)                   | - 

もちろん実際には「目覚めの気分」に影響を与える要因は明らかにこれ以外にも多数存在しますが、心技体が揃ったということで先に進ませていただきます。

# 少しデータを眺める

自分自身に関するあらゆる発見がありそうなので本当はゆっくりデータを見ていきたいですが、時間の関係上とりあえず予測対象となる「目覚めの気分」だけでも少し見てみます。
(Youtubeの累計時間などは改めて集計するとちょっと落ち込みそうですし）

## 評価の分布

悪い評価の方が少し多いぐらいで、ほとんどが普通というような分布です。
ちなみに平均値は`2.89`でした。

![daylio_hist.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14471/4c383acf-02e8-f67c-e1b6-d79e6704e5fb.png)


## 曜日別の平均点

予測に役立つかは分かりませんが、ちょっと興味があったので見てみました。

![weekday.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14471/ab516aca-6114-d2d5-a679-753542689d1c.png)

土日のほうが評価が悪いです。(統計的に優位な差はありませんでしたが）
その理由はよくわかりませんが、私が分からないなら誰にも分からないでしょう。


# データ補正

## 特徴量エンジニアリング

翌朝の気分は前日だけのアクティビティに影響を受けるとは限りませんので、前々日などのアクティビティも加味するようにしました。
例えば「当日の歩数」を以下のように増幅しています。

3日前の歩数 | 2日前の歩数 | 前日の歩数 | 3日間の累計
---------- | ---------- | --------- | -----------
8,000      | 12,000     | 5,000     | 25,000  

ちなみに過去データを参照するようにしたので、学習の際には時系列の順序を考慮してテストデータの分割等をする必要が出てきます。

あとは曜日が少し影響していそうだったので、曜日の情報なども追加しています。

## 運用上の考慮

ところでこの予測モデルで「目覚め気分」はいつ使うのでしょうか？
例えばその日の「睡眠時間」を特徴量として入れると、翌朝目覚めたあとにしか予測できません。
そんな予測モデルはなんの役にも立ちません。と偉そうに言っていますが、この事実に後から気付き特徴量から削除しました。
と言うわけで運用まで想定したモデル設計の重要性を学びました。

ここでは、前日の寝る前に予測できれば良いという想定で特徴量を選択しておきました。
(前日の夜に翌朝の「目覚め気分」が分かって何が嬉しいのか？という話はいったん置いておきます)

## 欠損処理

平均値で補完しています。
簡単な検証しかできませんでしたが、少なくとも何もしないよりはましだったので。

# 予測モデルの構築

今回は精度を追い求める事は諦め、信頼と実績の [LightGBM](https://github.com/microsoft/LightGBM) を使用しました。

「目覚めの気分」は5段階評価ですが、ここでは連続値とみなし回帰問題としてRMSE(二乗平均平方根誤差)を最小化するタスクとして学習を行いました。

なおハイパーパラメータは [optuna](https://optuna.org/) を使用させていただき、軽くチューニングは実施しました。[^1]

[^1]: [Optuna の拡張機能 LightGBM Tuner によるハイパーパラメータ自動最適化](https://tech.preferred.jp/ja/blog/hyperparameter-tuning-with-optuna-integration-lightgbm-tuner/)

# モデル評価

## ベースライン

最終的に得られた予測モデルの性能を評価するために、ベースラインを定めておきます。

ここでは「目覚めの気分」の過去の平均値を、予測値として常に返すようなモデルをベースモデルとして考えます。
目覚めの気分はなんとなく正規分布に近そうだったので、RMSEを最小化するという観点では平均値は妥当な選択かと思います。[^2]

[^2]: [精度評価指標と回帰モデルの評価](https://funatsu-lab.github.io/open-course-ware/basic-theory/accuracy-index/#rmse)

## 予測モデルの結果

予測モデルの結果をベースラインと並べて表示します。

モデル | RMSE | MAE
------- | ---- | -----------
ベースモデル | 0.49 | 0.32
予測モデル   | 0.43 | 0.29

たいして良くなっていませんね…

とはいえベースラインよりは改善されているので、この予測モデルの存在は全く無駄とは言えません。ということにします。

残差に関しても多少なりとも小さく改善しようとする努力の跡は感じるので。
（テストデータに対する結果です）

![res.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14471/470dffe1-a463-021b-1811-fc271de8e7c6.png)


# 考察

## 「目覚めの気分」に影響を与える要因

予測モデルから何が「目覚めの気分」を決める要因となっているのか、少し見てみます。
要因が分かれば、良い目覚めのために行動習慣を変えるモチベーションが生まれるかもしれません。

まずは各特徴量について、重要度のトップ5のみを出力してみます。
どうも運動に関することだけですね。

特徴量                   | 重み
---------------------   |---------------
2日前の「強めの運動時間」 | 0.071
3日間累計の「徒歩最大速度」 | 0.071
前日の「徒歩時間」 | 0.071
前日の「最大心拍数」 | 0.057
前日の「運動時間」 | 0.057

なお重要度は[feature_importances_](http://devdoc.net/bigdata/LightGBM-doc-2.2.2/Python-API.html#lightgbm.LGBMModel.feature_importances_)から取得しています。

次に[partial_dependence](https://scikit-learn.org/stable/auto_examples/inspection/plot_partial_dependence.html)を用いて、個人的に気になった特徴量が具体的にどのように効いているのかを見てみます。

### 「強めの運動時間」

前日ではなく、なぜか2日前の「強めの運動時間」のみが要因として強く効いていました。
そして「目覚めの気分」への影響は以下のように効いているようです。

![hard_min_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14471/0ae661ae-02b9-d13d-7cad-b30110003419.png)

つまり、良い目覚めのためには、2日前に60分程度の運動をするのが良いそうです。
やり過ぎは良くない。

### 「徒歩距離」

歩いた距離である「徒歩距離」も前日ではなく2日前が影響を与えていました。
こちらは歩く距離が多いほど、良い目覚めに繋がるようですね。

![distance_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14471/949afc33-4222-871e-a268-8089b442f60a.png)

ちなみにこの前日ではなく2日前という傾向は、単純に年のせいとかだったりするのでしょうか…

### お酒の影響

お酒の影響は個別に出ていないのですが、3日間の累計にて現れていました。
つまり私の場合、過去3日間の間に1日でもお酒を飲んでいると目覚めに悪い影響を与えるようです。
(青い線はわかりやすいように追加）

![sake.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14471/c3a2384e-4750-5170-4f30-307244fcb6e0.png)

とはいえ微々たる影響なので無視しても良いでしょう。

## 明日の目覚めを予測する

予測モデルの本来の役割である、予測に使ってみます。
(厳密にはアルコールの有無は翌朝入力することになっているのですが、アルコール無しとします。実際今日は呑んでませんし。)

今日時点のデータで明日の目覚めを予測した結果…

明日の「目覚めの気分」は`3.19`でした。
私の平均値は「普通」以下の`2.89`だったので、明日の目覚めは多少期待できそうです。

# まとめ

日々のアクティビティをもとに、翌日の「目覚めの気分」を予測するモデルを作りました。

時間の都合により満足できるモデルが構築できたとは言えませんが、自分のデータを利用する楽しさは感じられました。

ただいくつか問題が判明しており、データ量も少ないためか、特徴量を少し変えるだけで結果も結構変わってしまったので、「目覚めの気分」の記録はもう少し続けてみる気になりました。

なお記事を推敲する時間が取れず、分かりにくい内容になってしまい誠に恐縮ではございますが、明日の良い目覚めに影響が出ると困るので今日は眠ることにします。

おやすみなさい。