首页 > 解决方案 > 将具有不同长度的 for 循环中的向量组合在一起的最快方法

问题描述

我正在运行一个带有 for 循环的查询,该循环创建不同长度的向量。第一个向量的代码不一定是最长的(我创建了这个示例,以便第一列最短并且越来越长)。我想以某种方式绑定这些向量。我对这个临时 cbind.fill 函数做了一些处理,但没有让它工作(rowr::cbind.fill 在 R 4.xx 中不再可用)。

下面的示例代码无法正常运行,因为runif(i)会使每个后续循环的向量更长。请注意,对于实际数据,我不知道哪一列最长。检查这是可能的,但不是首选,尽管我可以想象可能只保留向量直到循环完成并绑定它们然后会更快。

示例代码:

dat <- c(1,2,3)
dat <- as.data.frame(dat)
for (i in 1:5) {
    temp <- runif(i)
    dat <- cbind(dat, temp)
    names(dat)[i+1] <- paste0("nr", i)
}

将输出向量转换为 data.frame的最快方法是什么?我想先将它们放入向量列表中(但在这种情况下不知道如何命名),或者可能用数量的 NA 填充每个向量length(longest_vector)-length(vector[i])

期望的输出:

# A tibble: 8 x 6
  dat   nr1                 nr2                 nr3                 nr4                    nr5
  <chr> <chr>               <chr>               <chr>               <chr>                <dbl>
1 1     1                   1                   1                   1                   1     
2 2     2                   2                   2                   2                   2     
3 3     3                   3                   3                   3                   3     
4 NA    0.43526783056537444 0.25560407791435225 0.91653997616714789 0.62635622073335406 0.888 
5 NA    NA                  0.56979342124862575 0.43296269966267631 0.46423817219260977 0.522 
6 NA    NA                  NA                  0.89399553062032511 0.34917334540558442 0.745 
7 NA    NA                  NA                  NA                  0.4131315834365703  0.0403
8 NA    NA                  NA                  NA                  NA                  0.564 

 desired_out <- structure(list(dat = c("1", "2", "3", "NA", "NA", "NA", "NA", 
"NA"), nr1 = c("1", "2", "3", "0.43526783056537444", "NA", "NA", 
"NA", "NA"), nr2 = c("1", "2", "3", "0.25560407791435225", "0.56979342124862575", 
"NA", "NA", "NA"), nr3 = c("1", "2", "3", "0.91653997616714789", 
"0.43296269966267631", "0.89399553062032511", "NA", "NA"), nr4 = c("1", 
"2", "3", "0.62635622073335406", "0.46423817219260977", "0.34917334540558442", 
"0.4131315834365703", "NA"), nr5 = c(1, 2, 3, 0.887930290142606, 
0.522131799371126, 0.745103223905874, 0.0403367661303002, 0.563609740553749
)), class = c("tbl_df", "tbl", "data.frame"), row.names = c(NA, 
-8L))

标签: rfor-loop

解决方案


您可以使用plyr::ldply不同长度的多个向量

dat <- c(1,2,3)
dat <- as.data.frame(dat)
dat.list <- list(as.vector(t(dat)))
for (i in 1:5) {
  dat.list[[(i+1)]] <- runif(i)
}
dat <- t(plyr::ldply(dat.list, rbind))
colnames(dat) <- c("dat", paste0("nr", 1:5))

> dat
  dat       nr1       nr2       nr3       nr4        nr5
1   1 0.8714848 0.8165862 0.5245153 0.7647691 0.15276644
2   2        NA 0.1034356 0.3850973 0.1769444 0.56437654
3   3        NA        NA 0.3773377 0.9142521 0.31727519
4  NA        NA        NA        NA 0.5343319 0.44647840
5  NA        NA        NA        NA        NA 0.07558151

使用检查时间成本microbenchmark::microbenchmark

microbenchmark::microbenchmark(
  a = {dat <- c(1,2,3)
  dat <- as.data.frame(dat)
  dat.list <- list(as.vector(t(dat)))
  for (i in 1:5) {
    dat.list[[(i+1)]] <- runif(i)
  }
  dat <- t(plyr::ldply(dat.list, rbind))
  colnames(dat) <- c("dat", paste0("nr", 1:5))}
)

Unit: milliseconds
 expr   min     lq     mean median      uq  max neval
    a 5.008 5.3714 5.844143 5.6862 5.98705 9.84   100

对于 1000 -1000 长度的向量 -,

microbenchmark::microbenchmark(
  a = {dat <- c(1,2,3)
  dat <- as.data.frame(dat)
  dat.list <- list(as.vector(t(dat)))
  for (i in 1:1000) {
    dat.list[[(i+1)]] <- runif(1000)
  }
  dat <- t(plyr::ldply(dat.list, rbind))
  colnames(dat) <- c("dat", paste0("nr", 1:1000))}
)

Unit: milliseconds
 expr      min      lq     mean   median       uq      max neval
    a 127.9646 132.236 151.2108 135.2484 141.3047 369.3313   100

推荐阅读