¿Agregar valor al vector vacío en R?

160

Estoy tratando de aprender R y no puedo entender cómo agregar a una lista.

Si esto fuera Python, lo haría. . .

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

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

¿Cómo se hace esto en 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
fuente
solo por claridad, no es así como harías esto en python, al menos si te entiendo correctamente. simplemente podrías hacer vector = values; o podrías hacer vector = vector + valores. Pero podría estar malentendiendo su caso de uso
Privado

Respuestas:

210

Agregar a un objeto en un bucle for hace que todo el objeto se copie en cada iteración, lo que hace que mucha gente diga "R es lento" o "Se deben evitar los bucles R".

Como mencionó BrodieG en los comentarios: es mucho mejor asignar previamente un vector de la longitud deseada, luego establecer los valores de los elementos en el bucle.

Aquí hay varias formas de agregar valores a un vector. Todos ellos están desanimados.

Agregar a un vector en un bucle

# 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")habría respondido a su pregunta y ahorrado el tiempo que le tomó escribir esta pregunta (pero le habría causado desarrollar malos hábitos). ;-)

Tenga en cuenta que vector <- c()no es un vector vacío; es NULL. Si desea un vector de caracteres vacío, use vector <- character().

Preasignar el vector antes de repetir

Si absolutamente debe usar un bucle for, debe preasignar todo el vector antes del bucle. Esto será mucho más rápido que agregar para vectores más grandes.

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
fuente
2
Intenté esto pero obtuve una lista NULL cuando
imprimo
66
¿+1 para recordar la ineficiencia, pero tal vez agregar detalles sobre cómo solucionar ( vector <- character(length(values)); for(...)?
BrodieG
20
Si todos se desaniman, sería bueno resaltar lo que se fomenta, ya que este es un patrón bastante común.
baxx
en este punto, puede valer la pena mencionar también el gran libro "R inferno" que analiza los vectores en crecimiento en el círculo 2 burns-stat.com/pages/Tutor/R_inferno.pdf
Tjebo
62

FWIW: análogo al apéndice de Python ():

b <- 1
b <- c(b, 2)
tumultous_rooster
fuente
8
También está el modo de adición () en R. Se puede utilizar como: b <- 1; b <- append(b, 2). Pero como mencionas, c () es una forma más R de hacer las cosas.
juanbretti
31

Tienes pocas opciones:

  • c(vector, values)

  • append(vector, values)

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

El primero es el enfoque estándar. El segundo te da la opción de agregar otro lugar que no sea el final. El último está un poco retorcido pero tiene la ventaja de modificarse vector(aunque en realidad, podría hacerlo con la misma facilidad) vector <- c(vector, values).

Tenga en cuenta que en R no necesita recorrer los vectores. Puede operarlos en su totalidad.

Además, esto es bastante básico, por lo que debe revisar algunas de las referencias .

Algunas opciones más basadas en comentarios OP:

for(i in values) vector <- c(vector, i)
BrodieG
fuente
Estoy haciendo algo un poco más complicado aunque. necesito agregarlos a través de for-loop porque los estoy modificando
O.rka
1
@ draconisthe0ry, ¿por qué no proporciona más detalles sobre lo que está tratando de hacer?
BrodieG
1
¡Oh ya veo! en lugar de hacer c (vector, valores [i]) en el bucle for, debe "vector = c (vector, valores [i])
O.rka
¿se supone que me gustaría usar cpara agregar un marco de datos en lugar de vectores?
loretoparisi
18

Solo en aras de la integridad, agregar valores a un vector en un bucle for no es realmente la filosofía en R. R funciona mejor operando en vectores en su conjunto, como señaló @BrodieG. Vea si su código no puede reescribirse como:

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

La salida será un vector de valores de retorno. También puede usar lapplyif values ​​es una lista en lugar de un vector.

antoine
fuente
8

A veces tenemos que usar bucles, por ejemplo, cuando no sabemos cuántas iteraciones necesitamos para obtener el resultado. Tome los bucles while como ejemplo. A continuación se detallan los métodos que debe 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 

Estos son muy ineficientes porque R copia el vector cada vez que se agrega.

La forma más eficiente de agregar es usar index. Tenga en cuenta que esta vez lo dejé iterar 1e7 veces, pero aún es mucho más 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  

Esto es aceptable Y podemos hacerlo un poco más rápido reemplazando [con [[.

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

Tal vez ya haya notado que lengthpuede llevar mucho tiempo. Si reemplazamos lengthcon un 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 mencionaron otros usuarios, la preasignación del vector es muy útil. Pero esto es una compensación entre la velocidad y el uso de la memoria si no sabe cuántos bucles necesita para obtener el 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 

Un método intermedio es agregar gradualmente bloques 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
usuario2923419
fuente
2

En R, puedes probar de esta manera:

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
fuente
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
fuente
0

Lo que estás usando en el código de Python se llama una lista en Python, y es muy diferente de los vectores R, si obtengo lo que quieres hacer:

# 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
fuente