在 R 中的列表上使用应用族和多个函数
Using apply family and multiple functions on lists in R
我对这个问题的回答之后有一个问题
我的解决方案是使用 for 循环,但我们应该尽可能地尝试优化(矢量化)。
我想了解的是如何矢量化我在 post 中制定的解决方案。
我的解决方案是
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
时放入的内容。
所有数据都可以在 link 我 posted 中找到,但这里是数据
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)
因为你需要在你的调用中多次使用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
不是向量化——它只是 "loop hiding"。在这种情况下,我认为您的 for
循环比 lapply
更好。特别是因为您正在 修改 现有对象,您的简单 for
循环可能比 lapply
解决方案更有效,并且更具可读性。
当我们谈论向量化以提高效率时,我们几乎总是指原子向量,而不是 list
s。 (是向量化,毕竟不是列表化。)使用lapply
和相关函数的原因(sapply
, vapply
、Map
、大多数 purrr
包)不是计算机效率,而是 可读性 和人类编写效率。
假设您有一个数据框列表,my_list = list(iris, mtcars, CO2)
。如果您想获取列表中每个数据框的行数并将其存储在变量中,我们可以使用 sapply
或 for
循环:
# 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 年的答案中,您会看到 有时 *apply
稍微 比 for
循环。自从 JIT 编译器以来,我想你会发现相反的情况:大多数 的时间 for
循环比 稍微 快 [= =34=].
但在这两种情况下,除非你在 for/apply 中做一些绝对微不足道的事情,无论你在 [=77] 中做什么=] 将主导计时.
我对这个问题的回答之后有一个问题
我的解决方案是使用 for 循环,但我们应该尽可能地尝试优化(矢量化)。
我想了解的是如何矢量化我在 post 中制定的解决方案。
我的解决方案是
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
时放入的内容。
所有数据都可以在 link 我 posted 中找到,但这里是数据
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)
因为你需要在你的调用中多次使用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
不是向量化——它只是 "loop hiding"。在这种情况下,我认为您的 for
循环比 lapply
更好。特别是因为您正在 修改 现有对象,您的简单 for
循环可能比 lapply
解决方案更有效,并且更具可读性。
当我们谈论向量化以提高效率时,我们几乎总是指原子向量,而不是 list
s。 (是向量化,毕竟不是列表化。)使用lapply
和相关函数的原因(sapply
, vapply
、Map
、大多数 purrr
包)不是计算机效率,而是 可读性 和人类编写效率。
假设您有一个数据框列表,my_list = list(iris, mtcars, CO2)
。如果您想获取列表中每个数据框的行数并将其存储在变量中,我们可以使用 sapply
或 for
循环:
# 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 年的答案中,您会看到 有时 *apply
稍微 比 for
循环。自从 JIT 编译器以来,我想你会发现相反的情况:大多数 的时间 for
循环比 稍微 快 [= =34=].
但在这两种情况下,除非你在 for/apply 中做一些绝对微不足道的事情,无论你在 [=77] 中做什么=] 将主导计时.