有效使用载体

时间:2015-10-15 05:25:09

标签: r vector

我正在尝试使用以下语法将一个向量复制到另一个向量:

data<-NULL
for( i in 1:nrow(line)){
  data=append(data,line[i*4])
}

从我所看到的情况来看,以这种方式使用append会导致大量数据复制,这使得R非常慢。将一个数组的第四个元素复制到另一个数组的语法是什么,假设您复制的列表具有给定的大小?

2 个答案:

答案 0 :(得分:2)

如果您尝试从向量中提取每个第四个元素,则可以使用seq进行索引以获取正确的元素:

data <- letters[seq(4, length(letters), by=4)]
data
# [1] "d" "h" "l" "p" "t" "x"

当您在问题中显示时,一次增长一个向量将会很慢,因为您需要不断重新分配向量(有关详细信息,请参阅The R Inferno的第二个圆圈)。但是,与在单个矢量化索引操作中构造向量相比,即使预先分配向量并使用for循环构造它也会很慢。

要了解速度的提升,请考虑与您所描述的方法进行比较,除非使用预分配:

for.prealloc <- function(x) {
  data <- vector(mode="numeric", length = floor(length(x)/4))
  for (i in 1:floor(length(x)/4)) {
    data[i] <- x[i*4]
  }
  data
}
josilber <- function(x) x[seq(4, length(x), by=4)]
r <- rnorm(10000)
all.equal(for.prealloc(r), josilber(r))
# [1] TRUE

library(microbenchmark)
microbenchmark(for.prealloc(r), josilber(r))
# Unit: microseconds
#             expr      min        lq      mean   median      uq      max neval
#  for.prealloc(r) 1846.014 2035.7890 2351.9681 2094.804 2244.56 5283.285   100
#      josilber(r)   95.757   97.4125  125.9877  113.179  138.96  259.606   100

我建议的方法比使用for和预先分配的向量快20倍(它甚至比使用append和非预先分配的向量更快。)

答案 1 :(得分:2)

以下是基准测试的三种方法。你可以看到在method2函数中预先分配向量的速度要快得多,而lapply方法是中等的,而你的函数是最慢的。

当然,这些是1D向量而不是n-D阵列,但我预计基准测试会相似甚至更加明显。

method1 <- function(line) {
  data<-NULL
  for( i in 1:length(line)){
    data=append(data,line[i])
  }
}

method2 <- function(line) {
  data <- vector(mode="numeric", length = length(line))
  for (i in 1:length(line)) {
    data[i] <- line[i]
  }
}

library(microbenchmark)
r <- rnorm(1000)
microbenchmark(method2(r), unit="ms")
#> Unit: milliseconds
#>        expr     min       lq     mean   median       uq     max neval
#>  method2(r) 2.18085 2.279676 2.428731 2.371593 2.500495 5.24888   100
microbenchmark(lapply(r, function(x) { data<-append(data, x) }), unit="ms")
#> Unit: milliseconds
#>                                                    expr      min       lq
#>  lapply(r, function(x) {     data <- append(data, x) }) 3.014673 3.091299
#>      mean   median       uq      max neval
#>  3.287216 3.150052 3.260199 6.036501   100
microbenchmark(method1(r), unit="ms")
#> Unit: milliseconds
#>        expr      min       lq    mean   median       uq      max neval
#>  method1(r) 3.938684 3.978002 5.71831 4.020001 4.280521 98.58584   100

没有意识到OP只想要每四分之一。为什么不使用数据框或data.table?

d <- data.frame(matrix(rnorm(1000), ncol=1))
microbenchmark(d2 <- d[seq(1,nrow(d), 4),])
#> Unit: microseconds
#>                           expr    min      lq     mean median      uq
#>  d2 <- d[seq(1, nrow(d), 4), ] 64.846 65.9915 73.08007 67.225 73.8225
#>      max neval
#>  220.438   100
library(data.table)
dt <- data.table(d)
microbenchmark(d2 <- dt[seq(1,nrow(d), 4),])
#> Unit: microseconds
#>                            expr     min       lq     mean  median      uq
#>  d2 <- dt[seq(1, nrow(d), 4), ] 298.163 315.2025 324.8793 320.554 330.416
#>      max neval
#>  655.124   100