Ajouter une valeur au vecteur vide dans R?


160

J'essaie d'apprendre R et je n'arrive pas à comprendre comment ajouter à une liste.

Si c'était Python, je le ferais. . .

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

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

Comment faites-vous cela 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

juste pour des raisons de clarté, ce n'est pas ainsi que vous feriez cela en python, du moins si je vous comprends bien. vous pourriez simplement faire vector = values; ou vous pouvez faire vector = vecteur + valeurs. Mais je ne comprends peut-être pas votre cas d'utilisation
Privé

Réponses:


210

L'ajout à un objet dans une boucle for fait que l'objet entier est copié à chaque itération, ce qui amène beaucoup de gens à dire "R est lent" ou "les boucles R doivent être évitées".

Comme BrodieG l'a mentionné dans les commentaires: il est préférable de pré-allouer un vecteur de la longueur souhaitée, puis de définir les valeurs des éléments dans la boucle.

Voici plusieurs façons d'ajouter des valeurs à un vecteur. Tous sont découragés.

Ajout à un vecteur dans une boucle

# 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")aurait répondu à votre question et économisé le temps qu'il vous a fallu pour écrire cette question (mais vous aurait fait développer de mauvaises habitudes). ;-)

Notez que ce vector <- c()n'est pas un vecteur vide; c'est NULL. Si vous voulez un vecteur de caractères vide, utilisez vector <- character().

Pré-allouer le vecteur avant de boucler

Si vous devez absolument utiliser une boucle for, vous devez pré-allouer le vecteur entier avant la boucle. Ce sera beaucoup plus rapide que d'ajouter des vecteurs plus grands.

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
J'ai essayé cela mais j'ai obtenu une liste NULL lorsque
j'imprime

6
+1 pour un rappel sur l'inefficacité, mais peut-être ajouter des détails sur la façon de contourner ( vector <- character(length(values)); for(...)?
BrodieG

20
Si tout le monde est découragé, il serait bien de mettre en évidence ce qui est encouragé à la place, car il s'agit d'un schéma assez courant.
baxx

à ce stade, il vaut peut-être la peine de mentionner également le grand livre "R inferno" qui traite des vecteurs croissants dans le cercle 2 burns-stat.com/pages/Tutor/R_inferno.pdf
Tjebo

62

FWIW: analogue à append () de python:

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

8
Il y a aussi la append () R. Sera utilisé comme: b <- 1; b <- append(b, 2). Mais comme vous le dites, c () est une manière plus R de faire les choses.
juanbretti

31

Vous avez quelques options:

  • c(vector, values)

  • append(vector, values)

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

Le premier est l'approche standard. Le second vous donne la possibilité d'ajouter un endroit autre que la fin. Le dernier est un peu déformé mais a l'avantage de le modifier vector(bien que vraiment, vous puissiez le faire aussi facilement vector <- c(vector, values).

Notez que dans R, vous n'avez pas besoin de parcourir les vecteurs. Vous pouvez simplement les opérer dans leur intégralité.

En outre, ce sont des choses assez basiques, vous devriez donc consulter certaines des références .

Quelques autres options basées sur les commentaires OP:

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

Je fais quelque chose d'un peu plus compliqué. je dois les ajouter via for-loop car je les modifie
O.rka

1
@ draconisthe0ry, pourquoi ne pas fournir plus de détails sur ce que vous essayez de faire?
BrodieG

1
Oh je vois! au lieu de faire c (vecteur, valeurs [i]) dans la boucle for, vous devez "vector = c (vecteur, valeurs [i])
O.rka

supposé que je voudrais utiliser cpour ajouter des données au lieu de vecteurs?
loretoparisi

18

Par souci d'exhaustivité, ajouter des valeurs à un vecteur dans une boucle for n'est pas vraiment la philosophie de R. R fonctionne mieux en opérant sur des vecteurs dans leur ensemble, comme l'a souligné @BrodieG. Vérifiez si votre code ne peut pas être réécrit comme suit:

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

La sortie sera un vecteur de valeurs de retour. Vous pouvez également utiliser lapplysi les valeurs sont une liste au lieu d'un vecteur.


8

Parfois, nous devons utiliser des boucles, par exemple, lorsque nous ne savons pas combien d'itérations nous avons besoin pour obtenir le résultat. Prenons l'exemple des boucles while. Voici les méthodes que vous devez absolument éviter:

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 

Celles-ci sont très inefficaces car R copie le vecteur à chaque ajout.

Le moyen le plus efficace d'ajouter est d'utiliser l'index. Notez que cette fois, je le laisse itérer 1e7 fois, mais c'est quand même beaucoup plus rapide 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  

C'est acceptable. Et nous pouvons le rendre un peu plus rapide en remplaçant [par [[.

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

Peut-être avez-vous déjà remarqué que cela lengthpeut prendre du temps. Si nous remplaçons lengthpar un compteur:

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

Comme d'autres utilisateurs l'ont mentionné, la pré-allocation du vecteur est très utile. Mais c'est un compromis entre la vitesse et l'utilisation de la mémoire si vous ne savez pas combien de boucles vous avez besoin pour obtenir le résultat.

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 

Une méthode intermédiaire consiste à ajouter progressivement des blocs de résultats.

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

Dans R, vous pouvez essayer de cette façon:

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

Ce que vous utilisez dans le code python s'appelle une liste en python, et c'est totalement différent des vecteurs R, si j'obtiens ce que vous voulez faire:

# 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))
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.