Aggiungi valore al vettore vuoto in R?


160

Sto cercando di imparare R e non riesco a capire come aggiungere a un elenco.

Se questo fosse Python lo farei. . .

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

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

Come si fa in 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

solo per chiarezza, non è così che faresti in Python, almeno se ti capisco correttamente. potresti semplicemente fare vector = values; oppure potresti fare vector = vector + valori. Ma potrei fraintendere il tuo caso d'uso
Privato

Risposte:


210

L'aggiunta a un oggetto in un ciclo for fa sì che l'intero oggetto venga copiato su ogni iterazione, il che fa sì che molte persone affermino che "R è lento" o "R loop dovrebbero essere evitati".

Come BrodieG ha menzionato nei commenti: è molto meglio pre-allocare un vettore della lunghezza desiderata, quindi impostare i valori degli elementi nel loop.

Ecco alcuni modi per aggiungere valori a un vettore. Tutti sono scoraggiati.

Aggiunta a un vettore in un ciclo

# 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")avrebbe risposto alla tua domanda e risparmiato il tempo necessario per scrivere questa domanda (ma ti avrebbe causato lo sviluppo di cattive abitudini). ;-)

Nota che vector <- c()non è un vettore vuoto; lo è NULL. Se si desidera un vettore di caratteri vuoto, utilizzare vector <- character().

Pre-allocare il vettore prima del loop

Se è assolutamente necessario utilizzare un ciclo for, è necessario pre-allocare l'intero vettore prima del ciclo. Questo sarà molto più veloce rispetto all'aggiunta di vettori più grandi.

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 

2
Ho provato questo ma ho ottenuto un elenco NULL quando
stampo

6
+1 per un promemoria sull'inefficienza, ma forse aggiungere dettagli su come aggirare ( vector <- character(length(values)); for(...)?
BrodieG,

20
Se tutti sono scoraggiati, sarebbe bello evidenziare invece ciò che è incoraggiato, poiché si tratta di un modello abbastanza comune.
baxx,

a questo punto, potrebbe valere la pena menzionare anche il grande libro "R inferno" che parla dei vettori in crescita nel cerchio 2 burns-stat.com/pages/Tutor/R_inferno.pdf
Tjebo

62

FWIW: analogo all'append di Python ():

b <- 1
b <- c(b, 2)

8
C'è anche l'append () in R. saranno utilizzati come: b <- 1; b <- append(b, 2). Ma come dici, c () è un modo più R di fare le cose.
juanbretti,

31

Hai alcune opzioni:

  • c(vector, values)

  • append(vector, values)

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

Il primo è l'approccio standard. Il secondo ti dà la possibilità di aggiungere un posto diverso dalla fine. L'ultimo è un po 'contorto ma ha il vantaggio di modificarlo vector(anche se in realtà, potresti farlo altrettanto facilmente vector <- c(vector, values).

Si noti che in R non è necessario scorrere i vettori. Puoi semplicemente operare su di essi per intero.

Inoltre, questa è roba abbastanza semplice, quindi dovresti passare attraverso alcuni dei riferimenti .

Alcune altre opzioni basate sul feedback OP:

for(i in values) vector <- c(vector, i)

sto facendo qualcosa di un po 'più complicato però. ho bisogno di aggiungerli attraverso for-loop perché li sto modificando
O.rka

1
@ draconisthe0ry, perché non fornisci maggiori dettagli su ciò che stai cercando di fare?
BrodieG,

1
Oh, capisco! invece di fare c (vettore, valori [i]) nel ciclo for devi "vettore = c (vettore, valori [i])
O.rka

suppongo che vorrei usare cper aggiungere dataframe invece di vettori?
Loretoparisi,

18

Solo per completezza, aggiungere valori a un vettore in un ciclo for non è in realtà la filosofia di R. R che funziona meglio operando sui vettori nel loro insieme, come ha sottolineato @BrodieG. Verifica se il tuo codice non può essere riscritto come:

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

L'output sarà un vettore di valori di ritorno. È inoltre possibile utilizzare lapplyse i valori sono un elenco anziché un vettore.


8

A volte dobbiamo usare i loop, ad esempio, quando non sappiamo quante iterazioni abbiamo bisogno per ottenere il risultato. Prendi ad esempio i loop. Di seguito sono riportati i metodi che dovresti assolutamente evitare:

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 

Questi sono molto inefficienti perché R copia il vettore ogni volta che viene aggiunto.

Il modo più efficiente di aggiungere è utilizzare l'indice. Nota che questa volta l'ho lasciato iterare 1e7 volte, ma è comunque molto più veloce di c.

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

Questo è accettabile E possiamo renderlo un po 'più veloce sostituendolo [con [[.

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

Forse hai già notato che lengthpuò richiedere molto tempo. Se sostituiamo lengthcon un contatore:

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

Come menzionato da altri utenti, la pre-allocazione del vettore è molto utile. Ma questo è un compromesso tra velocità e utilizzo della memoria se non sai di quanti loop hai bisogno per ottenere il risultato.

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 

Un metodo intermedio consiste nell'aggiungere gradualmente blocchi di risultati.

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

2

In R, puoi provare in questo modo:

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"

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"

0

Quello che stai usando nel codice Python è chiamato un elenco in Python, ed è completamente diverso dai vettori R, se ottengo ciò che vuoi fare:

# 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))
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.