【问题标题】:Efficient multidimensional dynamic time warping implementation高效的多维动态时间规整实现
【发布时间】:2013-12-05 03:36:31
【问题描述】:

以下是文献如何解释如何计算两个时间序列的多维动态时间扭曲:

 library(dtw)
 x<- cbind(1:10,1)
 y<- cbind(11:15,2)
 cxdist <-dist(x,y,method="euclidean")
 dtw(cxdist)$distance

实际上,它首先计算交叉距离矩阵,然后将其用作 dtw 函数的输入。

我想在具有相当大图像的图像分类中使用多维动态时间扭曲。 图像值存储在可能如下所示的数据框中:

 inDf <- data.frame(matrix(rnorm(60), ncol = 6))
 colnames(inDf) <- c('var1t1','var2t1','var1t2','var2t2','var1t3','var2t3')

在这个例子中,有两个变量(var1 和 var2)被观察了 3 次。

问题是如何在计算强度方面以尽可能高的效率获得 dtw 距离矩阵?

以下是一些想法: - 遍历输入图像矩阵的每个值,将向量重塑为矩阵,以便能够计算交叉距离,然后计算 dtw 距离并将其存储在专用矩阵中。 这无疑是计算量最大的解决方案

【问题讨论】:

  • 那么,您需要高效计算 var1 和 var2 之间的距离矩阵(欧几里得)(两者都是相同长度的 3 维数组)吗? IE。在x &lt;- inDf[,c("var1t1","var1t2","var1t3")]y &lt;- inDf[,c("var2t1","var2t2","var2t3")] 之间?
  • 您能否说明inDf 与您的第一个示例有何关联?是var1t1x,和var2t1y,然后再重复另外两个时间段?您是否要计算每个时间段内每对变量的dtw 距离?这些东西与图像有什么关系?另外,看起来dtw 自己计算了dist,所以你不需要这一步。
  • 第一个示例和第二个示例之间的区别在于每个样本测量的变量数量。首先,x 和 y 都是同一唯一变量随时间变化的时间序列。在第二种情况下,每个 x 都由两个变量、两个时间序列来表征。希望更清楚
  • 在第二个例子中,cxdist 的尺寸是多少?据我了解,他们应该是10x10。因此,我们正在计算var1 中的 10 个 3 维点和var2 中的 10 个 3 维点之间的成对距离。对不对?

标签: r performance image-processing distance


【解决方案1】:

在处理密集计算时,考虑Rcpp 包总是有意义的。如果你想更快地得到欧式距离的距离矩阵,可以实现对应的Rcpp函数:

library(Rcpp)
library(inline)

# Rcpp function for euclidean distance
fastdist <- cxxfunction(signature(x="matrix", y="matrix"), plugin="Rcpp",
body='
  Rcpp::NumericMatrix dx(x);
  Rcpp::NumericMatrix dy(y);

  const int N = dx.nrow();
  const int M = dy.nrow();

  Rcpp::NumericMatrix res(N, M);

  for(int i=0; i<N; i++){
    for(int j=0; j<M; j++){
      res(i,j) = sqrt(sum((dx(i,_)-dy(j,_))*(dx(i,_)-dy(j,_))));
    }
  }

  return res;
')

它使用Rcpp 语法sugar 以使代码更紧凑和可读。但是,有时最好使用包装函数来检查类型、强制等。这不是必需的——您可以直接调用fastdist。但是,无论如何,包装器可以是这样的:

# Wrapper R function
fast.dist <- function(x, y){
  stopifnot(class(x) %in% c("data.frame","matrix") &
            class(y) %in% c("data.frame","matrix") &
            ncol(x)==ncol(y))

  fastdist(as.matrix(x), as.matrix(y))
}

现在我们可以转向文学例子。

library(dtw)

# EXAMPLE 1
x<- cbind(1:10,1)
y<- cbind(11:15,2)
# Check results
all.equal(fast.dist(x,y), dist(x,y,method="euclidean"), check.attributes=F)
# [1] "target is matrix, current is crossdist"
all.equal(fast.dist(x,y), matrix(dist(x,y,method="euclidean"), ncol=nrow(y)))
# [1] TRUE

注意,dist 返回类 crossdist 的结果。所以,为了比较,它应该被强制为matrix

现在您的主要问题 - 我们首先生成数据:

# EXAMPLE 2
set.seed(1234)
N <- 100
inDf <- data.frame(matrix(rnorm(6*N), ncol = 6))
colnames(inDf) <- c('var1t1','var2t1','var1t2','var2t2','var1t3','var2t3')

# Extracting variables
var1 <- inDf[,c("var1t1","var1t2","var1t3")]
var2 <- inDf[,c("var2t1","var2t2","var2t3")]

我不完全确定你的数据结构,但无论如何你都可以根据自己的需要准备变量。

比较和基准测试:

library(rbenchmark)

all.equal(fast.dist(var1,var2), matrix(dist(var1,var2), ncol=N))
# [1] TRUE
benchmark(fast.dist(var1,var2), dist(var1,var2), order="relative")[,1:4]
#                    test replications elapsed relative
# 1 fast.dist(var1, var2)          100   0.081    1.000
# 2      dist(var1, var2)          100   0.246    3.037

fast.dist 在这种情况下比dist 快大约 3 倍。然而,虽然N 正在增长,但相对增速将下降。

还请注意,正如 cmets 中提到的,dtw 可以自行计算距离矩阵。然而,预先计算距离矩阵更有效。请参阅下面的快速测试:

cxdist <- fast.dist(var1,var2)
benchmark(dtw(cxdist)$distance, dtw(var1,var2)$distance, order="relative")[,1:4]
#                       test replications elapsed relative
# 1     dtw(cxdist)$distance          100   0.476    1.000
# 2 dtw(var1, var2)$distance          100   0.736    1.546

此外,如果您只对$distance 感兴趣,您可以将distance.only=T 传递给dtw() - 它可以加快速度。

【讨论】:

  • 感谢非常好的回答,非常清楚。我不知道 Rcpp。如果我想在大量样本上应用这个,你有什么想法可以加快这个过程吗?
  • @WAF 谢谢。注意:如果您只对$distance 感兴趣,您可以将distance.only=T 传递给dtw() - 它可以加快速度。至于在大量样本上应用代码。 dtw() 似乎只使用一个内核,因此在多核系统或集群上批量运行处理可能会带来好处。看看foreach 包。
猜你喜欢
  • 1970-01-01
  • 2020-01-31
  • 1970-01-01
  • 2011-06-24
  • 2019-10-02
  • 1970-01-01
  • 1970-01-01
  • 2023-03-24
  • 1970-01-01
相关资源
最近更新 更多