将值附加到R中的空向量?

O.r*_*rka 141 r list vector append

我正在尝试学习R而我无法弄清楚如何附加到列表中.

如果这是Python我会的...

#Python
vector = []
values = ['a','b','c','d','e','f','g']

for i in range(0,len(values)):
    vector.append(values[i])
Run Code Online (Sandbox Code Playgroud)

你是怎么用R做的?

#R Programming
> vector = c()
> values = c('a','b','c','d','e','f','g')
> for (i in 1:length(values))
+ #append value[i] to empty vector
Run Code Online (Sandbox Code Playgroud)

Jos*_*ich 184

这有几种方法可以做到.所有人都气馁.附加到for循环中的对象会导致整个对象在每次迭代时被复制,这会导致很多人说"R很慢",或者"应该避免使用R循环".

# one way
for (i in 1:length(values))
  vector[i] <- values[i]
# another way
for (i in 1:length(values))
  vector <- c(vector, values[i])
# yet another way?!?
for (v in values)
  vector <- c(vector, v)
# ... more ways
Run Code Online (Sandbox Code Playgroud)

help("append")会回答你的问题并节省你写这个问题的时间(但会导致你养成坏习惯).;-)

请注意,这vector <- c()不是空矢量; 它是NULL.如果你想要一个空的字符向量,请使用vector <- character().

还要注意,正如BrodieG在评论中指出的那样:如果你绝对必须使用for循环,那么至少在循环之前预先分配整个向量.这比附加更大的向量要快得多.

set.seed(21)
values <- sample(letters, 1e4, TRUE)
vector <- character(0)
# slow
system.time( for (i in 1:length(values)) vector[i] <- values[i] )
#   user  system elapsed 
#  0.340   0.000   0.343 
vector <- character(length(values))
# fast(er)
system.time( for (i in 1:length(values)) vector[i] <- values[i] )
#   user  system elapsed 
#  0.024   0.000   0.023 
Run Code Online (Sandbox Code Playgroud)

  • 如果不鼓励所有人,那么强调鼓励什么是鼓励的,因为这是一种相当普遍的模式. (10认同)
  • 提示关于低效率的提示+1,但可能会添加有关如何解决的详细信息(`vector < - character(length(values)); for(...`)? (6认同)
  • 我试过这个但是当我打印(矢量)时得到一个NULL列表 (2认同)

Mat*_*ien 57

FWIW:类似于python的append():

b <- 1
b <- c(b, 2)
Run Code Online (Sandbox Code Playgroud)

  • R中还有**append()**.用作:`b < - 1; b < - 追加(b,2)`.但正如你所提到的,**c()**是一种更R的做事方式. (7认同)

Bro*_*ieG 28

你有几个选择:

for(i in values) vector <- c(vector, i)
Run Code Online (Sandbox Code Playgroud)

第一个是标准方法.第二个允许您选择追加除结尾之外的某个位置.最后一个有点扭曲,但具有修改的优势c(vector, values)(尽管如此,你可以轻松做到append(vector, values).

请注意,在R中,您不需要循环遍历向量.你可以整体操作它们.

此外,这是相当基本的东西,所以你应该通过一些参考.

基于OP反馈的更多选项:

for(i in values) vector <- c(vector, i)
Run Code Online (Sandbox Code Playgroud)


ant*_*ine 15

仅仅为了完整性,将值附加到for循环中的向量并不是R中的哲学.通过对整个向量进行操作,R的效果更好,正如@BrodieG所指出的那样.看看您的代码是否无法重写为:

ouput <- sapply(values, function(v) return(2*v))
Run Code Online (Sandbox Code Playgroud)

输出将是返回值的向量.您还可以使用lapplyif值是列表而不是向量.


use*_*419 5

有时我们必须使用循环,例如,当我们不知道需要多少迭代来获得结果时.以while循环为例.以下是您绝对应该避免的方法:

a=numeric(0)
b=1
system.time(
  {
    while(b<=1e5){
      b=b+1
      a<-c(a,pi)
    }
  }
)
# user  system elapsed 
# 13.2     0.0    13.2 

a=numeric(0)
b=1
system.time(
  {
    while(b<=1e5){
      b=b+1
      a<-append(a,pi)
    }
  }
)
# user  system elapsed 
# 11.06    5.72   16.84 
Run Code Online (Sandbox Code Playgroud)

这些效率非常低,因为R每次附加时都会复制矢量.

追加的最有效方法是使用索引.请注意,这次我让它迭代1e7次,但它仍然比它快得多c.

a=numeric(0)
system.time(
  {
    while(length(a)<1e7){
      a[length(a)+1]=pi
    }
  }
)
# user  system elapsed 
# 5.71    0.39    6.12  
Run Code Online (Sandbox Code Playgroud)

这是可以接受的.我们可以通过替换[来加快速度[[.

a=numeric(0)
system.time(
  {
    while(length(a)<1e7){
      a[[length(a)+1]]=pi
    }
  }
)
# user  system elapsed 
# 5.29    0.38    5.69   
Run Code Online (Sandbox Code Playgroud)

也许你已经注意到这length可能很费时间.如果我们length用柜台替换:

a=numeric(0)
b=1
system.time(
  {
    while(b<=1e7){
      a[[b]]=pi
      b=b+1
    }
  }
)
# user  system elapsed 
# 3.35    0.41    3.76
Run Code Online (Sandbox Code Playgroud)

正如其他用户所提到的,预先分配向量非常有用.但是,如果您不知道获得结果需要多少循环,那么这是速度和内存使用之间的权衡.

a=rep(NaN,2*1e7)
b=1
system.time(
  {
    while(b<=1e7){
      a[[b]]=pi
      b=b+1
    }
    a=a[!is.na(a)]
  }
)
# user  system elapsed 
# 1.57    0.06    1.63 
Run Code Online (Sandbox Code Playgroud)

中间方法是逐步添加结果块.

a=numeric(0)
b=0
step_count=0
step=1e6
system.time(
  {
    repeat{
      a_step=rep(NaN,step)
      for(i in seq_len(step)){
        b=b+1
        a_step[[i]]=pi
        if(b>=1e7){
          a_step=a_step[1:i]
          break
        }
      }
      a[(step_count*step+1):b]=a_step
      if(b>=1e7) break
      step_count=step_count+1
    }
  }
)
#user  system elapsed 
#1.71    0.17    1.89
Run Code Online (Sandbox Code Playgroud)