以下を参考にDTWを実装し、それを用いてズレのある2つの時系列データを揃えようとしています。
http://emoson.hateblo.jp/entry/2014/11/03/023224
2つの時系列データを用意し、DTWの距離が最小となるように一方のデータをずらしていくことで揃えられると思ったのですが、どうもうまくいきません。
データの100の位置が揃うように、5個分ずらすと見た目ぴったり重なるのですが、ズレの結果を求めようとしても答えが5個分にならず、直観に反する答えが返ってきます。
・DTWの実装がおかしい
・DTWの使い方がおかしい
どこがおかしいのか教えていただけますでしょうか。
よろしくお願いします。
DTWの実装
//2つの時系列データのDTW距離を計算する
public static double dtw(List<Double> list1, List<Double> list2){
//ループ用のサイズを取得
int size1 = list1.size();
int size2 = list2.size();
//行列を定義する
double[][] matrix = new double[size1 + 1][size2 + 1];
//行列に初期値をセット
for (int i = 0; i < size1; i++){
for (int j = 0; j < size2; j++){
matrix[i][j] = Double.POSITIVE_INFINITY;
}
}
matrix[0][0] = 0;
//ループ開始
for (int i = 1; i <= size1; i++){
for (int j = 1; j <= size2; j++){
double cost = Math.abs(list1.get(i - 1) - list2.get(j - 1));
matrix[i][j] = cost + Math.min(matrix[i - 1][j], Math.min(matrix[i][j - 1], matrix[i - 1][j - 1]));
}
}
//結果出力
return matrix[size1][size2];
}
ズレの結果を求める
//listを左にずらしていったときにDTW距離が最小になるずらし幅を求める
private static int calcLeftDiffByDTW(List<Double> baseList, List<Double> list){
//時系列データそのままをDTW距離の初期値とする
double minDiff = Test.dtw(baseList, list);
//listを左にずらしながら比較する
int resultCnt = 0;
int leftCnt = 0;
for (int i = 0; i < baseList.size() / 2; i++){//ずらすのは半分くらいまででいいだろう
//listの最初の要素を削り、結果的に左に1つずらした時のDTW距離を求める
list.remove(0);
leftCnt++;
//時系列データのサイズが異なってもDTWは定義可能(サイズを合わせた方が良い?)
double diff = Test.dtw(baseList, list);
//DTW距離の最小値といくつずらしたかを保持する
if (minDiff > diff){
minDiff = diff;
resultCnt = leftCnt;
}
}
//結果を見てみる
System.out.println(resultCnt);
System.out.println(minDiff);
return resultCnt; }
2つの時系列データ
1.31 1.2
1.32 1.2
1.34 1.21
1.36 1.21
1.38 1.22
1.42 1.24
1.58 1.25
2.36 1.27
5.49 1.29
13.63 1.31
29.02 1.36
50.63 1.56
72.98 2.52
89.93 5.9
99.08 14.07
100 29.05
91.03 49.75
69.56 71
40.36 87.37
17.2 97.45
6.2 100
2.79 92.92
1.92 72.89
1.61 43.79
1.45 19.15
1.34 6.79
1.26 2.82
1.2 1.84
1.17 1.55
1.15 1.39
1.14 1.27
1.14 1.18
1.12 1.12
1.09 1.09
1.06 1.06
1.04 1.03
あなたの回答
tips
プレビュー