【问题标题】:Using apply family and multiple functions on lists in R在 R 中的列表上使用应用族和多个函数
【发布时间】:2019-04-23 01:55:28
【问题描述】:

在我对这个问题的回答之后,我有一个问题 Matching vertex attributes across a list of edgelists R

我的解决方案是使用 for 循环,但我们应该始终尽可能优化(矢量化)。

我想了解的是如何将我在帖子中提出的解决方案矢量化。

我的解决方案是

for(i in 1:length(graph_list)){
  graph_list[[i]]=set_vertex_attr(graph_list[[i]],"gender", value=attribute_df$gender[match(V(graph_list[[i]])$name, attribute_df$names)])
}

理想情况下,我们可以使用 lapply 将其矢量化,但我在构思如何做到这一点时遇到了一些麻烦。这就是我所拥有的

graph_lists_new=lapply(graph_list, set_vertex_attr, value=attribute_df$gender[match(V(??????????)$name, attribute_df$names)]))

我不清楚的是我在?????? 的部分中添加了什么。 V() 函数中的内容应该是列表中的每个项目,但我没有得到的是我在使用 lapply 时放入的内容。

所有数据都可以在我发布的链接中找到,但无论如何都是数据

attribute_df<- structure(list(names = structure(c(6L, 7L, 5L, 2L, 1L, 8L, 3L, 
4L), .Label = c("Andy", "Angela", "Eric", "Jamie", "Jeff", "Jim", 
"Pam", "Tim"), class = "factor"), gender = structure(c(3L, 2L, 
3L, 2L, 3L, 1L, 1L, 2L), .Label = c("", "F", "M"), class = "factor"), 
    happiness = c(8, 9, 4.5, 5.7, 5, 6, 7, 8)), class = "data.frame", row.names = c(NA, 
-8L))



edgelist<-list(structure(list(nominator1 = structure(c(3L, 4L, 1L, 2L), .Label = c("Angela", 
"Jeff", "Jim", "Pam"), class = "factor"), nominee1 = structure(c(1L, 
2L, 3L, 2L), .Label = c("Andy", "Angela", "Jeff"), class = "factor")), class = "data.frame", row.names = c(NA, 
-4L)), structure(list(nominator2 = structure(c(4L, 1L, 2L, 3L
), .Label = c("Eric", "Jamie", "Oscar", "Tim"), class = "factor"), 
    nominee2 = structure(c(1L, 3L, 2L, 3L), .Label = c("Eric", 
    "Oscar", "Tim"), class = "factor")), class = "data.frame", row.names = c(NA, 
-4L)))

graph_list<- lapply(edgelist, graph_from_data_frame)

【问题讨论】:

  • lapply 不是矢量化——它只是“循环隐藏”。在这种情况下,您的for 循环是比lapply 更好的处理方式。由于您正在修改现有对象,而 lapply 可能需要制作完整的副本,因此您的简单 for 循环几乎肯定会比 lapply 解决方案更有效,并且更具可读性。

标签: r vectorization


【解决方案1】:

由于您需要在调用中多次使用graph_list[[i]],因此要使用lapply,您需要编写一个自定义函数,例如这个匿名函数。 (这与你的循环代码相同,我只是将它包装在function(x) 中,并将graph_list[[i]] 的所有实例替换为x。)

graph_list = lapply(graph_list, function(x)
  set_vertex_attr(x, "gender", value = attribute_df$gender[match(V(x)$name, attribute_df$names)])
)

(请注意,我没有对此进行测试,但它应该可以工作,除非我打错了。)

lapply 不是矢量化——它只是“循环隐藏”。在这种情况下,我认为您的for 循环是比lapply 更好的做事方式。特别是因为您正在修改现有对象,您的简单 for 循环可能会比 lapply 解决方案更有效,并且更具可读性。

当我们谈论向量化以提高效率时,我们几乎总是指原子向量,而不是lists。 (这是矢量化,毕竟不是列表化。)使用lapply和相关函数的原因(sapplyvapplyMap,大部分purrr 包)不是计算机效率,而是可读性和人类编写效率。

假设您有一个数据框列表my_list = list(iris, mtcars, CO2)。如果您想获取列表中每个数据帧的行数并将其存储在变量中,我们可以使用sapplyfor 循环:

# easy to write, easy to read
rows_apply = sapply(my_list, nrow)

# annoying to read and write
rows_for = integer(length(my_list))
for (i in seq_along(my_list)) rows_for[i] = nrow(my_list[[i]])

但是你的任务越复杂,for 循环与类似的替代方案相比就越易读。在你的情况下,我更喜欢 for 循环。


有关此内容的更多信息,请参阅旧问题 Is apply more than syntactic sugar?。自从编写了这些答案以来,R 已经升级为包含一个即时编译器,这进一步加快了 for 相对于应用的循环。在近 10 年前的答案中,您会看到有时 *applyfor 循环快。由于 JIT 编译器,我认为您会发现相反的情况:大多数for 循环*apply 快。

但在这两种情况下,除非您在 for/apply 中执行绝对微不足道的操作无论您在 for/apply 中执行的操作都将支配时间

【讨论】:

  • 有没有办法让这项工作高效而整洁地获得我想要的所有列?喜欢指定我想要的性别和幸福栏吗?我宁愿在没有循环的情况下这样做
  • 可能吗?我真的不知道igraphset_vertex_attr 函数,我只知道循环和应用函数是如何工作的。您要问的问题听起来取决于set_vertex_attr 的工作方式以及您是否可以一次从中获取多个列。
猜你喜欢
  • 1970-01-01
  • 2017-05-03
  • 2016-06-27
  • 1970-01-01
  • 1970-01-01
  • 2017-08-09
  • 2017-06-21
  • 1970-01-01
  • 2020-08-18
相关资源
最近更新 更多