【问题标题】:how to convert a nested loop to lapply in r如何在 r 中将嵌套循环转换为 lapply
【发布时间】:2020-02-07 21:31:21
【问题描述】:

我有一个名为“daha​​k”的列表,其中包含 1 到 10 之间的 30000 个数字。我想用列表中的所有数字检查每个数字,如果两个数字相等,则将数字 1 附加到 weight_list,如果两个数字不等于然后计算它们的差并将其存储为 x 并将 x 附加到 weight_list。 代码如下:

for(j in 1:num_nodes){
  for (k in 1:num_nodes){
    if(j==k){
      weight_list <- c(weight_list,0)
    }
    else if(as.numeric(dahak[j])==as.numeric(dahak[k])){
      weight_list <- c(weight_list,1)
    }
    else if(as.numeric(dahak[j])!=as.numeric(dahak[k])){
      x = 1 - (abs(as.numeric(dahak[j]) - as.numeric(dahak[k])) / 10)
      weight_list <- c(weight_list,x)
    }
  }
}

如何优化这段代码?我怎么能用 lapply 做到这一点?

【问题讨论】:

  • 请展示一个可重现的小例子,以便其他人可以测试
  • 如果没有可重现的例子就不清楚了。可能是v1 &lt;- unlist(dahak); outer(v1, v1, FUN = '==')
  • 什么是num_nodes?另外,第二个if 语句应该是else if 吗?正如示例中所写,如果j==kdahak[j]==dahak[k]weight_list 将在同一迭代中同时附加01
  • @akrun dahak 列表是这样的:[1,1,2,6,4,3,3,3,2,3,1,2,] ...我的代码没有错误,但是运行需要很长时间...我使用 wight_list 创建矩阵,然后使用矩阵创建网络...如果您想要所有代码,我可以将其发送给您
  • 您已经问过如何优化您的代码,因为它需要很长时间才能运行。除了下面的Allan's answer,这里还有 3 个提示: (1) 在循环中增长向量非常耗时,因为数据会一遍又一遍地复制。更好地预先分配一个向量并通过子集更新单个元素。 (2) 最后两个if 子句是不必要的,因为如果dahak[j] == dahak[k] 无论如何你的公式都会返回1 (3) 将dahak 的强制从循环中拉出,而不是对循环中的单个元素重复此操作.

标签: r nested-loops lapply


【解决方案1】:

听起来您想创建一个 30,000 x 30,000 矩阵。听起来dahak 也是一个向量而不是一个列表。如果那是真的你想要做的,你可以简化你的逻辑并像这样矢量化;

get_weights <- function(x)  1 - abs(x - as.numeric(dahak))/10 
weights <- do.call(rbind, lapply(as.numeric(dahak), get_weights)) - diag(length(dahak))

使用与我得到的@ThomasIsCoding 相同的虚拟数据:

weights
#>       [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] [,12] [,13] [,14] [,15]
#>  [1,]  0.0  0.9  0.7  0.3  1.0  0.4  0.3  0.6  0.6   0.8   1.0   0.9   0.6   0.9   0.5
#>  [2,]  0.9  0.0  0.8  0.4  0.9  0.5  0.4  0.7  0.7   0.7   0.9   0.8   0.7   1.0   0.6
#>  [3,]  0.7  0.8  0.0  0.6  0.7  0.7  0.6  0.9  0.9   0.5   0.7   0.6   0.9   0.8   0.8
#>  [4,]  0.3  0.4  0.6  0.0  0.3  0.9  1.0  0.7  0.7   0.1   0.3   0.2   0.7   0.4   0.8
#>  [5,]  1.0  0.9  0.7  0.3  0.0  0.4  0.3  0.6  0.6   0.8   1.0   0.9   0.6   0.9   0.5
#>  [6,]  0.4  0.5  0.7  0.9  0.4  0.0  0.9  0.8  0.8   0.2   0.4   0.3   0.8   0.5   0.9
#>  [7,]  0.3  0.4  0.6  1.0  0.3  0.9  0.0  0.7  0.7   0.1   0.3   0.2   0.7   0.4   0.8
#>  [8,]  0.6  0.7  0.9  0.7  0.6  0.8  0.7  0.0  1.0   0.4   0.6   0.5   1.0   0.7   0.9
#>  [9,]  0.6  0.7  0.9  0.7  0.6  0.8  0.7  1.0  0.0   0.4   0.6   0.5   1.0   0.7   0.9
#> [10,]  0.8  0.7  0.5  0.1  0.8  0.2  0.1  0.4  0.4   0.0   0.8   0.9   0.4   0.7   0.3
#> [11,]  1.0  0.9  0.7  0.3  1.0  0.4  0.3  0.6  0.6   0.8   0.0   0.9   0.6   0.9   0.5
#> [12,]  0.9  0.8  0.6  0.2  0.9  0.3  0.2  0.5  0.5   0.9   0.9   0.0   0.5   0.8   0.4
#> [13,]  0.6  0.7  0.9  0.7  0.6  0.8  0.7  1.0  1.0   0.4   0.6   0.5   0.0   0.7   0.9
#> [14,]  0.9  1.0  0.8  0.4  0.9  0.5  0.4  0.7  0.7   0.7   0.9   0.8   0.7   0.0   0.6
#> [15,]  0.5  0.6  0.8  0.8  0.5  0.9  0.8  0.9  0.9   0.3   0.5   0.4   0.9   0.6   0.0

【讨论】:

  • 没错,我想创建一个 30,000 * 30,000 矩阵,但它没有得到正确的答案...检查此数据和最终答案... dahak 列表是[9,1,4,3,2] 和矩阵必须是V1 V2 V3 V4 V5 1 0 0.2 0.5 0.4 0.3 2 0.2 0 0.7 0.8 0.9 3 0.5 0.7 0 0.9 0.8 4 0.4 0.8 0.9 0 0.9 5 0.3 0.9 0.8 0.9 0
  • @omidjahadi 这就是我在上面的修改版本中得到的答案
  • 运行程序后出现此错误,数据为 30000 ...Error: cannot allocate vector of size 292 Kb
  • @omidjahadi 您正在尝试编写一个包含 900000000 个条目的矩阵,因此您可能没有足够的内存。您可以尝试重新启动 R 会话
  • @omidjahadi 我的计算机也无法在内存中保存 9 亿个值。为什么需要这么大的矩阵?您可以使用其他方法吗?
【解决方案2】:

我想这可能是您正在寻找的简化,其中使用了 outerifelse

下面是一个带有虚拟数据的示例:

set.seed(1)
num_nodes <- 15
dahak <- sample(10,num_nodes,replace = TRUE)

如果你想要一个维度为num_nodesweigth_list 的矩阵,那么你可以试试

weight_list <- (u<-ifelse((z<-abs(outer(dahak,dahak,FUN = "-")))!=0,1-z/10,1))-diag(diag(u))

这样

> weight_list
      [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] [,12] [,13] [,14] [,15]
 [1,]  0.0  0.5  0.8  0.2  0.3  0.8  0.3  0.4  0.2   0.6   0.6   0.9   0.7   0.9   0.8
 [2,]  0.5  0.0  0.7  0.7  0.8  0.7  0.8  0.9  0.7   0.9   0.9   0.4   0.8   0.4   0.7
 [3,]  0.8  0.7  0.0  0.4  0.5  1.0  0.5  0.6  0.4   0.8   0.8   0.7   0.9   0.7   1.0
 [4,]  0.2  0.7  0.4  0.0  0.9  0.4  0.9  0.8  1.0   0.6   0.6   0.1   0.5   0.1   0.4
 [5,]  0.3  0.8  0.5  0.9  0.0  0.5  1.0  0.9  0.9   0.7   0.7   0.2   0.6   0.2   0.5
 [6,]  0.8  0.7  1.0  0.4  0.5  0.0  0.5  0.6  0.4   0.8   0.8   0.7   0.9   0.7   1.0
 [7,]  0.3  0.8  0.5  0.9  1.0  0.5  0.0  0.9  0.9   0.7   0.7   0.2   0.6   0.2   0.5
 [8,]  0.4  0.9  0.6  0.8  0.9  0.6  0.9  0.0  0.8   0.8   0.8   0.3   0.7   0.3   0.6
 [9,]  0.2  0.7  0.4  1.0  0.9  0.4  0.9  0.8  0.0   0.6   0.6   0.1   0.5   0.1   0.4
[10,]  0.6  0.9  0.8  0.6  0.7  0.8  0.7  0.8  0.6   0.0   1.0   0.5   0.9   0.5   0.8
[11,]  0.6  0.9  0.8  0.6  0.7  0.8  0.7  0.8  0.6   1.0   0.0   0.5   0.9   0.5   0.8
[12,]  0.9  0.4  0.7  0.1  0.2  0.7  0.2  0.3  0.1   0.5   0.5   0.0   0.6   1.0   0.7
[13,]  0.7  0.8  0.9  0.5  0.6  0.9  0.6  0.7  0.5   0.9   0.9   0.6   0.0   0.6   0.9
[14,]  0.9  0.4  0.7  0.1  0.2  0.7  0.2  0.3  0.1   0.5   0.5   1.0   0.6   0.0   0.7
[15,]  0.8  0.7  1.0  0.4  0.5  1.0  0.5  0.6  0.4   0.8   0.8   0.7   0.9   0.7   0.0

【讨论】:

  • 请检查您的回答。我认为有两个缺陷:(1)对角线未设置为零,(2)abs() 已被省略,因此生成的weight_list 包含范围 [0, 1] 之外的值。谢谢。
  • @Uwe 谢谢!我不知道 OP 代码的预期输出,因此帖子描述中遗漏了一些重要信息。现在答案更新了
猜你喜欢
  • 1970-01-01
  • 2020-06-05
  • 2021-08-09
  • 2022-01-24
  • 2017-04-20
  • 1970-01-01
  • 2016-04-24
  • 2021-12-30
  • 2020-07-02
相关资源
最近更新 更多