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。