【问题标题】:Speeding up calculation across columns跨列加速计算
【发布时间】:2020-03-21 06:38:07
【问题描述】:

我有几个中等大小的数据框,需要跨数据中的不同列进行计算;例如,我想将一个数据框中的 i 列与另一个数据框中的 i - 1 进行比较。我目前使用 for 循环。计算涉及每对值的元素比较,所以有点慢:例如我获取每一列数据,将其转换为矩阵并与自身的转置进行比较(还有一些额外的复杂性)。在我的应用程序(其中数据大约有 100 列和 3000 行)中,这当前需要大约 95 秒。我正在寻找提高效率的方法。如果我要比较每个数据框的 SAME 列,我会尝试使用 mapply,但是因为我需要在不同的列之间进行比较,所以我看不出这是如何工作的。当前的代码是这样的:

d1 <- as.data.frame(matrix(rnorm(100000), nrow=1000))
d2 <- as.data.frame(matrix(rnorm(100000), nrow=1000))

r <- list()
ptm2 <- proc.time()
for(i in 2:100){
  t <- matrix(0 + d1[,i] > 0,1000,1000)
  u <- matrix(d1[,i],1000,1000)*t(matrix(d2[,i-1],1000,1000))
  r[[i]] <- t * u
}
proc.time() - ptm2

这在我的电脑上大约需要 3 秒;如前所述,实际计算比这个 MWE 建议的要复杂一些。显然,也可以提高计算本身的效率,但我正在寻找解决“将 i 列与 i-1 列比较”问题的解决方案。

【问题讨论】:

  • d1d2 是否应该与 tu 具有相同的维度?
  • 没有。如果有助于澄清:这是一个社交网络应用程序,我根据值 i、j 之间的关系计算关系,其中 j 是单位,i 是年——因此是矩阵
  • 当我对此进行分析时(例如使用profr),似乎matrixt 占用了大部分时间。因此,这并不是真正的循环本身,而是将列转换为矩阵并形成转置。我想知道这可能不是 Rcpp 的完美用例...
  • 谢谢你的建议,虽然可能有点超出我的深度(对于这个应用程序来说太过分了......也可以等待代码运行)

标签: r for-loop time


【解决方案1】:

根据您的示例,如果您根据要比较的列提前对齐 d1 和 d2 矩阵,那么您可以使用mapply。它似乎只是稍微快一点,因此并行计算将是实现速度提升的更好方法。

d1 <- as.data.frame(matrix(rnorm(100000), nrow=1000))
d2 <- as.data.frame(matrix(rnorm(100000), nrow=1000))

r <- list()
ptm2 <- proc.time()
for(i in 2:100){
  t <- matrix(0 + d1[,i] > 0,1000,1000)
  u <- matrix(d1[,i],1000,1000)*t(matrix(d2[,i-1],1000,1000))
  r[[i]] <- t * u
}
proc.time() - ptm2
#user  system elapsed 
#0.90    0.87    1.79 
#select last 99 columns of d1 and first 99 columns of d2 based on your calcs
d1_99 <- as.data.frame(d1[,2:100]) #have to convert to data.frame for mapply to loop across columns; a data.frame is simply a list of vectors of equal length
d2_99 <- as.data.frame(d2[,1:99])
ptm3 <- proc.time()
r_test <- mapply(function(x, y) {
  t <- matrix(x > 0, 1000, 1000) #didn't understand why you were adding 0 in your example
  u <- matrix(x,1000,1000)*t(matrix(y,1000,1000))
  t * u
}, x=d1_99, y=d2_99, SIMPLIFY = FALSE)
proc.time() - ptm3
#user  system elapsed 
#0.91    0.83    1.75 
class(r_test)
#[1] "list"
length(r_test)
#[1] 99
#test for equality
all.equal(r[[2]], r_test[[1]])
#[1] TRUE
all.equal(r[[100]], r_test[[99]])
#[1] TRUE

【讨论】:

    猜你喜欢
    • 2021-01-19
    • 1970-01-01
    • 1970-01-01
    • 2017-08-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多