質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
機械学習

機械学習は、データからパターンを自動的に発見し、そこから知能的な判断を下すためのコンピューターアルゴリズムを指します。人工知能における課題のひとつです。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

1回答

3956閲覧

時系列データに対するk近傍法の精度の評価について

AI_engineer

総合スコア15

機械学習

機械学習は、データからパターンを自動的に発見し、そこから知能的な判断を下すためのコンピューターアルゴリズムを指します。人工知能における課題のひとつです。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2020/11/09 05:34

時系列データに対るk近傍法の適用
↑こちらの質問の延長のような質問になっています。

時系列データ(加速度データ)に対しk近傍法を使ってx軸加速度の異常度をグラフ化してみました。
異常箇所でしっかりと高い異常度の値を出すことができました。
ここで質問ですが、
・どのくらいの異常度の値をとると異常と判定すればよいのか。閾値の決め方について
・実際に元データと比べてどれくらいの精度で異常判定ができているかを評価するにはどのようなコードをかけばよいか

という2点の疑問が残ります。

どなたかご教授お願いします。

python

1import pandas as pd 2import numpy as np 3import matplotlib.pyplot as plt 4from sklearn.neighbors import NearestNeighbors 5 6 7''' 8dataをsize毎のスライス窓に分割 9''' 10 11def main(): 12 df = pd.read_csv("20191121.csv") 13 14 # 余分なデータをDataFrameから削除 15 df = df.drop(['name', 'x_rad/s', 'y_rad/s', 'z_rad/s'], axis=1) 16 17 df = df.set_index('time') 18 19 #x, y, z軸加速度を視認化 20 df.plot().legend(loc='upper left') 21 22 # 前から2480件のx軸加速度を学習データ、その次の2479件をテストデータとする 23 # # df.iloc[2479] ---> 53845130 24 # df.iloc[2480] ---> 53845150 25 train_data = df.loc[:53845130, 'x_ags'] 26 test_data = df.loc[53845150:, 'x_ags'].reset_index(drop=True) 27 28 # 窓幅 29 width = 30 30 31 # k近傍法のk 32 nk = 1 33 34 # 窓幅を使ってベクトルの集合を作成 35 train = embed(train_data, width) 36 test = embed(test_data, width) 37 38 # k近傍法でクラスタリング 39 neigh = NearestNeighbors(n_neighbors=nk) 40 neigh.fit(train) 41 42 # 距離を計算 43 d = neigh.kneighbors(test)[0] 44 45 # 距離の正規化 46 mx = np.max(d) 47 d = d / mx 48 49 # 訓練データ 50 plt.subplot(221) 51 plt.plot(train_data, label='Training') 52 plt.xlabel("Amplitude", fontsize=12) 53 plt.ylabel("Sample", fontsize=12) 54 plt.grid() 55 leg = plt.legend(loc=1, fontsize=15) 56 leg.get_frame().set_alpha(1) 57 58 # 異常度 59 plt.subplot(222) 60 plt.plot(d, label='d') 61 plt.xlabel("Amplitude", fontsize=12) 62 plt.ylabel("Sample", fontsize=12) 63 plt.grid() 64 leg = plt.legend(loc=1, fontsize=15) 65 leg.get_frame().set_alpha(1) 66 67 # 検証用データ 68 plt.subplot(223) 69 plt.plot(test_data, label='Test') 70 plt.xlabel("Amplitude", fontsize=12) 71 plt.ylabel("Sample", fontsize=12) 72 plt.grid() 73 leg = plt.legend(loc=1, fontsize=15) 74 leg.get_frame().set_alpha(1) 75 76 77def embed(lst, dim): 78 emb = np.empty((0, dim), float) 79 for i in range(lst.size - dim + 1): 80 tmp = np.array(lst[i:i+dim])[::-1].reshape((1, -1)) 81 emb = np.append(emb, tmp, axis=0) 82 return emb 83 84if __name__ == '__main__': 85 main()

左上:加速度の訓練データ,右上:異常度,左下:加速度のテストデータ

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

k近傍法を少し勘違いされているかもしれません。

k=1でのk近傍法は、「最も近い距離の訓練データと同じ正解を採用する」というもので、その判断に距離の大小は関係ありません。

ウィキペディア-k近傍法
「k = 1 のときの k近傍法を、最近傍法と呼び、最も近傍にある訓練例のクラスを採用する。」

なお、上記の話にk=1は本質的ではありません。k>1でも絶対距離にはあまり関係なく、近い順からk個の訓練データを選択して、その結果の多数決で正解を予測します。k近傍法では、kを決めた後は予測において、距離順番の大小は関係ありますが絶対距離の大小は関係ありません

逆に、ドメイン知識から、「そうはいっても絶対距離の大小で判断が変わるのが正しい」と感じるのでしたら、k近傍法は適していない、ということです。他の手法を考えてみましょう。

投稿2020/11/09 11:08

編集2020/11/09 11:09
toast-uz

総合スコア3266

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

AI_engineer

2020/11/09 13:33

回答ありがとうございます。 k近傍法について色々調べている途中で、大まかに理解しているつもりでした。 私の解釈としては、 例えばk=5であればテストデータのベクトルから距離の短い順に学習データからベクトルを5個とり、その5個のベクトルの中で最も多いクラスにテストデータは分類される。 (距離の短い順に5つのベクトルをとるだけであって、距離の大きさは関係ない) と考えています。 しかし、これを時系列データに置き換えたときにいまいち理解ができず混乱してしまいます。 例えば時系列データとして, X=(x_1, x_2, ..., x_3000)のデータがあると仮定したとき、窓幅(WN)を30ととると、 W=(W_1, W_2, ..., W_100)、W_1=(x_1, ..., x_30),W_2=(x_2, ... x_31), ...と分割されると思います。 このときW_1~W_50を訓練データ、W_51~W_100を検証データとすると、k=1の時、W_51の予測ベクトル値はW_1~W_50の中で最も距離の近いベクトル値になる。そして、W_51から最も近いベクトル値(W_1~W_50)までの絶対距離を異常度としている。 すなわち、実際に得られた検証データW_51のベクトル値がW_1~W_50までの学習データのどのベクトル値よりも距離が離れていれば異常度が高くなる。 異常度が予め設定した閾値を超えていれば異常と判定、そうでなければ正常と判定する。 という風に解釈しています。 この解釈であると、私がソースコードの中で計算している異常度は検証データと学習データの絶対距離になり、時系列データの異常度を計算するためにk近傍法を用いてそこから異常判定をする、というような流れになると思うのですがどうでしょうか。 自分でも時系列データに対するk近傍法の理論はいまいち理解できていないと感じているので解釈を間違えている箇所があればご指摘をお願いします。
toast-uz

2020/11/09 14:23

時間軸は単なる1つの次元であり、特別なものと考えない方が良いです。 例で出されたW_Nがk近傍法におけるユークリッド空間の点であれば、学習データについてはW_Nそれぞれに正常か異常かのラベルがある必要かあります。そこに距離は関係ありません。またW_N同士の前後関係も関係ありません。その前提で、未知のテストデータW_Mに対して、k近傍法により正解か予測されるだけです。
AI_engineer

2020/11/10 06:14

申し訳ありません。理解力が乏しく理解できませんでした。。。 https://recruit.cct-inc.co.jp/tecblog/machine-learning/k-nearest-neighbors/ ↑このサイトではk近傍法を用いてテストデータと学習データの絶対距離を異常度として定義しているように解釈したのですがやはり違うのでしょうか。 また、今まで転倒検知の手法の提案をしていただきましたが、toast-uzさんならまずどの手法の使用を考えるかのご助言をいただきたいです。 以下、転倒検知をする上での条件と転倒の特徴です。 <条件> ・転倒検知の条件として、転倒時の3軸加速度、角速度のみを特徴量とする。 ・できればリアルタイムで検知したい <転倒の特徴> ・転倒後は転倒したままの状態がずっと続くとする。 (通常の転倒ならば転倒後も動くため日常生活の加速度値が高い動作との見極めが困難である。しかし、転倒後、転倒したまま動かないことを仮定するとその特徴を利用して加速度のみで転倒を検知できるのではと考えた。) また今まで異常部位検出を考えていましたが転倒後、転倒した状態がずっと続くことを考えると、窓幅を持った変化点検値で転倒を検知することもできるのではないかと考えたのですがいかがでしょうか。 ご意見をいただけると幸いです。 私自身至らない点が多く回答に苦労するとは思いますがよろしくお願いいたします。
toast-uz

2020/11/10 11:58

リンク先を確認しました。k近傍法は、(1)ベクトルの定義〜(2)距離の算定〜(3)学種データの点群を元にしたk近傍法による予測、というセットだと理解しています。リンク先は(1)(2)しか実施しておらず、(3)が無いため「もはやk近傍法とは言えず(2)距離を1つの特徴量として導出した段階」であると思います。ただし、k近傍法と言えないだけで、手法そのものとしては、窓枠を使った時系列データのベクトル化は、特徴量導出の1つの有力な方法であると思います。なお、stft(短時間フーリエ変換)がこの手法をもっと「ちゃんとした」ものであると思います。 質問者様の状況では、モデルをあてはめる前に、<転倒の特徴>を、よく表せるような特徴量をいろいろ導出することを考えるべきです。先ほどの窓枠を使ったstftも1つですし、1次元CNNもそうですし、「転倒後は転倒したままの状態がずっと続く」みたいな「それなりに動いていたがいきなり急激な加速度が出て、その後ピタッと止まった状態」を数式的に特徴量としてどう表すか、を考えてみるのも有効と思います。それらの特徴量をもとに、ある程度、機械学習を使わなくても、正解の判別ができるようなロジックを考えてみてください。そこまでできれば、判別精度をさらに向上するために、機械学習のモデルが使えます。なお、上記でいろいろ説明したモデルは必ずしも1つではありません(GBDTとCNN多クラス分類はだいぶ違います)。よって、個々に結果を求め、それらをアンサンブルという手法でまとめ、結果精度を高めることも考慮しましょう。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問