时间序列聚类是基于相似度或者距离将时间序列数据划分为不同的组,使得同一组的时间序列是相似的。距离或相异度的度量有很多,如欧氏距离、曼哈顿距离、最大范数、海明距离、两个向量之间的角度(内积),以及动态时间规整(DTW)距离。
动态时间规整
动态时间规整(DTW)是要找出两个时间序列之间的最优配置,R语言中的dtw包提供了动态时间规整的实现,在dtw包中,函数dtw(x,y,...)计算动态时间规整并找出时间序列x和y之间的最优配置,函数dtwDist(mx,my=mx,...)或dist(mx, my=mx, method="DTW",...)计算时间序列mx和my之间的距离。示例代码如下:
> library(dtw)
> idx <- seq(0, 2*pi, len=100)
> a <- sin(idx) + runif(100)/10
> b <- cos(idx)
> align <- dtw(a,b, step=asymmetricP1, keep=T)
> dtwPlotTwoWay(align)
合成控制图的时间序列数据
接下来介绍合成控制图时间序列的例子,所使用的数据集来自
kdd.ics.uci/databases/synthetic_control/synthetic_control.data
这个数据集包含了600个控制图,每个控制图都是一个包含了60个值的时间序列,并且分为6类:
1~100:常规。
101~200:循环。
201~300:递增趋势。
301~400:递减趋势。
401~500:向上偏移。
501~600:向下便宜。
首先是使用函数read.table()将数据读入R中,当使用空格作为分隔符时,将参数seq设置为“”(双引号之间没有空格),即一个或多个空格、制表符、换行符或回车符。
> sc <- read.table("./synthetic_control.data", header=F, sep="")
> idx <- c(1,101,201,301,401,501)
> sample1 <- t(sc[idx,])
> plot.ts(sample1, main="")
基于欧氏距离的层次聚类
我们从每一种类的时间序列中随机抽取10个案例,否则原始数据集中的样本点太多将导致层次聚类的结果图像很拥挤。
> set.seed(6218)
> n <- 10
> s <- sample(1:100, n)
> idx <- c(s,100+s,200+s,300+s,400+s,500+s)
> sample2 <- sc[idx,]
> observedLabels <- rep(1:6, each=n)
> hc <- hclust(dist(sample2),method="average")
> plot(hc, labels=observedLabels,main="")
> rect.hclust(hc,k=6)
> memb <- cutree(hc, k=6)
> table(observedLabels,memb)
memb
observedLabels 1 2 3 4 5 6
1 10 0 0 0 0 0
2 1 6 2 1 0 0
3 0 0 0 0 10 0
4 0 0 0 0 0 10
5 0 0 0 0 10 0
6 0 0 0 0 0 10
从上图展示的层次聚类结果可以看到:递增趋势(类别3)与向上偏移(类别5)没有十分明确的划分,递减趋势(类别4)与向下偏移(类别6)也存在重叠。
基于DTW距离的层次聚类
接下来我们尝试基于DTW距离的层次聚类。
> library(dtw)
> distMatrix <- dist(sample2, method="DTW")
> hc <- hclust(distMatrix, method="average")
> plot(hc, labels=observedLabels, main="")
> rect.hclust(hc,k=6)
> memb <- cutree(hc, k=6)
> table(observedLabels,memb)
memb
observedLabels 1 2 3 4 5 6
1 10 0 0 0 0 0
2 0 7 3 0 0 0
3 0 0 0 10 0 0
4 0 0 0 0 7 3
5 2 0 0 8 0 0
6 0 0 0 0 0 10
从结果来看:和基于欧式距离的层次聚类相比,在衡量两个时间序列的相似度时,基于DTW距离的层次聚类性能要更好。