Soll ich einen data.frame oder eine Matrix verwenden?


152

Wann sollte man a verwenden data.frameund wann ist es besser, a zu verwenden matrix?

Beide halten Daten in einem rechteckigen Format, so dass es manchmal unklar ist.

Gibt es allgemeine Faustregeln für die Verwendung des Datentyps?


Oft kann eine Matrix besser für einen bestimmten Datentyp geeignet sein. Wenn das Paket, mit dem Sie diese Matrix analysieren möchten, jedoch einen Datenrahmen erwartet, müssen Sie ihn immer unnötig konvertieren. Ich denke, es gibt keine Möglichkeit zu vermeiden, sich daran zu erinnern, welches Paket welches verwendet.
xApple

Antworten:


176

Ein Teil der Antwort ist bereits in Ihrer Frage enthalten: Sie verwenden Datenrahmen, wenn erwartet werden kann, dass Spalten (Variablen) unterschiedlichen Typs sind (numerisch / Zeichen / logisch usw.). Matrizen sind für Daten des gleichen Typs.

Folglich ist die Auswahlmatrix / der Datenrahmen nur dann problematisch, wenn Sie Daten desselben Typs haben.

Die Antwort hängt davon ab, was Sie mit den Daten in data.frame / matrix tun werden. Wenn es an andere Funktionen übergeben werden soll, bestimmt der erwartete Typ der Argumente dieser Funktionen die Auswahl.

Ebenfalls:

Matrizen sind speichereffizienter:

m = matrix(1:4, 2, 2)
d = as.data.frame(m)
object.size(m)
# 216 bytes
object.size(d)
# 792 bytes

Matrizen sind eine Notwendigkeit, wenn Sie Operationen vom Typ der linearen Algebra ausführen möchten.

Datenrahmen sind praktischer, wenn Sie häufig nach Namen auf ihre Spalten verweisen (über den kompakten Operator $).

Datenrahmen eignen sich meiner Meinung nach auch besser zum Melden (Drucken) von Tabelleninformationen, da Sie die Formatierung für jede Spalte separat anwenden können.


5
Eine Sache, die ich zu dieser Antwort hinzufügen möchte, ist, dass ggplot2 nur mit data.frames und nicht mit Matrizen funktioniert, wenn Sie das ggplot2-Paket zum Erstellen von Diagrammen verwenden möchten. Nur etwas zu beachten!
Bajcz

77

Von @Michal nicht erwähnt, ist, dass nicht nur eine Matrix kleiner als der entsprechende Datenrahmen ist, sondern dass die Verwendung von Matrizen Ihren Code weitaus effizienter machen kann als die Verwendung von Datenrahmen, oftmals erheblich. Dies ist ein Grund, warum intern viele R-Funktionen zu Matrizendaten zwingen, die sich in Datenrahmen befinden.

Datenrahmen sind oft weitaus praktischer. man hat nicht immer nur atomare Datenblöcke herumliegen.

Beachten Sie, dass Sie eine Zeichenmatrix haben können. Sie müssen nicht nur numerische Daten haben, um eine Matrix in R zu erstellen.

Beachten Sie beim Konvertieren eines Datenrahmens in eine Matrix, dass es eine data.matrix()Funktion gibt, die Faktoren angemessen behandelt, indem sie basierend auf den internen Ebenen in numerische Werte konvertiert werden. Das Erzwingen über as.matrix()führt zu einer Zeichenmatrix, wenn eine der Faktorbezeichnungen nicht numerisch ist. Vergleichen Sie:

> head(as.matrix(data.frame(a = factor(letters), B = factor(LETTERS))))
     a   B  
[1,] "a" "A"
[2,] "b" "B"
[3,] "c" "C"
[4,] "d" "D"
[5,] "e" "E"
[6,] "f" "F"
> head(data.matrix(data.frame(a = factor(letters), B = factor(LETTERS))))
     a B
[1,] 1 1
[2,] 2 2
[3,] 3 3
[4,] 4 4
[5,] 5 5
[6,] 6 6

Ich verwende fast immer einen Datenrahmen für meine Datenanalyse-Aufgaben, da ich oft mehr als nur numerische Variablen habe. Wenn ich Funktionen für Pakete codiere, zwinge ich fast immer zur Matrix und formatiere die Ergebnisse dann wieder als Datenrahmen. Dies liegt daran, dass Datenrahmen praktisch sind.


Ich habe mich auch über den Unterschied zwischen data.matrix () und as.matrix () gewundert. Vielen Dank, um sie und Ihre Tipps in der Programmierung zu klären.
Mikrobe

Vielen Dank für das Teilen von @Gavin Simpson! Können Sie uns etwas mehr darüber vorstellen, wie Sie von 1-6 zu af zurückkehren können?
YJZ

1
@YZhang Sie müssten die Beschriftungen für jeden Faktor und einen logischen Vektor speichern, der angibt, welche Spalten der Matrix Faktoren waren. Dann wäre es relativ trivial, nur die Spalten, die Faktoren waren, wieder in Faktoren mit den richtigen Bezeichnungen umzuwandeln. Kommentare sind keine guten Stellen für Code. Überprüfen Sie daher, ob das Q zuvor gestellt und beantwortet wurde, und stellen Sie eine neue Frage, wenn dies nicht der Fall ist.
Gavin Simpson

47

@Michal: Matrizen sind nicht wirklich speichereffizienter:

m <- matrix(1:400000, 200000, 2)
d <- data.frame(m)
object.size(m)
# 1600200 bytes
object.size(d)
# 1600776 bytes

... es sei denn, Sie haben eine große Anzahl von Spalten:

m <- matrix(1:400000, 2, 200000)
d <- data.frame(m)
object.size(m)
# 1600200 bytes
object.size(d)
# 22400568 bytes

Beim Argument der Speichereffizienz geht es wirklich darum data.frames, mehr Flexibilität gegenüber Spaltentypen zu bieten. data.frame(a = rnorm(1e6), b = sample(letters, 1e6, TRUE))wird matrixaufgrund von Typenzwang im Speicher viel kleiner sein (6x nach meiner schnellen Berechnung) als die Version.
MichaelChirico

9

Die Matrix ist eigentlich ein Vektor mit zusätzlichen Methoden. während data.frame eine Liste ist. Der Unterschied ist auf Vektor gegen Liste zurückzuführen. Halten Sie sich für die Berechnungseffizienz an die Matrix. Verwenden Sie bei Bedarf data.frame.


3
Hmm, eine Matrix ist ein Vektor mit Dimensionen. Ich sehe nicht, wo Methoden dazu kommen.
Gavin Simpson

0

Matrizen und Datenrahmen sind rechteckige 2D-Arrays und können nach Zeilen und Spalten heterogen sein . Sie teilen einige Methoden und Eigenschaften, aber nicht alle.

Beispiele:

M <- list(3.14,TRUE,5L,c(2,3,5),"dog",1i)  # a list
dim(M) <- c(2,3)                           # set dimensions
print(M)                                   # print result

#      [,1]  [,2]      [,3]
# [1,] 3.14  5         "dog"
# [2,] TRUE  Numeric,3 0+1i

DF <- data.frame(M)                   # a data frame
print(DF)                             # print result

#      X1      X2   X3
#  1 3.14       5  dog
#  2 TRUE 2, 3, 5 0+1i

M <- matrix(c(1,1,1,1,2,3,1,3,6),3)   # a numeric matrix
DF <- data.frame(M)                   # a all numeric data frame

solve(M)                              # obtains inverse matrix
solve(DF)                             # obtains inverse matrix
det(M)                                # obtains determinant
det(DF)                               # error

0

Ich kann den Effizienzunterschied zwischen den beiden nicht mehr betonen! Zwar sind DFs in einigen Fällen, insbesondere bei der Datenanalyse, bequemer, sie ermöglichen jedoch auch heterogene Daten, und einige Bibliotheken akzeptieren sie nur. Diese sind jedoch nur zweitrangig, es sei denn, Sie schreiben einen einmaligen Code für eine bestimmte Aufgabe.

Lassen Sie mich Ihnen ein Beispiel geben. Es gab eine Funktion, die den 2D-Pfad der MCMC-Methode berechnen würde. Grundsätzlich bedeutet dies, dass wir einen Anfangspunkt (x, y) nehmen und einen bestimmten Algorithmus iterieren, um bei jedem Schritt einen neuen Punkt (x, y) zu finden, wobei auf diese Weise der gesamte Pfad konstruiert wird. Der Algorithmus beinhaltet die Berechnung einer recht komplexen Funktion und die Erzeugung einer Zufallsvariablen bei jeder Iteration. Wenn er also 12 Sekunden lang ausgeführt wird, dachte ich, dass es in Ordnung ist, wenn man bedenkt, wie viel Zeug er bei jedem Schritt macht. Davon abgesehen sammelte die Funktion alle Punkte im konstruierten Pfad zusammen mit dem Wert einer Zielfunktion in einem 3-Spalten-Datenrahmen. 3 Spalten sind also nicht so groß, und die Anzahl der Schritte war auch mehr als vernünftig 10.000 (bei dieser Art von Problemen sind Pfade mit einer Länge von 1.000.000 typisch, also sind 10.000 nichts). Also dachte ich ein DF 10, 000x3 ist definitiv kein Problem. Der Grund, warum ein DF verwendet wurde, ist einfach. Nach dem Aufruf der Funktion wurde ggplot () aufgerufen, um den resultierenden (x, y) -Pfad zu zeichnen. Und ggplot () akzeptiert keine Matrix.

Dann entschied ich mich irgendwann aus Neugier, die Funktion zu ändern, um den Pfad in einer Matrix zu sammeln. Gerne ist die Syntax von DFs und Matrizen ähnlich. Ich habe lediglich die Zeile, in der df als data.frame angegeben ist, in eine Zeile geändert, die es als Matrix initialisiert. Hier muss ich auch erwähnen, dass der DF im Anfangscode so initialisiert wurde, dass er die endgültige Größe hat. Später im Code der Funktion wurden nur neue Werte in bereits zugewiesenen Leerzeichen aufgezeichnet, und es gab keinen Aufwand für das Hinzufügen neuer Zeilen zum DF. Dies macht den Vergleich noch fairer und vereinfacht auch meine Arbeit, da ich nichts weiter in der Funktion umschreiben musste. Nur eine Zeile ändert sich von der anfänglichen Zuordnung eines Datenrahmens der erforderlichen Größe zu einer Matrix derselben Größe. Um die neue Version der Funktion an ggplot () anzupassen, habe ich die jetzt zurückgegebene Matrix in Daten konvertiert.

Nachdem ich den Code erneut ausgeführt hatte, konnte ich das Ergebnis nicht glauben. Der Code läuft in Sekundenbruchteilen! Anstelle von ca. 12 Sekunden. Und wieder las und schrieb die Funktion während der 10.000 Iterationen nur Werte für bereits zugewiesene Leerzeichen in einem DF (und jetzt in einer Matrix). Und dieser Unterschied gilt auch für die vernünftige (oder eher kleine) Größe 10000x3.

Wenn Ihr einziger Grund für die Verwendung eines DF darin besteht, ihn mit einer Bibliotheksfunktion wie ggplot () kompatibel zu machen, können Sie ihn jederzeit im letzten Moment in einen DF konvertieren - arbeiten Sie mit Matrizen, so weit Sie möchten. Wenn es andererseits einen wesentlicheren Grund für die Verwendung eines DF gibt, z. B. wenn Sie ein Datenanalysepaket verwenden, das ansonsten eine konstante Transformation von Matrizen zu DFs und zurück erfordern würde, oder wenn Sie selbst keine intensiven Berechnungen durchführen und nur Standard verwenden Pakete (viele von ihnen wandeln einen DF tatsächlich intern in eine Matrix um, erledigen ihre Arbeit und wandeln dann das Ergebnis zurück - damit sie alle Effizienzarbeiten für Sie erledigen) oder erledigen einen einmaligen Job, damit Sie sich nicht darum kümmern und sich nicht so fühlen Wenn Sie sich mit DFs wohler fühlen, sollten Sie sich keine Sorgen um die Effizienz machen.

Oder eine andere, praktischere Regel: Wenn Sie eine Frage wie im OP haben, verwenden Sie Matrizen, sodass Sie DFs nur verwenden würden, wenn Sie keine solche Frage haben (weil Sie bereits wissen, dass Sie DFs verwenden müssen, oder weil Sie dies tun nicht wirklich wichtig, da der Code einmalig ist usw.).

Im Allgemeinen sollte dieser Effizienzpunkt jedoch immer im Vordergrund stehen.

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.