R:查找拆分列表的最大值时出现性能问题
当尝试查找拆分列表的最大值时,我遇到了严重的性能问题 有没有办法优化以下代码:R:查找拆分列表的最大值时出现性能问题,r,performance,list,split,lapply,R,Performance,List,Split,Lapply,当尝试查找拆分列表的最大值时,我遇到了严重的性能问题 有没有办法优化以下代码: # Generate data for this MWE x <- matrix(runif(900 * 9000), nrow = 900, ncol = 9000) y <- rep(1:100, each = 9) my_data <- cbind(y, x) my_data <- data.frame(my_data) # This is the critical part I wo
# Generate data for this MWE
x <- matrix(runif(900 * 9000), nrow = 900, ncol = 9000)
y <- rep(1:100, each = 9)
my_data <- cbind(y, x)
my_data <- data.frame(my_data)
# This is the critical part I would like to optimize
my_data_split <- split(my_data, y)
max_values <- lapply(my_data_split, function(x) x[which.max(x[ , 50]), ])
#为此MWE生成数据
x您可能还不清楚这一点
有一个内部函数max.col
执行类似的操作,只是它沿着矩阵行(而不是列)查找最大值的位置索引。因此,如果您转换原始矩阵x
,您将能够使用此函数
当您想按组执行max.col
时,复杂性会逐步增加。需要split
-lappy
约定。但是,如果在转置之后,我们将矩阵转换为数据帧,我们可以执行split.default
。(注意,它不是split
或split.data.frame
。这里数据帧被视为一个列表(向量),因此拆分发生在数据帧列之间。)最后,我们执行sapply
以按组应用max.col
,并cbind
将结果应用到矩阵中
tx <- data.frame(t(x))
tx.group <- split.default(tx, y) ## note the `split.default`, not `split`
pos <- sapply(tx.group, max.col)
您只需生成一次查找表,并随时进行任意提取
此方法的缺点:
拆分后,每组中的数据存储在数据帧中,而不是矩阵中。也就是说,例如,tx.group[[1]]
是一个9000 x 9的数据帧。但是max.col
需要一个矩阵,因此它将在内部将此数据帧转换为矩阵
因此,主要的性能/内存开销包括:
- 初始矩阵变换李>
- 矩阵到数据帧转换李>
- 数据帧到矩阵的转换(每组)
我不确定我们是否用MatrixStats
包中的一些函数消除了上述所有功能。我期待着看到这方面的解决办法
但无论如何,这个答案已经比OP最初的答案快得多。你可能还不太清楚
有一个内部函数max.col
执行类似的操作,只是它沿着矩阵行(而不是列)查找最大值的位置索引。因此,如果您转换原始矩阵x
,您将能够使用此函数
当您想按组执行max.col
时,复杂性会逐步增加。需要split
-lappy
约定。但是,如果在转置之后,我们将矩阵转换为数据帧,我们可以执行split.default
。(注意,它不是split
或split.data.frame
。这里数据帧被视为一个列表(向量),因此拆分发生在数据帧列之间。)最后,我们执行sapply
以按组应用max.col
,并cbind
将结果应用到矩阵中
tx <- data.frame(t(x))
tx.group <- split.default(tx, y) ## note the `split.default`, not `split`
pos <- sapply(tx.group, max.col)
您只需生成一次查找表,并随时进行任意提取
此方法的缺点:
拆分后,每组中的数据存储在数据帧中,而不是矩阵中。也就是说,例如,tx.group[[1]]
是一个9000 x 9的数据帧。但是max.col
需要一个矩阵,因此它将在内部将此数据帧转换为矩阵
因此,主要的性能/内存开销包括:
- 初始矩阵变换李>
- 矩阵到数据帧转换李>
- 数据帧到矩阵的转换(每组)
我不确定我们是否用MatrixStats
包中的一些函数消除了上述所有功能。我期待着看到这方面的解决办法
但无论如何,这个答案已经比OP最初的答案快得多。使用{dplyr}的解决方案:
# Generate data for this MWE
x <- matrix(runif(900 * 9000), nrow = 900, ncol = 9000)
y <- rep(1:100, each = 9)
my_data <- cbind.data.frame(y, x)
# This is the critical part I would like to optimize
system.time({
my_data_split <- split(my_data, y)
max_values <- lapply(my_data_split, function(x) x[which.max(x[ , 50]), ])
})
# Using {dplyr} is 9 times faster, but you get results in a slightly different format
library(dplyr)
system.time({
max_values2 <- my_data %>%
group_by(y) %>%
do(max_values = .[which.max(.[[50]]), ])
})
all.equal(max_values[[1]], max_values2$max_values[[1]], check.attributes = FALSE)
#为此MWE生成数据
x使用{dplyr}的解决方案:
# Generate data for this MWE
x <- matrix(runif(900 * 9000), nrow = 900, ncol = 9000)
y <- rep(1:100, each = 9)
my_data <- cbind.data.frame(y, x)
# This is the critical part I would like to optimize
system.time({
my_data_split <- split(my_data, y)
max_values <- lapply(my_data_split, function(x) x[which.max(x[ , 50]), ])
})
# Using {dplyr} is 9 times faster, but you get results in a slightly different format
library(dplyr)
system.time({
max_values2 <- my_data %>%
group_by(y) %>%
do(max_values = .[which.max(.[[50]]), ])
})
all.equal(max_values[[1]], max_values2$max_values[[1]], check.attributes = FALSE)
#为此MWE生成数据
非常感谢你的全面回答。这对我帮助很大。非常感谢你全面的回答。这对我帮助很大。非常感谢你的回答。我认为我应该开始使用dplyr包,因为它被广泛使用,并且有一个非常清晰的synthax。非常感谢您的回答。我认为我应该开始使用dplyr包,因为它被广泛使用,并且有一个非常清晰的synthax。