Meine Frage bezieht sich auf die Zuweisung durch Referenz oder das Kopieren in data.table
. Ich möchte wissen, ob man Zeilen durch Referenz löschen kann, ähnlich wie
DT[ , someCol := NULL]
Ich möchte es wissen
DT[someRow := NULL, ]
Ich denke, es gibt einen guten Grund, warum diese Funktion nicht existiert. Vielleicht können Sie einfach eine gute Alternative zum üblichen Kopieransatz aufzeigen, wie unten. Insbesondere mit meinem Favoriten aus Beispiel (data.table),
DT = data.table(x = rep(c("a", "b", "c"), each = 3), y = c(1, 3, 6), v = 1:9)
# x y v
# [1,] a 1 1
# [2,] a 3 2
# [3,] a 6 3
# [4,] b 1 4
# [5,] b 3 5
# [6,] b 6 6
# [7,] c 1 7
# [8,] c 3 8
# [9,] c 6 9
Angenommen, ich möchte die erste Zeile aus dieser Datentabelle löschen. Ich weiß, ich kann dies tun:
DT <- DT[-1, ]
aber oft möchten wir das vermeiden, weil wir das Objekt kopieren (und das erfordert ungefähr 3 * N Speicher, wenn N object.size(DT)
, wie hier ausgeführt . Jetzt habe ich gefunden set(DT, i, j, value)
. Ich weiß, wie man bestimmte Werte setzt (wie hier: setze alle Werte in den Zeilen 1 und 2 und den Spalten 2 und 3 bis Null)
set(DT, 1:2, 2:3, 0)
DT
# x y v
# [1,] a 0 0
# [2,] a 0 0
# [3,] a 6 3
# [4,] b 1 4
# [5,] b 3 5
# [6,] b 6 6
# [7,] c 1 7
# [8,] c 3 8
# [9,] c 6 9
Aber wie kann ich beispielsweise die ersten beiden Zeilen löschen? Tun
set(DT, 1:2, 1:3, NULL)
setzt den gesamten DT auf NULL.
Meine SQL-Kenntnisse sind sehr begrenzt, also sagt ihr mir: Wenn data.table SQL-Technologie verwendet, gibt es eine Entsprechung zum SQL-Befehl
DELETE FROM table_name
WHERE some_column=some_value
in data.table?
quelle
data.table()
SQL-Technologie so sehr verwendet wird, als dass man eine Parallele zwischen den verschiedenen Operationen in SQL und den verschiedenen Argumenten zu a ziehen kanndata.table
. Für mich impliziert der Verweis auf "Technologie" etwas, dass erdata.table
irgendwo auf einer SQL-Datenbank sitzt, was AFAIK nicht der Fall ist.DT[ , keep := .I > 1]
dann eine Teilmenge für spätere Operationen:DT[(keep), ...]
vielleicht sogarsetindex(DT, keep)
die Geschwindigkeit dieser Teilmenge. Kein Allheilmittel, aber es lohnt sich, es als Design-Wahl in Ihrem Workflow zu betrachten. Möchten Sie wirklich alle diese Zeilen aus dem Speicher löschen oder möchten Sie sie lieber ausschließen? Die Antwort unterscheidet sich je nach Anwendungsfall.Antworten:
Gute Frage.
data.table
Zeilen können noch nicht als Referenz gelöscht werden.data.table
kann Spalten als Referenz hinzufügen und löschen , da der Vektor der Spaltenzeiger bekanntlich überbelegt wird. Der Plan ist, etwas Ähnliches für Zeilen zu tun und schnellinsert
und schnell zuzulassendelete
. Ein Zeilenlöschvorgang würdememmove
in C verwendet, um die Elemente (in jeder einzelnen Spalte) nach den gelöschten Zeilen zu verschieben. Das Löschen einer Zeile in der Mitte der Tabelle wäre im Vergleich zu einer Zeilenspeicherdatenbank wie SQL, die sich besser zum schnellen Einfügen und Löschen von Zeilen eignet, wo immer sich diese Zeilen in der Tabelle befinden, immer noch recht ineffizient. Trotzdem wäre es viel schneller als das Kopieren eines neuen großen Objekts ohne die gelöschten Zeilen.Da andererseits Spaltenvektoren überbelegt würden, könnten Zeilen am Ende sofort eingefügt (und gelöscht) werden . zB eine wachsende Zeitreihe.
Es wurde als Problem abgelegt: Löschen Sie Zeilen als Referenz .
quelle
fread
zuerst fertig werden . Danach ist es ziemlich hoch.DT[b<8 & a>3]
gibt eine neue data.table zurück. Wir möchten hinzufügendelete(DT, b>=8 | a<=3)
undDT[b>=8 | a<=8, .ROW:=NULL]
. Der Vorteil der letzteren würde mit anderen Merkmalen kombiniert werden ,[]
wie beispielsweise die Zeilennummern ini
, verbinden sie ini
undroll
profitiert von der[i,j,by]
Optimierung.Der Ansatz, den ich gewählt habe, um die Verwendung des Speichers ähnlich wie das Löschen an Ort und Stelle zu machen, besteht darin, jeweils eine Spalte zu unterteilen und zu löschen. Nicht so schnell wie eine richtige C-Memmove-Lösung, aber die Speichernutzung ist alles, was mich hier interessiert. etwas wie das:
quelle
memmove
s sein, um die Lücken zu schließen, aber das ist in Ordnung.DT[, col:= NULL, with = F]
inset(DT, NULL, col, NULL)
Hier ist eine Arbeitsfunktion, die auf der Antwort von @ vc273 und dem Feedback von @ Frank basiert.
Und ein Beispiel für seine Verwendung:
Wobei "dat" eine Datentabelle ist. Das Entfernen von 14.000 Zeilen aus 1,4 Millionen Zeilen dauert auf meinem Laptop 0,25 Sekunden.
PS. Da ich neu bei SO bin, konnte ich dem Thread von @ vc273 keinen Kommentar hinzufügen :-(
quelle
Versuchen Sie stattdessen oder versuchen Sie, auf NULL zu setzen, auf NA (passend zum NA-Typ für die erste Spalte).
quelle
Das Thema ist immer noch interessant für viele Leute (ich eingeschlossen).
Was ist damit? Ich habe
assign
denglovalenv
und den zuvor beschriebenen Code ersetzt. Es wäre besser, die ursprüngliche Umgebung zu erfassen, aber zumindestglobalenv
ist sie speichereffizient und wirkt wie eine Änderung durch ref.quelle
address(DT); delete(DT, 3); address(DT)
) gelöscht , obwohl es in gewissem Sinne effizient sein kann.Hier sind einige Strategien, die ich verwendet habe. Ich glaube, dass eine .ROW-Funktion kommen könnte. Keiner dieser folgenden Ansätze ist schnell. Dies sind einige Strategien, die etwas über Teilmengen oder Filterung hinausgehen. Ich habe versucht, wie dba zu denken, nur um Daten zu bereinigen. Wie oben erwähnt, können Sie Zeilen in data.table auswählen oder entfernen:
Hinweis: .SD erstellt eine Teilmenge der Originaldaten und ermöglicht es Ihnen, in j oder nachfolgenden Datentabellen eine Menge Arbeit zu erledigen. Siehe https://stackoverflow.com/a/47406952/305675 . Hier habe ich meine Iris nach Sepal Länge bestellt, mindestens eine bestimmte Sepal.Länge genommen, die drei besten (nach Sepal Länge) aller Arten ausgewählt und alle zugehörigen Daten zurückgegeben:
Die Ansätze ordnen vor allem eine Datentabelle beim Entfernen von Zeilen nacheinander neu an. Sie können eine data.table transponieren und die alten Zeilen entfernen oder ersetzen, die jetzt transponierte Spalten sind. Wenn Sie mit ': = NULL' eine transponierte Zeile entfernen, wird auch der nachfolgende Spaltenname entfernt:
Wenn Sie den data.frame zurück in eine data.table transponieren, möchten Sie möglicherweise die ursprüngliche data.table umbenennen und beim Löschen die Klassenattribute wiederherstellen. Durch Anwenden von ": = NULL" auf eine jetzt transponierte Datentabelle werden alle Zeichenklassen erstellt.
Möglicherweise möchten Sie nur doppelte Zeilen entfernen, die Sie mit oder ohne Schlüssel ausführen können:
Es ist auch möglich, einen inkrementellen Zähler mit '.I' hinzuzufügen. Sie können dann nach doppelten Schlüsseln oder Feldern suchen und diese entfernen, indem Sie den Datensatz mit dem Zähler entfernen. Dies ist rechenintensiv, hat jedoch einige Vorteile, da Sie die zu entfernenden Zeilen drucken können.
Sie können auch einfach eine Zeile mit Nullen oder NAs füllen und diese dann mit einer i-Abfrage löschen:
quelle
t
eines data.frame ist normalerweise keine gute Idee. Überprüfen Siestr(m_iris)
, ob alle Daten zu Zeichenfolgen / Zeichen geworden sind. Übrigens können Sie auch Zeilennummern abrufen,d_iris[duplicated(Key), which = TRUE]
indem Sie eine Zählerspalte erstellen.