Acrescente valor ao vetor vazio em R?

159

Estou tentando aprender R e não consigo descobrir como anexar a uma lista.

Se fosse Python, eu faria. . .

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

for i in range(0,len(values)):
    vector.append(values[i])

Como você faz isso no 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
O.rka
fonte
apenas por uma questão de clareza, não é assim que você faria isso em python, pelo menos se eu entendi corretamente. você poderia simplesmente fazer vector = values; ou você pode fazer vector = vector + values. Mas eu posso estar entendendo mal o seu caso de uso
Privado

Respostas:

208

Anexar a um objeto em um loop for faz com que o objeto inteiro seja copiado em todas as iterações, o que faz com que muitas pessoas digam "R é lento" ou "R loops devem ser evitados".

Como BrodieG mencionou nos comentários: é muito melhor pré-alocar um vetor do comprimento desejado, depois defina os valores dos elementos no loop.

Aqui estão várias maneiras de acrescentar valores a um vetor. Todos eles estão desencorajados.

Anexando a um vetor em um loop

# 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

help("append")teria respondido à sua pergunta e economizado o tempo que você levou para escrever essa pergunta (mas teria feito com que você desenvolvesse maus hábitos). ;-)

Observe que vector <- c()não é um vetor vazio; ele é NULL. Se você deseja um vetor de caractere vazio, use vector <- character().

Aloque previamente o vetor antes de fazer o loop

Se você absolutamente precisar usar um loop for, pré-aloque todo o vetor antes do loop. Isso será muito mais rápido do que o anexo para vetores maiores.

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 
Joshua Ulrich
fonte
2
Eu tentei isso, mas tem uma lista NULL quando eu imprimir (vector)
O.rka
6
+1 como lembrete de ineficiência, mas talvez adicione detalhes sobre como contornar ( vector <- character(length(values)); for(...)?
BrodieG
20
Se todos estiverem desanimados, seria bom destacar o que é incentivado, pois esse é um padrão bastante comum.
Baxx
neste ponto, vale a pena mencionar também o grande livro "R inferno", que discute vetores crescentes no círculo 2 burns-stat.com/pages/Tutor/R_inferno.pdf
Tjebo
62

FWIW: análogo ao append do python ():

b <- 1
b <- c(b, 2)
tumultous_rooster
fonte
8
Há também o append () na R. será usado como: b <- 1; b <- append(b, 2). Mas como você mencionou, c () é uma maneira mais R de fazer as coisas.
Juanbretti
31

Você tem poucas opções:

  • c(vector, values)

  • append(vector, values)

  • vector[(length(vector) + 1):(length(vector) + length(values))] <- values

O primeiro é a abordagem padrão. O segundo oferece a opção de acrescentar outro lugar que não o final. O último é um pouco contorcido, mas tem a vantagem de modificar vector(embora realmente, você poderia fazer isso com a mesma facilidade) vector <- c(vector, values).

Observe que em R você não precisa alternar entre vetores. Você pode apenas operar neles por inteiro.

Além disso, esse é um material bastante básico, então você deve passar por algumas das referências .

Mais algumas opções baseadas no feedback do OP:

for(i in values) vector <- c(vector, i)
BrodieG
fonte
Estou fazendo algo um pouco mais complicado. eu preciso anexá-los através de loop for porque estou modificando-os
O.rka
1
@ draconisthe0ry, por que você não fornece mais detalhes sobre o que está tentando fazer?
BrodieG
1
Ah eu vejo! em vez de fazer c (vetor, valores [i]) no loop for que você tem que "vector = C (vetor, valores [i])
O.rka
suposto eu gostaria de usar cpara acrescentar dataframe em vez de vetores?
Loretoparisi
18

Por uma questão de integridade, acrescentar valores a um vetor em um loop for não é realmente a filosofia em R.R funciona melhor operando em vetores como um todo, como @BrodieG apontou. Veja se seu código não pode ser reescrito como:

ouput <- sapply(values, function(v) return(2*v))

A saída será um vetor de valores de retorno. Você também pode usar lapplyse valores for uma lista em vez de um vetor.

antoine
fonte
8

Às vezes, temos que usar loops, por exemplo, quando não sabemos quantas iterações precisamos para obter o resultado. Tome enquanto loops como um exemplo. Abaixo estão os métodos que você absolutamente deve evitar:

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 

Eles são muito ineficientes porque R copia o vetor toda vez que ele anexa.

A maneira mais eficiente de acrescentar é usar o índice. Observe que desta vez eu deixo repetir 1e7 vezes, mas ainda é muito mais rápido que c.

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

Isso é aceitável. E podemos torná-lo um pouco mais rápido substituindo [por [[.

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

Talvez você já tenha notado que isso lengthpode consumir tempo. Se substituirmos lengthpor um contador:

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

Como outros usuários mencionaram, pré-alocar o vetor é muito útil. Mas isso é uma troca entre velocidade e uso de memória, se você não souber quantos ciclos precisa para obter o resultado.

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 

Um método intermediário é adicionar gradualmente blocos de resultados.

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
user2923419
fonte
2

No R, você pode tentar desta maneira:

X = NULL
X
# NULL
values = letters[1:10]
values
# [1] "a" "b" "c" "d" "e" "f" "g" "h" "i" "j"
X = append(X,values)
X
# [1] "a" "b" "c" "d" "e" "f" "g" "h" "i" "j"
X = append(X,letters[23:26])
X
# [1] "a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "w" "x" "y" "z"
Sowmya S. Manian
fonte
2
> vec <- c(letters[1:3]) # vec <- c("a","b","c") ; or just empty vector: vec <- c()

> values<- c(1,2,3)

> for (i in 1:length(values)){
      print(paste("length of vec", length(vec))); 
      vec[length(vec)+1] <- values[i]  #Appends value at the end of vector
  }

[1] "length of vec 3"
[1] "length of vec 4"
[1] "length of vec 5"

> vec
[1] "a" "b" "c" "1" "2" "3"
Surya
fonte
0

O que você está usando no código python é chamado de lista em python, e é totalmente diferente dos vetores R, se eu conseguir o que você quer fazer:

# you can do like this if you'll put them manually  
v <- c("a", "b", "c")

# if your values are in a list 
v <- as.vector(your_list)

# if you just need to append
v <- append(v, value, after=length(v))
Youssef Snoussi
fonte