2012-03-25 15 views
343

Wenn ich ein data.frame filtern müssen, das heißt, zu extrahieren Zeilen, die bestimmte Bedingungen erfüllen, ziehe ich die subset Funktion zu verwenden:Warum ist `[` besser als `Teilmenge`?

subset(airquality, Month == 8 & Temp > 90) 

Anstatt die [ Funktion:

airquality[airquality$Month == 8 & airquality$Temp > 90, ] 

Es sind zwei Hauptgründe für meine Präferenz:

  1. Ich finde den Code liest besser, von links nach rechts. Sogar Leute, die nichts über R wissen, können sagen, was die oben genannte Anweisung tut.

  2. Da Spalten im Ausdruck select als Variablen bezeichnet werden können, kann ich ein paar Tastenanschläge speichern. In meinem obigen Beispiel musste ich nur airquality einmal mit subset eingeben, aber dreimal mit [.

So war ich leben glücklich, mit subset überall, weil es kürzer ist und liest besser, auch seine Schönheit zu meinen Kolleginnen und R Programmierer befürworten. Aber gestern ist meine Welt auseinander gebrochen. Beim Lesen der subset Dokumentation, merke ich diesen Abschnitt:

Warning

This is a convenience function intended for use interactively. For programming it is better to use the standard subsetting functions like [, and in particular the non-standard evaluation of argument subset can have unanticipated consequences.

Könnte jemand helfen klären, was die Autoren bedeuten?

Zuerst, was meinen sie mit "für interaktiv verwenden"? Ich weiß, was eine interaktive Sitzung ist, im Gegensatz zu einem Skript, das im BATCH-Modus ausgeführt wird, aber ich sehe nicht, welchen Unterschied es machen sollte.

Dann könnten Sie bitte erklären "die nicht-Standard-Evaluierung der Argument-Untermenge" und warum es gefährlich ist, vielleicht ein Beispiel geben?

+12

Es ist etwas weniger (aber Mutter kleiner als Teilmenge) mit verwenden, 'mit (Luftgüte, Luftgüte [Monat == 8 & Temp> 90])' –

+1

Dieser Thread behandelt die Warnung 'subset()': http://r.789695.n4.nabble.com/Variable-passed-to-function-not-used-in-function-in-select-in-subset- tt872217.html – jthetzel

+3

Sie können sich auch Cirlces 8.2.31 und 8.2.32 von 'The R Inferno' anschauen http://www.burns-stat.com/pages/Tutor/R_inferno.pdf –

Antwort

201

Diese Frage wurde in den Kommentaren von @James gut beantwortet und zeigte auf eine ausgezeichnete Erklärung von Hadley Wickham über die Gefahren von subset (und funktioniert so) [here]. Geh und lies es!

Es ist eine etwas lange zu lesen, so kann es hilfreich sein hier das Beispiel aufzuzeichnen, die Hadley verwendet, dass die meisten direkt die Frage der Adressen „was schief gehen kann?“:

Hadley schlägt das folgende Beispiel: Angenommen, wir der Teilmenge soll, und dann einen Datenrahmen unter Verwendung der folgenden Funktionen neu anordnen:

scramble <- function(x) x[sample(nrow(x)), ] 

subscramble <- function(x, condition) { 
    scramble(subset(x, condition)) 
} 

subscramble(mtcars, cyl == 4) 

das den Fehler zurückgibt:

Error in eval(expr, envir, enclos) : object 'cyl' not found

weil kein R l onger "weiß", wo das Objekt "cyl" zu finden ist. Er weist auch auf die wirklich bizarre Sachen aus, die durch Zufall passieren kann sich ein Objekt ‚Zyl‘ in der globalen Umwelt genannt ist:

cyl <- 4 
subscramble(mtcars, cyl == 4) 

cyl <- sample(10, 100, rep = T) 
subscramble(mtcars, cyl == 4) 

(Führen Sie sie und sehen Sie selbst, es ist ziemlich verrückt.)

+2

Darf ich einige neue Fragen zur Klärung haben? Wenn wir 'subset (mtcars, cyl == 4)' (auf oberster Ebene) schreiben, wo sucht R nach cyl? Wenn es in das 'mtcars'-Objekt schaut, das an' subset() 'übergeben wird, sollte es 'cyl' nicht finden können, selbst wenn' scramble' innerhalb einer anderen Funktion ist, da 'mtcars' immer noch übergeben wird es? Wenn meine Frage keinen Sinn ergibt, könntest du einfach weiter ausführen, warum R 'cyl' nicht mehr finden kann. Vielen Dank! – Heisenberg

+3

@Anh Innerhalb 'subset.data.frame' ist die Sache, die wir an diesem Punkt zu bewerten versuchen, nur' Bedingung'. Das gibt es nicht in 'mtcars'. So verwendet 'subset.data.frame'' enclos = parent.frame() 'um sicherzustellen, dass' condition' korrekt als 'cyl == 4' ausgewertet wird. Aber dann sind wir zum umschließenden Rahmen zurückgekehrt, und jetzt, wenn R nach 'cyl' sucht, schaut er nicht mehr in 'mtcars'. Wenn wir 'enclos' nicht verwenden würden, würde etwas wie" subset (mtcars, cyl == a) "überhaupt nicht funktionieren. – joran

+0

weiß jemand, warum subset() nicht nur die schnellere und sicherere Methode hinter den Kulissen implementieren würde? –

20

Auch ist [ schneller:

require(microbenchmark)   
microbenchmark(subset(airquality, Month == 8 & Temp > 90),airquality[airquality$Month == 8 & airquality$Temp > 90,]) 
    Unit: microseconds 
                  expr  min  lq median  uq  max neval 
        subset(airquality, Month == 8 & Temp > 90) 301.994 312.1565 317.3600 349.4170 500.903 100 
    airquality[airquality$Month == 8 & airquality$Temp > 90, ] 234.807 239.3125 244.2715 271.7885 340.058 100 
+26

Ja und Nein. Ich denke, der Zeitunterschied, den Sie sehen, ist auf zwei Dinge zurückzuführen. 1) ein kleiner (<100 Mikrosekunden) Overhead und 2) "Teilmenge" im Gegensatz zu "[" entfernt Zeilen, bei denen der Filter "NA" auswertet. Tun Sie dies und Sie werden sehen, dass sie beide so schnell sind, wenn sie "ziemlich" verglichen werden: 'x <- do.call (rbind, rep (liste (Luftqualität), 100)); microbenchmark (Teilmenge (x, Monat == 8 & Temp> 90), {i <- x $ Monat == 8 & x $ Temp> 90; x [! is.na (i) & i,]}) ' – flodel

Verwandte Themen