Python 中的多维动态时间规整实现 - 确认?

数据挖掘 Python 聚类 时间序列 无监督学习 距离
2022-03-04 05:43:34

我相信我在这里用 python 实现了 MDTW,但我不知道我是否做得正确。结果看起来很直观。有人可以查看此代码并告诉我您是否发现任何问题?

我读到的很多关于这个主题的论文有点让我头晕目眩,但这只是在给定窗口w内的每个时间点取矩阵s1s2中所有列向量的 mse,而不是一维动态时间扭曲,它只需要两个向量之间每个值的 mse 误差并找到最小的一个。

我使用 panda 的 Panel,它本质上是 DataFrame 的 3D 版本。

另外,在我有了这个之后,我想用一些多维时间序列进行聚类。关于运行哪种聚类算法的想法?克米恩斯?分层的?我将首先建立一个树状图。

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

def MDTWDistance(s1, s2, window=10, num_columns=1):
    DTW={}

    w = max(window, abs(len(s1)-len(s2)))

    for i in range(-1,len(s1)):
        for j in range(-1,len(s2)):
            DTW[(i, j)] = float('inf')
    DTW[(-1, -1)] = 0

    for i in range(len(s1)):
        for j in range(max(0, i-w), min(len(s2), i+w)):
            #print "Finding Distance of", s1.loc[i], s2.loc[j]
            dist= mdist(s1.loc[i], s2.loc[j], num_columns)
            #print "Dist", dist
            #print i, j, dist
            DTW[(i, j)] = dist + min(DTW[(i-1, j)],DTW[(i, j-1)], DTW[(i-1, j-1)])

    return np.sqrt(DTW[len(s1)-1, len(s2)-1])

def mdist(a, b, num_col):
    dist = 0
    for col in range(num_col):
        #print "Finding Distance of", a[col], b[col]
        dist = dist + (a[col]-b[col])**2
    return dist

x=np.linspace(0,50,100)
ts1=pd.Series(3.1*np.sin(x/1.5)+3.5)
ts2=pd.Series(2.2*np.sin(x/3.5+2.4)+3.2)
ts3=pd.Series(0.04*x+8.0)
ts4=pd.Series(0.048*x+8.6)
ts5=pd.Series(-0.17*x+4.1)
ts6=pd.Series(-0.14*x+4.5)

ts1.plot()
ts2.plot()
ts3.plot()
ts4.plot()
ts5.plot()
ts6.plot()

plt.ylim(-4,12)
plt.legend(['ts1','ts2','ts3','ts4','ts5','ts6'])
plt.show()

timeSeries = pd.Panel({0:pd.DataFrame(np.transpose([ts1, ts2])),
                 1:pd.DataFrame(np.transpose([ts3, ts4])),
                   2:pd.DataFrame(np.transpose([ts5, ts6]))
                  })

print "0 and 1:",MDTWDistance(timeSeries[0], timeSeries[1],window=10, num_columns=2)
print "0 and 2:",MDTWDistance(timeSeries[0], timeSeries[2],window=10, num_columns=2)
print "1 and 2:",MDTWDistance(timeSeries[1], timeSeries[2],window=10, num_columns=2)

输出如下:

0 and 1: 89.354619036
0 and 2: 58.8268328591
1 and 2: 133.434513377

用图表:

在此处输入图像描述

编辑:我使用 R 中的 MDTW 包找到了距离,代码如下:

import rpy2.robjects.numpy2ri
from rpy2.robjects.packages import importr
rpy2.robjects.numpy2ri.activate()

# Set up our R namespaces
R = rpy2.robjects.r
DTW = importr('dtw')

# Generate our data
idx = np.linspace(0, 2*np.pi, 100)
template = np.cos(idx)
query = np.sin(idx) + np.array(R.runif(100))/10

for i,j in ([0,1], [0,2], [1,2]):
    print "From", i, "to", j, R.dtw(np.transpose(np.array(timeSeries[i])), np.transpose(np.array(timeSeries[j])), keep=True).rx('distance')[0][0]

哪个输出:

From 0 to 1 186.623310713
From 0 to 2 119.769089068
From 1 to 2 272.849560995

所以这些数字大约是我距离的两倍......所以我离得不远,但我正在做的事情有问题。哈尔普。

2个回答

差异可能是由您使用的步进模式引起的吗?R 中的 Dtw 默认为symmetric2步进模式。Toni Giorgino 的论文中对步进模式的解释

symmetric2 是可归一化的、对称的,没有局部斜率约束。由于一个对角线步长与沿边的两个等效步长一样多,因此可以对其进行归一化除以(查询+参考长度)。N+M

在阅读Comparing Dynamic Time Warping in R and Python之后,我认为这可能是问题所在

如果您的问题相同,请尝试添加step=symmetric1您的R.dtw论点。

此处显示的代码是用于时间序列分析的动态规划的递归实现以进行相似性分析,但有一个更优化的实现,称为快速动态时间规整,可将时间和内存复杂度显着降低到O(n)

您将看到与原始 DTW 相比的显着改进,尽管测量的距离将直接受到所使用的距离测量的影响(通常是此处所示的 ecludidean 距离)。但是根据时间序列的性质,还有其他一些可以提供更好的结果。