【问题标题】:Increase speed for a ifelse-for loop in R, while filling matrix within loop提高 R 中 ifelse-for 循环的速度,同时在循环内填充矩阵
【发布时间】:2021-03-29 14:18:39
【问题描述】:

如果实际循环范围为 1000 秒,如何提高以下循环操作的速度? 在下面的代码中:

DF3= 数据框

OP 和 k 是 DF3 数据框中的两列。这里,k 取值从 1 到 10。

l1 <- seq(1, 10, 1)
E<-matrix(data=0, nrow=10, ncol=10)
for (i in seq_along(l1)){
  for (j in seq_along(l1)){
    E[i,j]=sum(ifelse (DF3$OP[DF3$k==i]<DF3$OP[DF3$k==j],1,0))
  }
}

DF3 示例:

k   OP
1   60
1   30
1   38
1   46
2   29
2   35
2   13
2   82
3   100
3   72
3   63
3   45

【问题讨论】:

  • 为了更简单,这里有一些小建议: (1) 代替seq(1, 2552, 1),您可以使用1:2552; (2) 不用seq_along(l1),直接用l1即可; (3),而不是sum(ifelse ( ... ,1,0)),只需从中删除ifelse() 函数,因为对逻辑TRUE/FALSE 值求和与对1 和0 求和相同。
  • 我认为你会因为一个太大而无法展示和/或只是“玩”的问题吓跑很多试图提供帮助的人。虽然我知道您想将其扩展到更大的尺寸,但在 更小的矩阵上显示可能会有所帮助,其比例为 10x10 而不是 2552x2552。

标签: r for-loop if-statement matrix


【解决方案1】:

由于您需要 DF3$OP 与 DF3$k 组的成对块以及反向重复以进行大于和小于比较,因此您实际上是在填充方阵的上下三角形。因此,可以考虑将数据帧分割成by的OP块,并传入combn进行矩阵填充。

OP_list <- by(DF3, DF3$k, function(sub) sub$OP)
OP_list
# DF3$k: 1
# [1] 60 30 38 46
# ------------------------------------------------------------ 
# DF3$k: 2
# [1] 29 35 13 82
# ------------------------------------------------------------ 
# DF3$k: 3

E <- matrix(data=0, nrow=max(DF3$k), ncol=max(DF3$k))

# COMPARE ACROSS ALL COMBINATIONS OF K-GROUP VECTORS
E[upper.tri(E)] <- combn(OP_list, 2, function(x) sum(x[[1]] < x[[2]]))
E[lower.tri(E)] <- combn(OP_list, 2, function(x) sum(x[[1]] > x[[2]]))

E
#      [,1] [,2] [,3]
# [1,]    0    2    3
# [2,]    2    0    3
# [3,]    1    1    0

应该适用于小型或大型套装。 见:Online Demo

【讨论】:

    【解决方案2】:

    逻辑比较

    DF3$OP[DF3$k==i]<DF3$OP[DF3$k==j]
    

    意味着在所有k 组中存在相同数量的结果。如果组之间的记录数量不均,计算就会出现问题。

    在您的数据集中,每组有 4 条记录。这表明,与其使用数据框,不如使用矩阵。

    ncols = length(unique(DF3$k))
    mat = matrix(DF3$OP, ncol = ncols)
    E = matrix(0L, ncols, ncols)
    
    for (i in seq_len(ncols)) {
      x = mat[, i]
      for (j in seq_len(ncols)) {
        E[i, j] = sum(x < mat[, j])
      }
    }
    E
    
    ##      [,1] [,2] [,3]
    ## [1,]    0    2    3
    ## [2,]    2    0    3
    ## [3,]    1    1    0
    

    【讨论】:

      【解决方案3】:

      也许您可以通过使用combn 简化嵌套的for 循环,它仅计算上三角矩阵的值(但它们足以获得整个矩阵中的值)

      E <- matrix(data = 0, nrow = max(DF3$k), ncol = max(DF3$k))
      v <- split(DF3$OP, DF3$k)
      E[lower.tri(E)] <- combn(v, 2, FUN = function(x) sum(do.call("-", x) < 0))
      E[upper.tri(E)] <- max(lengths(v)) - t(E)[upper.tri(E)]
      E <- t(E)
      

      最后你会得到

      > E
           [,1] [,2] [,3]
      [1,]    0    2    3
      [2,]    2    0    3
      [3,]    1    1    0
      

      数据

      > dput(DF3)
      structure(list(k = c(1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L, 3L, 3L, 
      3L, 3L), OP = c(60L, 30L, 38L, 46L, 29L, 35L, 13L, 82L, 100L,
      72L, 63L, 45L)), class = "data.frame", row.names = c(NA, -12L
      ))
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-07-20
        • 2011-09-29
        • 1970-01-01
        • 1970-01-01
        • 2021-09-29
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多