提高 R 中 ifelse-for 循环的速度,同时在循环中填充矩阵

Increase speed for a ifelse-for loop in R, while filling matrix within loop

提问人:vp_050 提问时间:12/19/2020 最后编辑:vp_050 更新时间:12/19/2020 访问量:101

问:

如果实际循环范围为 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
r for 循环 if 语句 矩阵

评论

2赞 LC-datascientist 12/19/2020
以下是一些小建议,以更好地简化:(1)相反,您可以使用;(2)代替 ,你可以直接使用;(3),而不是 ,只是从中删除函数,因为逻辑 TRUE/FALSE 值的总和与 1 和 0 的总和相同。seq(1, 2552, 1)1:2552seq_along(l1)l1sum(ifelse ( ... ,1,0))ifelse()
2赞 r2evans 12/19/2020
我认为你会吓跑很多试图通过遇到一个太大而无法展示和/或只是“玩”的问题来提供帮助的人。虽然我知道您想将其扩展到更大的尺寸,但在更小的矩阵上显示可能会有所帮助,比例为 10x10 而不是 2552x2552。

答:

4赞 ThomasIsCoding 12/19/2020 #1

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

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
))
1赞 Cole 12/19/2020 #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
1赞 Parfait 12/19/2020 #3

由于您需要具有反向重复的 by 组的成对块来进行比较,因此您实际上是在填充方形矩阵的上三角形和下三角形。因此,请考虑将数据框拆分为 OP 块,并传递到矩阵填充中。DF3$OPDF3$kbycombn

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