スマホの加速度センサで行動識別してみた

#はじめに
前回投稿した[誰でもできちゃうSVMによるパターン認識](https://qiita.com/seaka829/items/79fa628083a17456310f)で、SVMによるパターン認識を実装しました。
本記事では、前回作成したプログラムを使って、スマートフォンの加速度センサから行動を分類したいと思います。

具体的には、以下の4状態を学習させ、モデルを生成し、テストデータが正しく分類されるか確認します。

- スマホを机の上に置き、静止させた時のデータ
- スマホを手で持ち、全力で振った時のデータ
- スマホをポケットに入れて、歩いた時のデータ
- スマホをポケットに入れて、走った時のデータ

#環境

###使用スマートフォン
iPhoneX【iOS 12.3.1】

###使用アプリ
[加速度ロガー](https://apps.apple.com/jp/app/%E5%8A%A0%E9%80%9F%E5%BA%A6%E3%83%AD%E3%82%AC%E3%83%BC/id340777156)を使用させていただきます。
サンプリング周波数は、100Hzに設定しました。

#学習データの準備

###測定
今回は、各状態を10秒以上測定して、1000サンプルづつ(計4000サンプル)用意しました。

###前処理
入力データの項目は、以下の3つにしました。

- 3軸の合成加速度(以降、合成加速度)
- 直近10サンプルの合成加速度の平均(以降、移動平均)
- 直近10サンプルの合成加速度の標準偏差(以降、移動標準偏差)

スマホの向きを意識しないために、合成加速度を算出しました。
以下の式で合成加速度を算出することができます。

```math
(合成加速度) = \sqrt{(x軸の加速度)^2 + (y軸の加速度)^2 + (z軸の加速度)^2}
```

移動平均と移動標準偏差は以下のようにexcelで算出しました。
![excel.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108396/074dcd4f-1291-9a12-a387-2bc23ab1c508.png)

この状態でcsvで保存
↓
必要ない項目(HHmmss,x,y,z)と項目名を削除
↓
1000サンプルに調整

この手順で、4種類のデータの前処理を行います。

最終的に、以下のようなデータが出来上がると思います。

```learning_data.csv
1.00110588850531,1.0013994655249,0.000458744411473901,1
1.00210229018798,1.00139911591093,0.000458969293511815,1
1.00209231111709,1.00119778649611,0.000540661891005046,1
                  (997サンプル省略)
3.7148344512239,5.48437407500024,2.1345990737057,2
2.68436305294198,5.44778885322339,2.16749567720329,2
2.53429714122082,5.41660172074124,2.20888159457746,2
                  (997サンプル省略)
1.6548153975595,1.12418356215442,0.643001802938213,3
1.66477025441951,1.04119371895031,0.622384960951361,3
1.81568444394944,0.981822482334172,0.587403194733536,3
                  (997サンプル省略)
3.18631856536662,2.63215261941083,1.53650426566909,4
2.39536489913332,2.62277489846566,1.53271874591551,4
1.25657033229342,2.61339717752049,1.53891923881491,4
                  (997サンプル省略)
```

左から、合成加速度、移動平均、移動標準偏差、正解データ
正解データは、以下のようになっています。

- 1 ... スマホを机の上に置き、静止させた時のデータ
- 2 ... スマホを手で持ち、全力で振った時のデータ
- 3 ... スマホをポケットに入れて、歩いた時のデータ
- 4 ... スマホをポケットに入れて、走った時のデータ

#テストデータの準備
4状態のデータを新たに測定します。
学習データ同様、合成加速度・移動平均・移動標準偏差を算出。
4状態のテストデータを以下のように、500サンプルで準備しました。

```test_stop.csv(スマホを机の上に置き、静止させた時のデータ)
0.999313264196968,1.00080864557593,0.00120620913504573
0.999264729688785,1.00110610743585,0.00116689958774459
1.00231182772628,1.00120848030656,0.00103873107094196
                  (497サンプル省略)
```

```test_shake.csv(スマホを手で持ち、全力で振った時のデータ)
0.999313264196968,1.00080864557593,0.00120620913504573
0.999264729688785,1.00110610743585,0.00116689958774459
1.00231182772628,1.00120848030656,0.00103873107094196
                  (497サンプル省略)
```

```test_walk.csv(スマホをポケットに入れて、歩いた時のデータ)
0.999313264196968,1.00080864557593,0.00120620913504573
0.999264729688785,1.00110610743585,0.00116689958774459
1.00231182772628,1.00120848030656,0.00103873107094196
                  (497サンプル省略)
```

```test_run.csv(スマホをポケットに入れて、走った時のデータ)
0.999313264196968,1.00080864557593,0.00120620913504573
0.999264729688785,1.00110610743585,0.00116689958774459
1.00231182772628,1.00120848030656,0.00103873107094196
                  (497サンプル省略)
```

左から、合成加速度、移動平均、移動標準偏差になっています。

#コードの編集
500サンプル中の正解数を表示するために、前回のコードを少し編集します。
編集する箇所は、
- estimateメソッド
- 学習データとテストデータのパス

```main.js
/**
 * モデルからテストデータの分類を行う関数
 * @param {Array.<Array.<number>>} テストデータ
 */
function estimate(arr) {
    if(newModel) {  // モデルのnullチェック
        var result = Array(arr.length);
        for(var i=0; i<arr.length; i++) {
            result[i] = newModel.predictSync(arr[i]);   // モデルからテストデータを分類
            // console.log(result[i]);                     // 結果の表示
        }
        var result1 = 0,
            result2 = 0,
            result3 = 0,
            result4 = 0;
        for(var i=0; i<result.length; i++) {
            switch(result[i]) {
                case 1:
                    result1++;
                    break;
                case 2:
                    result2++;
                    break;
                case 3:
                    result3++;
                    break;
                case 4:
                    result4++;
                    break;
            }
        }
        console.log("1... " + result1 + "/" + result.length);
        console.log("2... " + result2 + "/" + result.length);
        console.log("3... " + result3 + "/" + result.length);
        console.log("4... " + result4 + "/" + result.length);
    }
}
```

#結果
4状態のテストデータの分類結果は、以下のようになりました。

```terminal
$ node main.js # 1...スマホを机の上に置き、静止させた時のデータ
1... 500/500
2... 0/500
3... 0/500
4... 0/500
$ node main.js # 2...スマホを手で持ち、全力で振った時のデータ
1... 0/500
2... 486/500
3... 0/500
4... 14/500
$ node main.js # 3...スマホをポケットに入れて、歩いた時のデータ
1... 67/500
2... 0/500
3... 397/500
4... 36/500
$ node main.js # 4...スマホをポケットに入れて、走った時のデータ
1... 0/500
2... 11/500
3... 145/500
4... 344/500
```

そこそこの精度ですね！

#最後に
今回は、そこそこの精度で4つの行動を分類することができました。
精度をあげるために、出来ることはいくつかあると思いますが、今回はここらへんで一度辞めたいと思います。