我的数据排列如下:
我的目标是有效地重新排列此数据:
示例数据可以使用以下代码生成(简化为只有2个数据帧,每行5行3列):
example_list<-lapply(X=1:2, FUN=function(X){setNames(data.frame(X*c(1:5), -X*c(1:5), X*100*c(1:5)), c("C1", "C2", "C3"))})
这将创建以下两个数据框的列表:
> example_list[1]
C1 C2 C3
1 1 -1 100
2 2 -2 200
3 3 -3 300
4 4 -4 400
5 5 -5 500
> example_list[2]
C1 C2 C3
1 2 -2 200
2 4 -4 400
3 6 -6 600
4 8 -8 800
5 10 -10 1000
我的当前解决方案(带有示例数据的硬编码数字)如下所示。在这种情况下,我假设我们只关心名为“C1”和“C2”的列:
important_cols <- c("C1", "C2")
result <- array(0, c(5, 2, length(important_cols)))
for(i in 1:5){
for(j in 1:2){
result[i,j,] <- c(example_list[[j]][i,important_cols], recursive=T)
}
}
其中给出了以下输出:
> result
, , 1
[,1] [,2]
[1,] 1 2
[2,] 2 4
[3,] 3 6
[4,] 4 8
[5,] 5 10
, , 2
[,1] [,2]
[1,] -1 -2
[2,] -2 -4
[3,] -3 -6
[4,] -4 -8
[5,] -5 -10
例如,result[5,2,] = [10, -10]
对应于原始数据的5
数据帧的2
行(删除了第三列)。
上述解决方案有效,但我不禁怀疑应该有一个明显更有效的解决方案比双手动实现的for循环并且逐个设置所有元素之一。
答案 0 :(得分:2)
您可以使用一些lapply
和purrr::transpose
来避免循环:
# Example
N <- 1e5
example_list <-
lapply(
X = 1:2,
FUN = function(X) {
setNames(data.frame(X * c(1:N), -X * c(1:N), X * 100 * c(1:N)), c("C1", "C2", "C3"))
}
)
important_cols <- c("C1", "C2")
# Your solution -> 58 seconds :O
system.time({
result <- array(0, c(N, 2, length(important_cols)))
for(i in 1:N){
for(j in 1:2){
result[i,j,] <- c(example_list[[j]][i,important_cols], recursive=T)
}
}
})
# Solution with purrr::transpose -> 0 sec
library(magrittr) ## for the %>%
system.time({
result2 <- example_list %>%
lapply(function(df) df[important_cols]) %>%
purrr::transpose() %>%
sapply(function(l) do.call(cbind, l))
})
dim(result2) <- c(nrow(example_list[[1]]),
length(example_list),
length(important_cols))
# Verification
all.equal(result, result2)