如何减少用于 R 中大数据的 Prado k-means 框架内的内存使用?
How to reduce memory usage within Prado's k-means framework used on big data in R?
我正在尝试验证基于 returns 相关矩阵的 Prado 聚类交易策略的 k-means 框架,如 his paper 中所见,对大量策略使用 R,比如 1000。
他尝试在所有可能的 k 上使用两个 for
循环来寻找最佳 k 和 k-means 的最佳初始化和一些初始化,即 k 从 2 到 N-1,其中 N 是策略数量。
问题是 运行ning k-means 很多次,尤其是有那么多集群时,内存耗尽,而我的计算机 m3.medium 我使用的 AWS 实例都无法做到工作。 (均为 4 GB RAM,但在 AWS 上,后台 RAM 消耗进程较少。)
那么,请问有什么办法可以处理这个内存问题吗?或者至少如何根据使用的策略数量来估计所需的内存量?
我已经尝试了软件包 biganalytics
及其 bigkmeans
功能,但还不够。
我也知道有更高的 RAM AWS 实例,但我想在切换到这样的实例之前确保我的代码是最佳的。
我还尝试限制使用的集群数量,这证实这是主要的内存消耗问题,但我不想坚持这种解决方案(也不会与更好的 AWS 实例结合使用)。
在 AWS 上正确执行的策略的最高数量约为 500。
内存优化的主要部分代码如下:
D <- nrow(dist)
seq.inits <- rep(1:nr.inits,D-2)
seq.centers <- rep(2:(D-1),each = nr.inits)
KM <- mapply(function(x,y){
set.seed(x+333)
kmeans(dist, y)
},seq.inits,seq.centers)
dist
是策略的“returns”相关距离矩阵(即列数等于行数,以及其他属性),nr.inits
是初始化次数。两者都是输入变量。之后,使用剪影得分确定最佳聚类,并在需要时重新聚类。
我知道距离矩阵不适合 k-means 的输入,我也知道数据挖掘问题,所以请不要解决这些问题。
我的上述问题是:
是否可以减少内存使用量,以便我能够在 m3.medium AWS 实例上 运行 1000 个策略?
是否可以至少根据使用的数字策略估计内存使用情况? (假设我尝试 2:(N-1)
个集群。)
其实第二个问题,最好是优化之后,对我来说比较重要。因为我想尝试比 "just" 1000 多得多的策略。
预先感谢您的回答!
不同时存储所有结果适用于许多问题,
即使你不使用 R。
此外,我认为您没有正确使用 kmeans
,
因为它需要你的输入数据,
不是交叉距离矩阵。
同样,您不需要分配所有 seq.centers
。
你提到剪影指数,
可以用cluster::silhouette
计算,所以:
library(cluster)
data(ruspini) # sample data included in the cluster package
由于您的数据没有改变,
你可以预先计算交叉距离矩阵:
dm <- dist(ruspini)
您想要的工作流程中的一个 "iteration" 是:
km <- kmeans(ruspini, 2) # try 2 clusters
score <- mean(cluster::silhouette(km$cluster, dist = dm)[,3L])
你想为同一个 k
集群随机启动几个:
num_starts <- 2L
scores <- sapply(seq_len(num_starts), function(ignored) {
km <- kmeans(ruspini, 2)
mean(cluster::silhouette(km$cluster, dist = dm)[,3L])
})
注意只保存分数,
没有聚类结果。
您还想要 k
:
的不同值
max_k <- 3L
num_starts <- 2L
scores <- sapply(2L:max_k, function(k) {
repetitions <- sapply(seq_len(num_starts), function(ignored) {
km <- kmeans(ruspini, k)
mean(cluster::silhouette(km$cluster, dist = dm)[,3L])
})
max(repetitions)
})
对于 k
的每个值,我们 return 只有所有重复的最大分数
(同样,通过不存储所有内容来节省 space)。
为了使所有内容都可重现,您在顶部使用 set.seed
;
使用一次就足以进行顺序计算。
也许您想利用并行化,
但是你可能需要更多的内存
(很难说有多少,
因为有很多因素在起作用),
并且您需要注意可重复性。
如果您想尝试一下,最终脚本可能如下所示:
library(doParallel)
library(cluster)
data(ruspini)
dm <- dist(ruspini)
max_k <- 3L
num_starts <- 2L
# get random seeds for each execution
RNGkind("L'Ecuyer")
set.seed(333L)
current_seed <- .Random.seed # initialize
seeds <- lapply(2L:max_k, function(ignored) {
lapply(seq_len(num_starts), function(also_ignored) {
seed <- current_seed
current_seed <<- parallel::nextRNGStream(current_seed)
# return
seed
})
})
workers <- makeCluster(detectCores())
registerDoParallel(workers)
scores <- foreach(k = 2L:max_k, k_seeds = seeds, .combine = c, .packages = "cluster") %dopar% {
repetitions <- sapply(seq_len(num_starts), function(i) {
set.seed(k_seeds[[i]])
km <- kmeans(ruspini, k)
mean(cluster::silhouette(km$cluster, dist = dm)[,3L])
})
max(repetitions)
}
stopCluster(workers); registerDoSEQ(); rm(workers)
names(scores) <- paste0("k_", 2L:max_k)
我正在尝试验证基于 returns 相关矩阵的 Prado 聚类交易策略的 k-means 框架,如 his paper 中所见,对大量策略使用 R,比如 1000。
他尝试在所有可能的 k 上使用两个 for
循环来寻找最佳 k 和 k-means 的最佳初始化和一些初始化,即 k 从 2 到 N-1,其中 N 是策略数量。
问题是 运行ning k-means 很多次,尤其是有那么多集群时,内存耗尽,而我的计算机 m3.medium 我使用的 AWS 实例都无法做到工作。 (均为 4 GB RAM,但在 AWS 上,后台 RAM 消耗进程较少。)
那么,请问有什么办法可以处理这个内存问题吗?或者至少如何根据使用的策略数量来估计所需的内存量?
我已经尝试了软件包 biganalytics
及其 bigkmeans
功能,但还不够。
我也知道有更高的 RAM AWS 实例,但我想在切换到这样的实例之前确保我的代码是最佳的。
我还尝试限制使用的集群数量,这证实这是主要的内存消耗问题,但我不想坚持这种解决方案(也不会与更好的 AWS 实例结合使用)。
在 AWS 上正确执行的策略的最高数量约为 500。
内存优化的主要部分代码如下:
D <- nrow(dist)
seq.inits <- rep(1:nr.inits,D-2)
seq.centers <- rep(2:(D-1),each = nr.inits)
KM <- mapply(function(x,y){
set.seed(x+333)
kmeans(dist, y)
},seq.inits,seq.centers)
dist
是策略的“returns”相关距离矩阵(即列数等于行数,以及其他属性),nr.inits
是初始化次数。两者都是输入变量。之后,使用剪影得分确定最佳聚类,并在需要时重新聚类。
我知道距离矩阵不适合 k-means 的输入,我也知道数据挖掘问题,所以请不要解决这些问题。
我的上述问题是:
是否可以减少内存使用量,以便我能够在 m3.medium AWS 实例上 运行 1000 个策略?
是否可以至少根据使用的数字策略估计内存使用情况? (假设我尝试
2:(N-1)
个集群。)
其实第二个问题,最好是优化之后,对我来说比较重要。因为我想尝试比 "just" 1000 多得多的策略。
预先感谢您的回答!
不同时存储所有结果适用于许多问题,
即使你不使用 R。
此外,我认为您没有正确使用 kmeans
,
因为它需要你的输入数据,
不是交叉距离矩阵。
同样,您不需要分配所有 seq.centers
。
你提到剪影指数,
可以用cluster::silhouette
计算,所以:
library(cluster)
data(ruspini) # sample data included in the cluster package
由于您的数据没有改变, 你可以预先计算交叉距离矩阵:
dm <- dist(ruspini)
您想要的工作流程中的一个 "iteration" 是:
km <- kmeans(ruspini, 2) # try 2 clusters
score <- mean(cluster::silhouette(km$cluster, dist = dm)[,3L])
你想为同一个 k
集群随机启动几个:
num_starts <- 2L
scores <- sapply(seq_len(num_starts), function(ignored) {
km <- kmeans(ruspini, 2)
mean(cluster::silhouette(km$cluster, dist = dm)[,3L])
})
注意只保存分数,
没有聚类结果。
您还想要 k
:
max_k <- 3L
num_starts <- 2L
scores <- sapply(2L:max_k, function(k) {
repetitions <- sapply(seq_len(num_starts), function(ignored) {
km <- kmeans(ruspini, k)
mean(cluster::silhouette(km$cluster, dist = dm)[,3L])
})
max(repetitions)
})
对于 k
的每个值,我们 return 只有所有重复的最大分数
(同样,通过不存储所有内容来节省 space)。
为了使所有内容都可重现,您在顶部使用 set.seed
;
使用一次就足以进行顺序计算。
也许您想利用并行化,
但是你可能需要更多的内存
(很难说有多少,
因为有很多因素在起作用),
并且您需要注意可重复性。
如果您想尝试一下,最终脚本可能如下所示:
library(doParallel)
library(cluster)
data(ruspini)
dm <- dist(ruspini)
max_k <- 3L
num_starts <- 2L
# get random seeds for each execution
RNGkind("L'Ecuyer")
set.seed(333L)
current_seed <- .Random.seed # initialize
seeds <- lapply(2L:max_k, function(ignored) {
lapply(seq_len(num_starts), function(also_ignored) {
seed <- current_seed
current_seed <<- parallel::nextRNGStream(current_seed)
# return
seed
})
})
workers <- makeCluster(detectCores())
registerDoParallel(workers)
scores <- foreach(k = 2L:max_k, k_seeds = seeds, .combine = c, .packages = "cluster") %dopar% {
repetitions <- sapply(seq_len(num_starts), function(i) {
set.seed(k_seeds[[i]])
km <- kmeans(ruspini, k)
mean(cluster::silhouette(km$cluster, dist = dm)[,3L])
})
max(repetitions)
}
stopCluster(workers); registerDoSEQ(); rm(workers)
names(scores) <- paste0("k_", 2L:max_k)