Ich möchte einen Datenrahmen zeilenweise in R erstellen. Ich habe einige Suchvorgänge durchgeführt, und alles, was ich mir ausgedacht habe, ist der Vorschlag, eine leere Liste zu erstellen, einen Listenindexskalar beizubehalten und dann jedes Mal zur Liste hinzuzufügen einen einzeiligen Datenrahmen und erweitern Sie den Listenindex um eins. Schließlich do.call(rbind,)
auf der Liste.
Während dies funktioniert, scheint es sehr umständlich. Gibt es nicht einen einfacheren Weg, um dasselbe Ziel zu erreichen?
Offensichtlich beziehe ich mich auf Fälle, in denen ich eine apply
Funktion nicht verwenden kann und den Datenrahmen explizit zeilenweise erstellen muss. Gibt es zumindest eine Möglichkeit, bis push
zum Ende einer Liste zu gelangen, anstatt den zuletzt verwendeten Index explizit zu verfolgen?
append()
[was wahrscheinlich als Einfügen bezeichnet werden sollte] verwenden oderc()
Elemente am Ende einer Liste hinzufügen, was Ihnen hier jedoch nicht weiterhilft.lapply()
,Map()
und so weiter, aber Sie können auch einen Blick zu nehmenaggregate()
,dapply() {heR.Misc}
undcast() {reshape}
zu sehen , ob Ihre Aufgaben nicht durch diese behandelt werden können Funktionen (diese geben alle Datenrahmen zurück).Antworten:
Sie können sie zeilenweise erweitern, indem Sie sie anhängen oder verwenden
rbind()
.Das heißt nicht, dass du es solltest. Dynamisch wachsende Strukturen sind eine der am wenigsten effizienten Methoden zum Codieren in R.
Wenn Sie können, ordnen Sie Ihren gesamten data.frame im Voraus zu:
und fügen Sie dann während Ihrer Operationen jeweils eine Zeile ein
Das sollte für beliebige data.frame funktionieren und viel effizienter sein. Wenn Sie N überschritten haben, können Sie am Ende immer leere Zeilen verkleinern.
quelle
data.table
scheint sogar schneller zu sein als die Vorabzuweisung mit data.frames. Testen hier: stackoverflow.com/a/11486400/636656Man kann Zeilen hinzufügen zu
NULL
:zum Beispiel
quelle
sapply
transponieren (oder zu vektorisieren).Dies ist ein dummes Beispiel für die Verwendung
do.call(rbind,)
auf der Ausgabe vonMap()
[ähnlich wielapply()
]Ich benutze dieses Konstrukt ziemlich oft.
quelle
Der Grund, warum ich Rcpp so sehr mag, ist, dass ich nicht immer verstehe, wie R Core denkt, und mit Rcpp muss ich das meistens nicht.
Jeder Wert philosophisch gesprochen, du ist in einem Zustand der Sünde in Bezug auf das funktionale Paradigma, das, um sicherzustellen versucht , erscheint unabhängig von jedem anderen Wert; Das Ändern eines Werts sollte niemals zu einer sichtbaren Änderung eines anderen Werts führen, wie dies bei Zeigern der Fall ist, die die Darstellung in C teilen.
Die Probleme entstehen, wenn die funktionale Programmierung dem kleinen Fahrzeug signalisiert, sich aus dem Weg zu räumen, und das kleine Fahrzeug antwortet: "Ich bin ein Leuchtturm". Wenn Sie eine lange Reihe kleiner Änderungen an einem großen Objekt vornehmen, das Sie in der Zwischenzeit bearbeiten möchten, befinden Sie sich auf dem Gebiet des Leuchtturms.
In der C ++ STL
push_back()
ist eine Lebensweise. Es versucht nicht, funktionsfähig zu sein, aber es versucht, gängige Programmiersprachen effizient zu berücksichtigen .Mit etwas Klugheit hinter den Kulissen kann man manchmal arrangieren, einen Fuß in jeder Welt zu haben. Snapshot-basierte Dateisysteme sind ein gutes Beispiel (das sich aus Konzepten wie Union Mounts entwickelt hat, die auch beide Seiten bedienen).
Wenn R Core dies tun wollte, könnte der zugrunde liegende Vektorspeicher wie ein Union Mount funktionieren. Ein Verweis auf den Vektorspeicher ist möglicherweise für Indizes gültig
1:N
, während ein anderer Verweis auf denselben Speicher für Indizes gültig ist1:(N+1)
. Es könnte reservierten Speicher geben, auf den noch nichts anderes verweist, als es für einen schnellen Zweck geeignet istpush_back()
. Sie verstoßen nicht gegen das Funktionskonzept, wenn Sie außerhalb des Bereichs anhängen, den eine vorhandene Referenz für gültig hält.Wenn Sie Zeilen schrittweise anhängen, geht Ihnen der reservierte Speicherplatz aus. Sie müssen von allem neue Kopien erstellen, wobei der Speicher mit einem gewissen Inkrement multipliziert wird. Die von mir verwendeten STL-Implementierungen multiplizieren den Speicher bei Erweiterung der Zuordnung in der Regel mit 2. Ich dachte, ich hätte in R Internals gelesen, dass es eine Speicherstruktur gibt, in der der Speicher um 20% erhöht wird. In beiden Fällen erfolgen Wachstumsoperationen mit logarithmischer Häufigkeit im Verhältnis zur Gesamtzahl der angehängten Elemente. Amortisiert ist dies normalerweise akzeptabel.
Als Tricks hinter den Kulissen gehen, habe ich Schlimmeres gesehen. Jedes Mal, wenn Sie
push_back()
eine neue Zeile in den Datenrahmen einfügen, muss eine Indexstruktur der obersten Ebene kopiert werden. Die neue Zeile kann an eine gemeinsame Darstellung angehängt werden, ohne dass alte Funktionswerte beeinträchtigt werden. Ich glaube nicht einmal, dass dies den Müllsammler sehr erschweren würde. da ich nicht vorschlage, dasspush_front()
alle Referenzen Präfixreferenzen auf der Vorderseite des zugewiesenen Vektorspeichers sind.quelle
Dirk Eddelbuettels Antwort ist die beste; Hier stelle ich nur fest, dass Sie es vermeiden können, die Datenrahmenabmessungen oder Datentypen nicht vorab anzugeben. Dies ist manchmal nützlich, wenn Sie mehrere Datentypen und viele Spalten haben:
quelle
df<-rbind(df, row2)
?Ich habe diesen Weg gefunden, um Datenrahmen durch Rohdaten ohne Matrix zu erstellen.
Mit automatischem Spaltennamen
Mit Spaltenname
quelle
Wenn Sie Vektoren haben, die zu Zeilen werden sollen, verketten Sie sie mit
c()
, übergeben Sie sie zeilenweise an eine Matrix und konvertieren Sie diese Matrix in einen Datenrahmen.Zum Beispiel Zeilen
kann folgendermaßen in einen Datenrahmen konvertiert werden:
Zugegeben, ich sehe zwei Hauptbeschränkungen: (1) Dies funktioniert nur mit Single-Mode-Daten, und (2) Sie müssen Ihre letzten # Spalten kennen, damit dies funktioniert (dh ich gehe davon aus, dass Sie nicht mit a arbeiten zerlumptes Array, dessen größte Zeilenlänge a priori unbekannt ist ).
Diese Lösung scheint einfach zu sein, aber aufgrund meiner Erfahrung mit Typkonvertierungen in R bin ich sicher, dass sie später neue Herausforderungen mit sich bringt. Kann jemand dies kommentieren?
quelle
Abhängig vom Format Ihrer neuen Zeile können Sie diese verwenden,
tibble::add_row
wenn Ihre neue Zeile einfach ist und in "Wertepaaren" angegeben werden kann. Oder Sie könntendplyr::bind_rows
"eine effiziente Implementierung des allgemeinen Musters von do.call (rbind, dfs)" verwenden.quelle