cb1*_*b14 6 loops r vectorization nested-lists
我有一个有点复杂的数据结构(嵌套列表)y,定义为:
x <- list(
list(1, "a", 2, "b", 0.1),
list(3, "c", 4, "d", 0.2),
list(5, "e", 6, "f", 0.3)
)
y <- rep(list(x), 10)
Run Code Online (Sandbox Code Playgroud)
我还有一个数据框df,定义为:
df <- data.frame(
x1 = c( 0.33, 1.67, -0.62, -0.56, 0.17, 0.73, 0.59, 0.56, -0.22, 1.49),
x2 = c(-0.82, 1.22, 0.65, 0.54, -2.26, 1.21, -0.44, -0.92, -0.56, 0.50),
x3 = c(-0.16, 0.49, -0.82, -0.71, 0.13, 1.22, 1.23, -0.01, -1.11, 0.97)
)
Run Code Online (Sandbox Code Playgroud)
其中列名并不重要。
我想将所有和替换y[[i]][[j]][[5]]为。我的 Python/Julia 大脑在循环中工作得最好,因此我通过循环,然后循环 的元素(每个 的副本)来完成此操作,如下所示:df[[i, j]]ijyyx
for (i in seq_along(y)) {
for (j in 1:3) {
y[[i]][[j]][[5]] <- df[[i, j]]
}
}
Run Code Online (Sandbox Code Playgroud)
这可行,但对于我更大的数据集来说,它真的很慢。所以我试图向量化嵌套for循环。我一直在尝试Map():
y_new <- y
for (j in 1:3) {
y_new <- Map(function(sublist, value) { sublist[[5]] <- value; sublist },
y_new, df[, j])
}
Run Code Online (Sandbox Code Playgroud)
但上面的方法不起作用,因为identical(y, y_new)returns FALSE。我认为我缺少一定程度的子集化。
Map()我根本没有结婚。我只是在寻找嵌套循环的最快替代方案for。
@akrun 关于取消列出和重新列出的建议非常优雅且非常惯用(“类似 R”)。
但我希望在没有强制的情况下做到这一点,尤其是从数字到字符再返回,这可能会很慢并导致精度损失。像这样的事情会更快更安全:
unlist0 <- function(x) unlist(x, recursive = FALSE, use.names = FALSE)
split0 <- function(x, f) unname(split(x, f))
n <- length(y) # 10
n1 <- length(y[[1L]]) # 3
n11 <- length(y[[1L]][[1L]]) # 5
uy <- unlist0(unlist0(y))
uy[seq.int(n11, n * n1 * n11, n11)] <- as.list(t(df))
suy <- split0(split0(uy, gl(n * n1, n11)), gl(n, n1))
Run Code Online (Sandbox Code Playgroud)
这是一个基准:
unlist0 <- function(x) unlist(x, recursive = FALSE, use.names = FALSE)
split0 <- function(x, f) unname(split(x, f))
n <- length(y) # 10
n1 <- length(y[[1L]]) # 3
n11 <- length(y[[1L]][[1L]]) # 5
library(purrr)
microbenchmark::microbenchmark(
colebrookson =
{
ans <- y
for (i in seq_len(n))
for (j in seq_len(n1))
ans[[i]][[j]][[n11]] <- df[[i, j]]
ans
},
TarJae =
{
map2(y, asplit(df, 1L), ~ map2(.x, .y, ~ { .x[[n11]] <- .y; .x }))
},
akrun.1 =
{
Map(function(u, v) Map(function(uu, vv) { uu[5L] <- vv; uu }, u, v), y, asplit(df, 1L))
},
akrun.2 =
{
uy <- unlist(y)
uy[seq.int(n11, n * n1 * n11, n11)] <- c(t(df))
type.convert(relist(uy, y), as.is = TRUE)
},
`Mikael Jagan` =
{
uy <- unlist0(unlist0(y))
uy[seq.int(n11, n * n1 * n11, n11)] <- as.list(t(df))
split0(split0(uy, gl(n * n1, n11)), gl(n, n1))
},
times = 1000L
)
Run Code Online (Sandbox Code Playgroud)
Unit: microseconds
expr min lq mean median uq max neval
colebrookson 1116.635 1171.6365 1318.72441 1195.2115 1238.077 16936.567 1000
TarJae 297.783 314.8390 365.66412 331.7105 352.026 1554.679 1000
akrun.1 76.096 82.4305 96.82716 87.0840 91.676 2076.117 1000
akrun.2 1206.343 1231.1685 1345.24661 1244.2270 1261.222 5023.197 1000
Mikael Jagan 35.465 40.9590 51.61260 45.7765 50.594 1271.984 1000
Run Code Online (Sandbox Code Playgroud)
一些备注:
identical。由于精度损失而有所不同。