Wert an leeren Vektor in R anhängen?


159

Ich versuche R zu lernen und kann nicht herausfinden, wie ich an eine Liste anhängen soll.

Wenn dies Python wäre, würde ich. . .

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

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

Wie machst du das 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

Nur aus Gründen der Klarheit würden Sie dies in Python nicht so machen, zumindest wenn ich Sie richtig verstehe. du könntest es einfach tun vector = values; oder Sie könnten vector = vector + values ​​tun. Aber ich könnte Ihren Anwendungsfall falsch verstehen
Privat

Antworten:


208

Das Anhängen an ein Objekt in einer for-Schleife bewirkt, dass das gesamte Objekt bei jeder Iteration kopiert wird, was dazu führt, dass viele Leute sagen "R ist langsam" oder "R-Schleifen sollten vermieden werden".

Wie BrodieG in den Kommentaren erwähnt hat: Es ist viel besser, einen Vektor der gewünschten Länge vorab zuzuweisen und dann die Elementwerte in der Schleife festzulegen .

Es gibt verschiedene Möglichkeiten, Werte an einen Vektor anzuhängen. Alle von ihnen sind entmutigt.

Anhängen an einen Vektor in einer Schleife

# 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")hätte Ihre Frage beantwortet und die Zeit gespart, die Sie zum Schreiben dieser Frage benötigt haben (hätte aber dazu geführt, dass Sie schlechte Gewohnheiten entwickelt haben). ;-);

Beachten Sie, dass dies vector <- c()kein leerer Vektor ist. es ist NULL. Wenn Sie einen leeren Zeichenvektor möchten, verwenden Sie vector <- character().

Ordnen Sie den Vektor vor dem Schleifen vorab zu

Wenn Sie unbedingt eine for-Schleife verwenden müssen, sollten Sie den gesamten Vektor vor der Schleife vorab zuweisen. Dies ist viel schneller als das Anhängen für größere Vektoren.

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
Ich habe es versucht, aber eine NULL-Liste bekommen, als ich
drucke

6
+1 zur Erinnerung an Ineffizienz, aber vielleicht Details zur Umgehung hinzufügen ( vector <- character(length(values)); for(...)?
BrodieG

20
Wenn alle entmutigt sind, wäre es schön hervorzuheben, was stattdessen gefördert wird, da dies ein ziemlich häufiges Muster ist.
Baxx

An dieser Stelle kann es sich auch lohnen, das großartige Buch "R inferno" zu erwähnen, in dem wachsende Vektoren in Kreis 2 behandelt werden burns-stat.com/pages/Tutor/R_inferno.pdf
Tjebo

62

FWIW: analog zu pythons append ():

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

8
Es gibt auch das append () in R. Wird verwendet als : b <- 1; b <- append(b, 2). Aber wie Sie bereits erwähnt haben, ist c () eine eher R-Methode, um Dinge zu tun.
Juanbretti

31

Sie haben einige Möglichkeiten:

  • c(vector, values)

  • append(vector, values)

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

Der erste ist der Standardansatz. Mit dem zweiten können Sie einen anderen Ort als das Ende anhängen. Der letzte ist etwas verzerrt, hat aber den Vorteil, dass er geändert werden kann vector(obwohl dies wirklich genauso einfach möglich ist vector <- c(vector, values).

Beachten Sie, dass Sie in R keine Vektoren durchlaufen müssen. Sie können sie nur als Ganzes bearbeiten.

Dies ist auch ziemlich grundlegend, so dass Sie einige der Referenzen durchgehen sollten .

Einige weitere Optionen basierend auf OP-Feedback:

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

Ich mache etwas etwas komplizierter. Ich muss sie durch for-Schleife anhängen, weil ich sie
ändere

1
@ draconisthe0ry, warum gibst du nicht mehr Details darüber an, was du versuchst zu tun?
BrodieG

1
Oh, ich verstehe! anstatt c (Vektor, Werte [i]) in der for-Schleife
auszuführen,

Vermeintliche ich möchte verwenden , cum append Datenrahmen anstelle von Vektoren?
Loretoparisi

18

Der Vollständigkeit halber ist das Anhängen von Werten an einen Vektor in einer for-Schleife nicht wirklich die Philosophie in R. R funktioniert besser, wenn Vektoren als Ganzes bearbeitet werden, wie @BrodieG hervorhob. Überprüfen Sie, ob Ihr Code nicht wie folgt umgeschrieben werden kann:

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

Die Ausgabe ist ein Vektor von Rückgabewerten. Sie können auch verwenden, lapplywenn Werte eine Liste anstelle eines Vektors sind.


8

Manchmal müssen wir Schleifen verwenden, wenn wir beispielsweise nicht wissen, wie viele Iterationen wir benötigen, um das Ergebnis zu erhalten. Nehmen Sie als Beispiel while-Schleifen. Nachfolgend finden Sie Methoden, die Sie unbedingt vermeiden sollten:

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 

Diese sind sehr ineffizient, da R den Vektor jedes Mal kopiert, wenn er angehängt wird.

Der effizienteste Weg zum Anhängen ist die Verwendung des Index. Beachten Sie, dass ich es diesmal 1e7 Mal iterieren lasse, aber es ist immer noch viel schneller als c.

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

Das ist akzeptabel. Und wir können es ein bisschen schneller machen durch den Austausch [mit [[.

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

Vielleicht haben Sie bereits bemerkt, dass lengthdies zeitaufwändig sein kann. Wenn wir durch lengtheinen Zähler ersetzen :

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

Wie andere Benutzer bereits erwähnt haben, ist die Vorabzuweisung des Vektors sehr hilfreich. Dies ist jedoch ein Kompromiss zwischen Geschwindigkeit und Speichernutzung, wenn Sie nicht wissen, wie viele Schleifen Sie benötigen, um das Ergebnis zu erhalten.

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 

Eine Zwischenmethode besteht darin, nach und nach Ergebnisblöcke hinzuzufügen.

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 können Sie Folgendes ausprobieren:

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

Was Sie im Python-Code verwenden, wird in Python als Liste bezeichnet und unterscheidet sich grundlegend von R-Vektoren, wenn ich das bekomme, was Sie tun möchten:

# 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))
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.