tidyr関数はdata.table機能では機能しないようです。 たとえば、大きなdata.tableの欠落している値を次のように埋めたいと思います。
#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))]
ただし、上記のコードは次のエラーをスローします。
# > 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')"
各列にfill()
を順番に適用してもその場で変更されないため、以下の方法は大きなdata.tablesの場合はコストがかかります。
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
# >
ご覧いただきありがとうございます!
これを行うためのプルリクエストを確認したいと思いますが、自分でそれを行う時間(またはdata.tableの知識)がありません。
@mindymallory 、あなたが説明することは、 tidyr
関数または実装する新機能の問題ではありません。 むしろ、 tidyr
関数をdata.table
でどのように使用するかが問題になります。
dt[, year := fill(year)]
行ったテストにはほとんどエラーがありません
fill
は2つの引数を取り、最初にデータ(data.frame、data.table、またはtbl)、次に裸の列名を取ります。 テストでは、最初の引数として列名を指定するため、 fill
はdata.table
とは独立して機能しません。fill
は指定した列を返しませんが、 fill
を適用したすべてのデータを返します。 これが、 year
をdt[, year := fill(year)]
のfill
関数の結果に置き換えることができない理由です。 LHS:=RHS
場合、 RHS
は置換値のベクトルである必要がありますが、 year := fill(year)
場合はそうではありません。したがって、試したコードには、 data.table
とのtidyr
互換性とは関係なく、これらの問題があります。
data.table
内でfill
を使用するいくつかの方法があります。 他のユーザーにも役立つ可能性があります。
library(data.table)
library(tidyr)
dt <- data.table(
year = c(2015, NA, NA, NA),
trt = c("A", NA, "B", NA)
)
tracemem(dt)
#> [1] "<0000000019B796C8>"
fill
を使用する場合は、最初にデータを指定し、次に列を指定する必要があります。 data.table
、そのために.SD
を使用し、 fill
がdt
すべての列を返すことを確認します。
dt[, fill(.SD, year)]
#> year trt
#> 1: 2015 A
#> 2: 2015 NA
#> 3: 2015 B
#> 4: 2015 NA
次に、たとえば$
列を選択すると、ベクトルが返されます。
dt[, fill(.SD, year)$year]
#> [1] 2015 2015 2015 2015
埋める列を複数指定すると、これらの列が埋められて返されます。
dt[, fill(.SD, year, trt)]
#> year trt
#> 1: 2015 A
#> 2: 2015 A
#> 3: 2015 B
#> 4: 2015 B
したがって、 fill
を適用して、 data.table
内の列を置き換える方法を説明します。
必要なベクターを抽出して、 :=
を使用できます。 そして、他の列のためにそれをもう一度やりなさい。
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
data.table
構文を使用して、変更を一度に適用することもできます。
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
ただし、 fill
はdata
引数のすべての列を返すため、 $
列を抽出せずに実行できます。
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
最後に、プログラミングにより適したアプローチを使用できます。
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
この方法を使用すると、列のサブセットにfill
簡単に適用できることに注意してください
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
これがあなたの質問とあなたが望む機能要求に答えることを願っています。 data.table
構文と概念が正しく使用されているため、コピーがなく、 tidyr
がdata.table
概念と互換性があることを示すために、 tracemem
を使用していることに注意してください。
@hadley 、このテーマについてレビューするPRはないと思います。
@cdervこの詳細な説明をありがとう! あなたは私にたくさんのメモリ使用量を節約しました!
最も参考になるコメント
@mindymallory 、あなたが説明することは、
tidyr
関数または実装する新機能の問題ではありません。 むしろ、tidyr
関数をdata.table
でどのように使用するかが問題になります。dt[, year := fill(year)]
行ったテストにはほとんどエラーがありませんfill
は2つの引数を取り、最初にデータ(data.frame、data.table、またはtbl)、次に裸の列名を取ります。 テストでは、最初の引数として列名を指定するため、fill
はdata.table
とは独立して機能しません。fill
は指定した列を返しませんが、fill
を適用したすべてのデータを返します。 これが、year
をdt[, year := fill(year)]
のfill
関数の結果に置き換えることができない理由です。LHS:=RHS
場合、RHS
は置換値のベクトルである必要がありますが、year := fill(year)
場合はそうではありません。したがって、試したコードには、
data.table
とのtidyr
互換性とは関係なく、これらの問題があります。data.table
内でfill
を使用するいくつかの方法があります。 他のユーザーにも役立つ可能性があります。fill
を使用する場合は、最初にデータを指定し、次に列を指定する必要があります。data.table
、そのために.SD
を使用し、fill
がdt
すべての列を返すことを確認します。次に、たとえば
$
列を選択すると、ベクトルが返されます。埋める列を複数指定すると、これらの列が埋められて返されます。
したがって、
fill
を適用して、data.table
内の列を置き換える方法を説明します。必要なベクターを抽出して、
:=
を使用できます。 そして、他の列のためにそれをもう一度やりなさい。data.table
構文を使用して、変更を一度に適用することもできます。ただし、
fill
はdata
引数のすべての列を返すため、$
列を抽出せずに実行できます。最後に、プログラミングにより適したアプローチを使用できます。
この方法を使用すると、列のサブセットに
fill
簡単に適用できることに注意してくださいこれがあなたの質問とあなたが望む機能要求に答えることを願っています。
data.table
構文と概念が正しく使用されているため、コピーがなく、tidyr
がdata.table
概念と互換性があることを示すために、tracemem
を使用していることに注意してください。@hadley 、このテーマについてレビューするPRはないと思います。