Die Aufräumfunktionen scheinen nicht mit der data.table-Funktionalität zu funktionieren. Zum Beispiel möchte ich fehlende Werte einer großen data.table wie folgt auffüllen:
#install.packages("data.table")
#install.packages("tidyr")
library(data.table)
library(tidyr)
dt <- data.table(
year = c(2015, NA, NA, NA),
trt = c("A", NA, "B", NA)
)
dt[, year := fill(year)]
dt[, c("year", "trt") := .(fill(year), fill(trt))]
aber der obige Code wirft den folgenden Fehler aus:
# > dt[, year := fill(year)]
# Error in UseMethod("fill_") :
# no applicable method for 'fill_' applied to an object of class "c('double', 'numeric')"
# > dt[, c("year", "trt") := .(fill(year), fill(trt))]
# Error in UseMethod("fill_") :
# no applicable method for 'fill_' applied to an object of class "c('double', 'numeric')"
Da das sequentielle Anwenden von fill()
auf jede Spalte keine Änderung an der Stelle bewirkt, ist die folgende Methode für große Datentabellen kostspielig.
rm(dt)
dt <- data.table(
year = c(2015, NA, NA, NA),
trt = c("A", NA, "B", NA)
)
tracemem(dt)
dt <- fill(dt, year)
dt <- fill(dt, trt)
# > rm(dt)
# > dt <- data.table(
# + year = c(2015, NA, NA, NA),
# + trt = c("A", NA, "B", NA)
# + )
# > tracemem(dt)
# [1] "<00000000088F6118>"
# > dt <- fill(dt, year)
# tracemem[0x00000000088f6118 -> 0x00000000092d8c50]: fill_.data.frame fill_ fill
# tracemem[0x00000000092d8c50 -> 0x00000000092d8b00]: [[<-.data.frame [[<- fill_.data.frame fill_ fill
# tracemem[0x00000000092d8b00 -> 0x00000000092d8ac8]: [[<-.data.frame [[<- fill_.data.frame fill_ fill
# > dt <- fill(dt, trt)
# tracemem[0x00000000092d8ac8 -> 0x000000000951f1c0]: fill_.data.frame fill_ fill
# tracemem[0x000000000951f1c0 -> 0x000000000951f0a8]: [[<-.data.frame [[<- fill_.data.frame fill_ fill
# tracemem[0x000000000951f0a8 -> 0x000000000951f070]: [[<-.data.frame [[<- fill_.data.frame fill_ fill
# >
Danke fürs reinschauen!
Ich wäre bereit, Pull-Requests zu überprüfen, um dies zu tun, aber ich habe nicht die Zeit (oder das Wissen über data.table), um dies selbst zu tun.
@mindymallory , Was Sie beschreiben, ist kein Problem mit der Funktion tidyr
oder einer neuen zu implementierenden Funktion. Es kommt vielmehr darauf an, wie Sie tidyr
Funktionen mit data.table
.
Bei den Tests, die Sie mit dt[, year := fill(year)]
durchgeführt haben, sind nur wenige Fehler
fill
2 Argumente, zuerst ein data (data.frame, data.table oder tbl) und dann einen bloßen Spaltennamen. In Ihrem Test geben Sie den Spaltennamen als erstes Argument an, damit fill
nicht unabhängig von data.table
funktioniert.fill
nicht die von Ihnen angegebene Spalte zurück, sondern alle Daten, auf die Sie fill
angewendet haben. Aus diesem Grund können Sie year
durch das Ergebnis der Funktion fill
in dt[, year := fill(year)]
ersetzen. Bei LHS:=RHS
muss RHS
ein Vektor von Ersatzwerten sein, was bei year := fill(year)
nicht der Fall ist.Der Code, den Sie ausprobiert haben, hat diese Probleme unabhängig von der Kompatibilität von tidyr
mit data.table
.
Hier sind einige Möglichkeiten, fill
innerhalb von data.table
. Es könnte auch anderen Benutzern helfen.
library(data.table)
library(tidyr)
dt <- data.table(
year = c(2015, NA, NA, NA),
trt = c("A", NA, "B", NA)
)
tracemem(dt)
#> [1] "<0000000019B796C8>"
Wenn Sie fill
möchten, müssen Sie zuerst Daten und dann eine Spalte angeben. Verwenden Sie in einem data.table
.SD
und sehen Sie, dass fill
alle Spalten von dt
return
dt[, fill(.SD, year)]
#> year trt
#> 1: 2015 A
#> 2: 2015 NA
#> 3: 2015 B
#> 4: 2015 NA
Sie können dann beispielsweise eine Spalte mit $
auswählen, die einen Vektor zurückgibt.
dt[, fill(.SD, year)$year]
#> [1] 2015 2015 2015 2015
Wenn Sie mehrere Spalten zum Füllen angeben, werden diese Spalten gefüllt zurückgegeben.
dt[, fill(.SD, year, trt)]
#> year trt
#> 1: 2015 A
#> 2: 2015 A
#> 3: 2015 B
#> 4: 2015 B
Also, wie wenden Sie fill
an, um Spalten in einem data.table
zu ersetzen.
Sie könnten den gewünschten Vektor extrahieren und :=
. Und wiederholen Sie es für die andere Spalte.
dt[, year := fill(.SD, year)$year]
dt
#> year trt
#> 1: 2015 A
#> 2: 2015 NA
#> 3: 2015 B
#> 4: 2015 NA
dt[, trt := fill(.SD, trt)$trt]
dt
#> year trt
#> 1: 2015 A
#> 2: 2015 A
#> 3: 2015 B
#> 4: 2015 B
Sie können die Änderung auch sofort mit der Syntax data.table
anwenden.
dt <- data.table(
year = c(2015, NA, NA, NA),
trt = c("A", NA, "B", NA)
)
tracemem(dt)
#> [1] "<0000000006104428>"
dt[, c("year", "trt") := .(fill(.SD, year)$year, fill(.SD, trt)$trt)]
dt
#> year trt
#> 1: 2015 A
#> 2: 2015 A
#> 3: 2015 B
#> 4: 2015 B
Da fill
jedoch alle Spalten des Arguments data
zurückgibt, können Sie auf das Extrahieren der Spalte mit $
dt <- data.table(
year = c(2015, NA, NA, NA),
trt = c("A", NA, "B", NA)
)
tracemem(dt)
#> [1] "<0000000005B57B98>"
dt[, c("year", "trt") := fill(.SD, year, trt)]
dt
#> year trt
#> 1: 2015 A
#> 2: 2015 A
#> 3: 2015 B
#> 4: 2015 B
Schließlich könnten Sie einen Ansatz verwenden, der besser für die Programmierung geeignet ist.
dt <- data.table(
year = c(2015, NA, NA, NA),
trt = c("A", NA, "B", NA)
)
tracemem(dt)
#> [1] "<00000000187CF230>"
cols <- c("year", "trt")
dt
#> year trt
#> 1: 2015 A
#> 2: NA NA
#> 3: NA B
#> 4: NA NA
dt[, (cols) := fill_(.SD, cols), .SDcols = cols]
dt
#> year trt
#> 1: 2015 A
#> 2: 2015 A
#> 3: 2015 B
#> 4: 2015 B
Beachten Sie, dass Sie auf diese Weise fill
leicht auf eine Teilmenge von Spalten anwenden können
dt <- data.table(
year = c(2015, NA, NA, NA),
trt = c("A", NA, "B", NA),
trt2 = c(NA, "C", NA, "D")
)
tracemem(dt)
#> [1] "<00000000049EFD30>"
cols <- c("year", "trt")
dt
#> year trt trt2
#> 1: 2015 A NA
#> 2: NA NA C
#> 3: NA B NA
#> 4: NA NA D
dt[, (cols) := fill_(.SD, cols), .SDcols = cols]
dt
#> year trt trt2
#> 1: 2015 A NA
#> 2: 2015 A C
#> 3: 2015 B NA
#> 4: 2015 B D
Ich hoffe, dies beantwortet Ihre Frage und die gewünschte Funktionsanforderung. Beachten Sie, dass ich tracemem
zu zeigen, dass es keine Kopien gibt und dass tidyr
mit dem data.table
Konzept kompatibel ist, da die Syntax und das Konzept von data.table
korrekt verwendet werden.
@hadley , ich denke, Sie haben keine PR zu diesem Thema.
@cderv Danke für diese ausführliche Erklärung! Sie haben mir viel Speicher gespart!
Hilfreichster Kommentar
@mindymallory , Was Sie beschreiben, ist kein Problem mit der Funktion
tidyr
oder einer neuen zu implementierenden Funktion. Es kommt vielmehr darauf an, wie Sietidyr
Funktionen mitdata.table
.Bei den Tests, die Sie mit
dt[, year := fill(year)]
durchgeführt haben, sind nur wenige Fehlerfill
2 Argumente, zuerst ein data (data.frame, data.table oder tbl) und dann einen bloßen Spaltennamen. In Ihrem Test geben Sie den Spaltennamen als erstes Argument an, damitfill
nicht unabhängig vondata.table
funktioniert.fill
nicht die von Ihnen angegebene Spalte zurück, sondern alle Daten, auf die Siefill
angewendet haben. Aus diesem Grund können Sieyear
durch das Ergebnis der Funktionfill
indt[, year := fill(year)]
ersetzen. BeiLHS:=RHS
mussRHS
ein Vektor von Ersatzwerten sein, was beiyear := fill(year)
nicht der Fall ist.Der Code, den Sie ausprobiert haben, hat diese Probleme unabhängig von der Kompatibilität von
tidyr
mitdata.table
.Hier sind einige Möglichkeiten,
fill
innerhalb vondata.table
. Es könnte auch anderen Benutzern helfen.Wenn Sie
fill
möchten, müssen Sie zuerst Daten und dann eine Spalte angeben. Verwenden Sie in einemdata.table
.SD
und sehen Sie, dassfill
alle Spalten vondt
returnSie können dann beispielsweise eine Spalte mit
$
auswählen, die einen Vektor zurückgibt.Wenn Sie mehrere Spalten zum Füllen angeben, werden diese Spalten gefüllt zurückgegeben.
Also, wie wenden Sie
fill
an, um Spalten in einemdata.table
zu ersetzen.Sie könnten den gewünschten Vektor extrahieren und
:=
. Und wiederholen Sie es für die andere Spalte.Sie können die Änderung auch sofort mit der Syntax
data.table
anwenden.Da
fill
jedoch alle Spalten des Argumentsdata
zurückgibt, können Sie auf das Extrahieren der Spalte mit$
Schließlich könnten Sie einen Ansatz verwenden, der besser für die Programmierung geeignet ist.
Beachten Sie, dass Sie auf diese Weise
fill
leicht auf eine Teilmenge von Spalten anwenden könnenIch hoffe, dies beantwortet Ihre Frage und die gewünschte Funktionsanforderung. Beachten Sie, dass ich
tracemem
zu zeigen, dass es keine Kopien gibt und dasstidyr
mit demdata.table
Konzept kompatibel ist, da die Syntax und das Konzept vondata.table
korrekt verwendet werden.@hadley , ich denke, Sie haben keine PR zu diesem Thema.