列表优于编号 data.tables
advantage of list over numbered data.tables
我有两个嵌套的 for 循环,我在每个循环中加载(这里模拟)和操作数据,以创建多个列表。
library(data.table)
for(i in 1:20){
perm <- rnorm(1); res <- list()
for(j in 1:500){
temp <- runif(5,0,20)
res[[j]] <- data.table(a=temp/perm, b=temp+perm)
}
assign(paste0("x",i),res); rm(res)
}
因为内部 for 循环输出 data.table,我在外部 for 循环的每次迭代中创建一个列表来保存内部循环产生的不同 data.table。
我读到 here and here 使用 assign(.)
的设置不是很方便,我想知道这是否可以改进。
一方面,我喜欢对 j 循环列表进行编号,这样我就可以将它们与加载到那里的数据集相关联(这里是模拟的)。另一方面,i-loop 可以生成列表列表,但我想知道除了可伸缩性之外还有什么优势。
使用基本 R *pply*
函数族或 purrr
中的 map_*
族函数对您有很大帮助。这是您使用基本 R 的代码:
res <- lapply(1:20, function(i) {
perm <- rnorm(100)
ret <- lapply(1:500, function(j) {
temp <- runif(5, 0, 20)
data.frame(a=temp/perm[i], b=temp+perm[i])
})
})
优点:无需填充当前环境,您有一个对象 (res
),您可以使用循环等轻松操作该对象。将结果存储在列表中的最直接优势是方便。您可以一次保存所有结果 (save(res, file="res.rda")
),计算您有多少 (length(res)
),用 lapply
或 map
浏览它们。
比如说,您想从 20 个重复中的每一个中获取第一个 j
索引:
j1 <- map(res, ~ .[[1]])
哦,你想把所有的都放在一个数据框中吗?
j1 <- map_dfr(res, ~ .[[1]])
第二个优势:您会立即发现您的代码有问题。对于每个 i,您生成 100 个随机数 (perm
),但您只使用...其中一个用于每个 i
! (perm[i]
,对于 1..20 中的 i)。为什么你需要 100 个?
列表的列表很好用,也很容易使用。但是,模式矩阵 "list" 可能是一个非常方便的替代方案:
m <- 2
n <- 3
res <- vector(length = m * n, mode = "list")
res <- matrix(res, ncol = m)
library(data.table)
for(i in 1:n){
perm <- rnorm(100)
for(j in 1:m){
temp <- runif(5,0,20)
res[i,j] <- list(data.table(a=temp/perm[i], b=temp+perm[i]))
}
}
res[1,] #result from first iteration of outer loop
#[[1]]
# a b
#1: -6.434118 7.744621
#2: -7.741497 9.607878
#3: -3.200882 3.136663
#4: -8.283567 10.380427
#5: -10.989466 14.236833
#
#[[2]]
# a b
#1: -12.045692 15.742150
#2: -13.199384 17.386375
#3: -6.176316 7.377206
#4: -13.549293 17.885059
#5: -3.025583 2.886829
我有两个嵌套的 for 循环,我在每个循环中加载(这里模拟)和操作数据,以创建多个列表。
library(data.table)
for(i in 1:20){
perm <- rnorm(1); res <- list()
for(j in 1:500){
temp <- runif(5,0,20)
res[[j]] <- data.table(a=temp/perm, b=temp+perm)
}
assign(paste0("x",i),res); rm(res)
}
因为内部 for 循环输出 data.table,我在外部 for 循环的每次迭代中创建一个列表来保存内部循环产生的不同 data.table。
我读到 here and here 使用 assign(.)
的设置不是很方便,我想知道这是否可以改进。
一方面,我喜欢对 j 循环列表进行编号,这样我就可以将它们与加载到那里的数据集相关联(这里是模拟的)。另一方面,i-loop 可以生成列表列表,但我想知道除了可伸缩性之外还有什么优势。
使用基本 R *pply*
函数族或 purrr
中的 map_*
族函数对您有很大帮助。这是您使用基本 R 的代码:
res <- lapply(1:20, function(i) {
perm <- rnorm(100)
ret <- lapply(1:500, function(j) {
temp <- runif(5, 0, 20)
data.frame(a=temp/perm[i], b=temp+perm[i])
})
})
优点:无需填充当前环境,您有一个对象 (res
),您可以使用循环等轻松操作该对象。将结果存储在列表中的最直接优势是方便。您可以一次保存所有结果 (save(res, file="res.rda")
),计算您有多少 (length(res)
),用 lapply
或 map
浏览它们。
比如说,您想从 20 个重复中的每一个中获取第一个 j
索引:
j1 <- map(res, ~ .[[1]])
哦,你想把所有的都放在一个数据框中吗?
j1 <- map_dfr(res, ~ .[[1]])
第二个优势:您会立即发现您的代码有问题。对于每个 i,您生成 100 个随机数 (perm
),但您只使用...其中一个用于每个 i
! (perm[i]
,对于 1..20 中的 i)。为什么你需要 100 个?
列表的列表很好用,也很容易使用。但是,模式矩阵 "list" 可能是一个非常方便的替代方案:
m <- 2
n <- 3
res <- vector(length = m * n, mode = "list")
res <- matrix(res, ncol = m)
library(data.table)
for(i in 1:n){
perm <- rnorm(100)
for(j in 1:m){
temp <- runif(5,0,20)
res[i,j] <- list(data.table(a=temp/perm[i], b=temp+perm[i]))
}
}
res[1,] #result from first iteration of outer loop
#[[1]]
# a b
#1: -6.434118 7.744621
#2: -7.741497 9.607878
#3: -3.200882 3.136663
#4: -8.283567 10.380427
#5: -10.989466 14.236833
#
#[[2]]
# a b
#1: -12.045692 15.742150
#2: -13.199384 17.386375
#3: -6.176316 7.377206
#4: -13.549293 17.885059
#5: -3.025583 2.886829