为什么在 proxy::dist 中使用自定义邻近函数会使它在 R 中变得如此缓慢?
Why using a custom proximity function in proxy::dist makes it so slow in R?
我正在尝试将 proxy::dist
函数与自定义距离矩阵一起使用,但我现在的速度很慢。
这是我如何调用自定义函数的可重现示例:
set.seed(1)
test <- matrix(runif(4200), 60, 70)
train <- matrix(runif(4200), 60, 70)
dMatrix <- proxy::dist(x = test, y = train, method = customDTW,
by_rows = T,
auto_convert_data_frames = T)
它应该计算 test
矩阵中每个时间序列与 train
矩阵中所有时间序列(每一行都是一个时间序列)之间的距离。
我的自定义函数是:
customDTW <- function(ts1, ts2){
d <- dtw(ts1, ts2,
dist.method = "Euclidean",
window.type = "sakoechiba",
window.size = 20
)
return(d$distance)
}
问题是,比起我用method="DTW"
,甚至比起我自己计算距离矩阵的情况,这都非常慢,而且随着时间序列的长度或它们的数量在增长,它呈指数级变慢。当然这源于嵌套循环,但我对效果的规模感到惊讶。我看不到它一定还有其他原因。
我的问题是我还可以如何使用proxy::dist
?
实现我的customDTW
以使其更快
这是我对执行时间的小实验:
60X7
的执行时间(使用 proxy::dist
+ customDTW
)
user system elapsed
2.852 0.012 2.867
60X70
的执行时间(使用 proxy::dist
+ customDTW
)
user system elapsed
5.384 0.000 5.382
60X700
的执行时间(使用 proxy::dist
+ customDTW
)
user system elapsed
509.088 18.652 529.115
60X700
的执行时间(没有 使用proxy::dist
)
user system elapsed
26.696 0.004 26.753
DTW 本质上很慢
您是否考虑过尝试使用 dtwclust(dtw 的并行实现)
https://github.com/asardaes/dtwclust
https://cran.r-project.org/web/packages/dtwclust/vignettes/dtwclust.pdf
这是我发现的,似乎提高了速度,但仍然没有我预期的那么快。 (任何其他想法仍然非常受欢迎。)
诀窍是使用 proxy
(即 Registry of proximities here)注册自定义距离函数,这样您就可以像内置距离测量。所以,首先:
proxy::pr_DB$set_entry(FUN = customDTW, names=c("customDTW"),
loop = TRUE, type = "metric", distance = TRUE)
现在您可以使用它,就像它已经在 proxy
包中一样。
dMatrix <- proxy::dist(x = test, y = train, method = "customDTW",
by_rows = T,
auto_convert_data_frames = T)
注意:如果要使用这种方法,那么customDTW
方法必须处理一对时间序列,而不是全部。所以 customDTW
看起来像这样:
customDTW2 <- function(ts1, ts2){
d <- dtw(ts1, ts2,
dist.method = "Euclidean",
window.type = "sakoechiba",
window.size = 20
)
return(d$distance)
}
有关更多信息,请参阅 ?pr_DB
。
R 是一种解释型语言,在底层是用 C 实现的。据我了解,代理包是在 C 中使用 R 的解释能力多次调用 R 代码,但仍然可以'避免解释的开销,所以几乎所有 "pure" R 实现都会变慢。
用proxy注册函数时指定loop=TRUE
意味着会发生上述情况(proxy会多次解释R代码来填充距离矩阵)。如果你真的想加快速度,你需要在 C/C++ 中实现填充本身,并使用 loop=FALSE
向代理注册函数;这就是 dtwclust 所做的(除其他外)。
如果您想测试自己的自定义 C/C++ 函数,即使您不想使用并行化,也可能需要查看 parallelDist 包。
我正在尝试将 proxy::dist
函数与自定义距离矩阵一起使用,但我现在的速度很慢。
这是我如何调用自定义函数的可重现示例:
set.seed(1)
test <- matrix(runif(4200), 60, 70)
train <- matrix(runif(4200), 60, 70)
dMatrix <- proxy::dist(x = test, y = train, method = customDTW,
by_rows = T,
auto_convert_data_frames = T)
它应该计算 test
矩阵中每个时间序列与 train
矩阵中所有时间序列(每一行都是一个时间序列)之间的距离。
我的自定义函数是:
customDTW <- function(ts1, ts2){
d <- dtw(ts1, ts2,
dist.method = "Euclidean",
window.type = "sakoechiba",
window.size = 20
)
return(d$distance)
}
问题是,比起我用method="DTW"
,甚至比起我自己计算距离矩阵的情况,这都非常慢,而且随着时间序列的长度或它们的数量在增长,它呈指数级变慢。当然这源于嵌套循环,但我对效果的规模感到惊讶。我看不到它一定还有其他原因。
我的问题是我还可以如何使用proxy::dist
?
customDTW
以使其更快
这是我对执行时间的小实验:
60X7
的执行时间(使用 proxy::dist
+ customDTW
)
user system elapsed
2.852 0.012 2.867
60X70
的执行时间(使用 proxy::dist
+ customDTW
)
user system elapsed
5.384 0.000 5.382
60X700
的执行时间(使用 proxy::dist
+ customDTW
)
user system elapsed
509.088 18.652 529.115
60X700
的执行时间(没有 使用proxy::dist
)
user system elapsed
26.696 0.004 26.753
DTW 本质上很慢 您是否考虑过尝试使用 dtwclust(dtw 的并行实现)
https://github.com/asardaes/dtwclust
https://cran.r-project.org/web/packages/dtwclust/vignettes/dtwclust.pdf
这是我发现的,似乎提高了速度,但仍然没有我预期的那么快。 (任何其他想法仍然非常受欢迎。)
诀窍是使用 proxy
(即 Registry of proximities here)注册自定义距离函数,这样您就可以像内置距离测量。所以,首先:
proxy::pr_DB$set_entry(FUN = customDTW, names=c("customDTW"),
loop = TRUE, type = "metric", distance = TRUE)
现在您可以使用它,就像它已经在 proxy
包中一样。
dMatrix <- proxy::dist(x = test, y = train, method = "customDTW",
by_rows = T,
auto_convert_data_frames = T)
注意:如果要使用这种方法,那么customDTW
方法必须处理一对时间序列,而不是全部。所以 customDTW
看起来像这样:
customDTW2 <- function(ts1, ts2){
d <- dtw(ts1, ts2,
dist.method = "Euclidean",
window.type = "sakoechiba",
window.size = 20
)
return(d$distance)
}
有关更多信息,请参阅 ?pr_DB
。
R 是一种解释型语言,在底层是用 C 实现的。据我了解,代理包是在 C 中使用 R 的解释能力多次调用 R 代码,但仍然可以'避免解释的开销,所以几乎所有 "pure" R 实现都会变慢。
用proxy注册函数时指定loop=TRUE
意味着会发生上述情况(proxy会多次解释R代码来填充距离矩阵)。如果你真的想加快速度,你需要在 C/C++ 中实现填充本身,并使用 loop=FALSE
向代理注册函数;这就是 dtwclust 所做的(除其他外)。
如果您想测试自己的自定义 C/C++ 函数,即使您不想使用并行化,也可能需要查看 parallelDist 包。