我想知道是否有更有效的方法在列表的每两个连续元素上应用函数。 This question让我思考,我为用户发布的解决方案来自here。
我认为使用Map/mapply
somelist[-length(somelist)]
和somelist[-1]
作为function(x, y)
调用的参数是足够好的,但是有没有直接的方法,可能在一个更大/更新的包?
考虑这个例子(从上述问题中偷来的):
我有三个矩阵列表:
set.seed(1)
matlist <- list(M1 = matrix(sample(1:10, 4, replace = T), nrow = 2, ncol = 2),
M2 = matrix(sample(1:10, 4, replace = T), nrow = 2, ncol = 2),
M3 = matrix(sample(1:10, 4, replace = T), nrow = 2, ncol = 2)
)
现在我要计算M1+M2
和M2+M3
。提到的方法是
Map(`+`, matlist[-3], matlist[-1])
[[1]]
[,1] [,2]
[1,] 5 11
[2,] 11 15
[[2]]
[,1] [,2]
[1,] 12 13
[2,] 5 18
我要提供的apply
系列的任何变体
xapply(matlist, `+`)
我知道我可以把自己写成一个小帮手,比如
xapply <- function(x, FUN){
Map(FUN, x[-length(x)], x[-1])
}
但据我所知this classic,sapply/lapply
等利用for
代码获得了优于C
循环的性能优势,因此xapply
上面的功能只是方便,而不是提升性能。
答案 0 :(得分:2)
apply函数比循环更快是不正确的。有时他们不是。
如果想法不是使用索引而是使用整个对象方法,那么这里有一些方法,尽管问题中的Map
方法似乎更好。
1)矩阵 rollsum
将对窗口执行求和。它不适用于列表,但如果您在矩阵中编写转换函数,它将起作用:
library(magrittr)
library(zoo)
# convert between list and matrix where each row of matrix is one list component
list2mat <- function(x) t(sapply(x, c))
mat2list <- function(x, n) lapply(1:nrow(x), function(i) matrix(x[i, ], n))
nr <- nrow(matlist[[1]])
matlist %>% list2mat %>% rollsum(2) %>% mat2list(nr)
2)减少这是Reduce
的尝试:
ans <- list()
invisible(Reduce(function(x, y) { ans <<- c(ans, list(x + y)); y }, matlist))
3)数组另一种方法是使用3d数组而不是列表。这样就可以使用aaply
和rollsum
来生成紧凑的单线程。
我们首先使用simplify2array
将列表转换为3d数组,然后在该框架内使用数组a
:
library(plyr)
library(zoo)
a <- simplify2array(matlist) # convert matlist to array
aa <- aaply(a, 1:2, rollsum, 2)
# check
bb <- simplify2array(Map("+", matlist[-1], matlist[-3]))
identical(unname(aa), unname(bb))
## [1] TRUE
aaply
基本上是一个幂等的应用,如果我们愿意置换(即广义转置),我们可以用普通的apply
做到这一点
三维数组。这与上面的aaply
行相同:
library(magrittr)
aa <- a %<% apply(1:2, rollsum, 2) %>% aperm(c(2, 3, 1))
这也有效:
aa <- a %>% aperm(3:1) %>% apply(2:3, rollsum, 2) %>% aperm(3:1)
答案 1 :(得分:0)
这是一种稍微不同的方法,尽管我不太喜欢。
select distinct tmp.UserName from
(
select distinct user_from as UserName from YourTable
union
select distinct user_To as UserName from YourTable
) as tmp;
这是管道的一种变体,我认为更好,因为我喜欢管道。
purr::map(seq_along(matlist)[-length(matlist)],
~ reduce(list(matlist[[.]], matlist[[.+1]]), `+`))
不幸的是,它像原始的Map答案一样,给出了带有错误名称的列表。要摆脱错误的名称,您必须执行以下操作:
matlist %>%
list(a = .[-length(.)], b = .[-1]) %>%
.[-1] %>%
pmap( ~ .x + .y)
我认为删除名称是值得的,因为它们会误导人。