2010-07-26 7 views
28

Angenommen, Sie haben einen Datenrahmen mit vielen Zeilen und vielen Spalten.In R, wie überschleifen Sie die Zeilen eines Datenrahmens wirklich schnell?

Die Spalten haben Namen. Sie möchten auf Zeilen nach Nummer und Spalten nach Namen zugreifen.

Zum Beispiel ist ein (möglicherweise langsam) Weg über die Zeilen-Schleife ist

for (i in 1:nrow(df)) { 
    print(df[i, "column1"]) 
    # do more things with the data frame... 
} 

Ein anderer Weg „Listen“ für die separaten Spalten zu erzeugen, ist (wie column1_list = df[["column1"]) und die Listen in einer Schleife zuzugreifen. Dieser Ansatz ist zwar schnell, aber auch unpraktisch, wenn Sie auf viele Spalten zugreifen möchten.

Gibt es eine schnelle Möglichkeit, die Zeilen eines Datenrahmens zu durchlaufen? Ist eine andere Datenstruktur besser für eine schnelle Schleife geeignet?

+1

Wie ist das anders als df [, "Spalte1"]? Siehe auch apply with margin = 1. – Greg

+0

Das Beispiel war nicht das, was ich wirklich machen wollte. Ich wollte einige Werte im Datenrahmen als Daten in einer Javascript-Datei schreiben. +1 für die Information über "margin" in "apply". –

+0

Ich musste die Zeilen durchlaufen, um Werte in Spalten in bestimmten Situationen zu verschieben. Ich wurde daran erinnert, dass der bessere Weg, dies in R zu tun ist: http://stackoverflow.com/questions/7746567/how-to-swap-values-between-2-columns – thadk

Antwort

13

Ich denke, ich muss dies eine vollständige Antwort machen, weil ich Kommentare schwerer zu verfolgen finde und ich habe bereits einen Kommentar zu diesem Thema verloren ... Es gibt ein Beispiel von nullglob, das die Unterschiede zwischen zeigt und viele Familienfunktionen anwenden besser als andere Beispiele. Wenn man die Funktion so ausführt, dass sie sehr langsam ist, dann wird die ganze Geschwindigkeit verbraucht und man findet keine Unterschiede zwischen den Variationen der Schleifen. Aber wenn Sie die Funktion trivial machen, können Sie sehen, wie sehr die Schleifen die Dinge beeinflussen.

Ich möchte auch hinzufügen, dass einige Mitglieder der Anwendungsfamilie, die in anderen Beispielen unerforscht sind, interessante Leistungseigenschaften haben. Zuerst zeige ich Replikationen der relativen Ergebnisse von Nullglob auf meinem Rechner.

n <- 1e6 
system.time(for(i in 1:n) sinI[i] <- sin(i)) 
    user system elapsed 
5.721 0.028 5.712 

lapply runs much faster for the same result 
system.time(sinI <- lapply(1:n,sin)) 
    user system elapsed 
    1.353 0.012 1.361 

Er fand auch sapply viel langsamer. Hier sind einige andere, die nicht getestet wurden.

Plain alter zu einer Matrix Version der Daten gilt ...

mat <- matrix(1:n,ncol =1),1,sin) 
system.time(sinI <- apply(mat,1,sin)) 
    user system elapsed 
    8.478 0.116 8.531 

Also, die apply() Befehl selbst ist wesentlich langsamer als die for-Schleife. (For-Schleife wird nicht verlangsamt deutlich, wenn ich sin verwenden (mat [i, 1]).

eine andere, die nicht in anderen Beiträgen getestet zu sein scheint ist tapply.

system.time(sinI <- tapply(1:n, 1:n, sin)) 
    user system elapsed 
12.908 0.266 13.589 

Natürlich man würde niemals tapply auf diese Weise verwenden, und sein Nutzen liegt in den meisten Fällen weit über einem solchen Geschwindigkeitsproblem

+1

+1 für den Verweis auf nullglob. Sein Beitrag enthält einen Verweis auf den Artikel "Wie kann ich diesen Loop vermeiden oder schneller machen?", Von Uwe Ligges und John Fox, in "R News", Mai 2008. Danke, dass Sie über die Anwendungsfunktionen geschrieben haben. –

11

Der schnellste Weg ist nicht Schleife (d. H. Vektorisierte Operationen). Einer der einzigen Fälle, in denen Sie eine Schleife ausführen müssen, ist, wenn Abhängigkeiten vorhanden sind (d. H. Eine Iteration hängt von einer anderen ab). Versuchen Sie andernfalls, so viel vektorisierte Berechnung wie möglich außerhalb der Schleife auszuführen.

Wenn Sie Notwendigkeit Schleife tun , dann eine for Schleife ist im Wesentlichen so schnell wie irgend etwas anderes (lapply etwas schneller sein können, aber other apply functions tend to be around the same speed as for).

+1

Vielleicht gibt es keine Möglichkeit, die Schleife zu vermeiden Was ich tun wollte - siehe meine Antwort auf Gregs Kommentar oben. –

+1

"ungefähr die gleiche Geschwindigkeit"? Hast du alle Antworten gelesen? In meiner Antwort dort zeigen, ich, dass mit vapply wird 3x schneller (für dieses Beispiel) als die for-Schleife ... – Tommy

+2

Im Hinblick auf die Effizienz, sie sind sehr ähnlich in der Geschwindigkeit: [Effizienz] (http: // en .wikipedia.org/wiki/Algorithmic_efficiency) – Toby

0

Ausnutzen der Tatsache, dass data.frames im Wesentlichen Listen von Spaltenvektoren sind, kann man do.call verwenden, um eine Funktion anzuwenden mit der Anzahl der Spalten über jeder Spalte des data.frames (ähnlich einem "Zippen" über eine Liste in anderen Sprachen).

do.call(paste, data.frame(x=c(1,2), z=c("a","b"), z=c(5,6))) 
+0

Aber das ist keine Schleife. –