はい、オブジェクト全体のコピーを作成するのは、Rでのサブ割り当て<-
(または=
or ->
)です。以下のように、とを使用してトレースできます。機能とそれらが渡されたどんなオブジェクトへの参照によって割り当てます。したがって、そのオブジェクトが以前に(サブ割り当てまたは明示的なによって)コピーされている場合、参照によって変更されるのはそのコピーです。tracemem(DT)
.Internal(inspect(DT))
data.table
:=
set()
<-
copy(DT)
DT <- data.table(a = c(1, 2), b = c(11, 12))
newDT <- DT
.Internal(inspect(DT))
# @0000000003B7E2A0 19 VECSXP g0c7 [OBJ,NAM(2),ATT] (len=2, tl=100)
# @00000000040C2288 14 REALSXP g0c2 [NAM(2)] (len=2, tl=0) 1,2
# @00000000040C2250 14 REALSXP g0c2 [NAM(2)] (len=2, tl=0) 11,12
# ATTRIB: # ..snip..
.Internal(inspect(newDT)) # precisely the same object at this point
# @0000000003B7E2A0 19 VECSXP g0c7 [OBJ,NAM(2),ATT] (len=2, tl=100)
# @00000000040C2288 14 REALSXP g0c2 [NAM(2)] (len=2, tl=0) 1,2
# @00000000040C2250 14 REALSXP g0c2 [NAM(2)] (len=2, tl=0) 11,12
# ATTRIB: # ..snip..
tracemem(newDT)
# [1] "<0x0000000003b7e2a0"
newDT$b[2] <- 200
# tracemem[0000000003B7E2A0 -> 00000000040ED948]:
# tracemem[00000000040ED948 -> 00000000040ED830]: .Call copy $<-.data.table $<-
.Internal(inspect(DT))
# @0000000003B7E2A0 19 VECSXP g0c7 [OBJ,NAM(2),TR,ATT] (len=2, tl=100)
# @00000000040C2288 14 REALSXP g0c2 [NAM(2)] (len=2, tl=0) 1,2
# @00000000040C2250 14 REALSXP g0c2 [NAM(2)] (len=2, tl=0) 11,12
# ATTRIB: # ..snip..
.Internal(inspect(newDT))
# @0000000003D97A58 19 VECSXP g0c7 [OBJ,NAM(2),ATT] (len=2, tl=100)
# @00000000040ED7F8 14 REALSXP g0c2 [NAM(2)] (len=2, tl=0) 1,2
# @00000000040ED8D8 14 REALSXP g0c2 [NAM(2)] (len=2, tl=0) 11,200
# ATTRIB: # ..snip..
変更されa
ていa
なくても、ベクターがコピーされた(16進数の値はベクターの新しいコピーを示す)ことに注意してください。b
変更が必要な要素を変更するだけでなく、全体がコピーされました。これは、大きなデータの場合は避けることが重要であり、その理由:=
とset()
はに導入されましたdata.table
。
これで、コピーしたものnewDT
を参照で変更できます。
newDT
# a b
# [1,] 1 11
# [2,] 2 200
newDT[2, b := 400]
# a b # See FAQ 2.21 for why this prints newDT
# [1,] 1 11
# [2,] 2 400
.Internal(inspect(newDT))
# @0000000003D97A58 19 VECSXP g0c7 [OBJ,NAM(2),ATT] (len=2, tl=100)
# @00000000040ED7F8 14 REALSXP g0c2 [NAM(2)] (len=2, tl=0) 1,2
# @00000000040ED8D8 14 REALSXP g0c2 [NAM(2)] (len=2, tl=0) 11,400
# ATTRIB: # ..snip ..
3つの16進数値(列ポイントのベクトル、および2つの列のそれぞれ)は変更されないことに注意してください。そのため、まったくコピーがなく、参照によって本当に変更されました。
または、DT
参照によってオリジナルを変更できます。
DT[2, b := 600]
# a b
# [1,] 1 11
# [2,] 2 600
.Internal(inspect(DT))
# @0000000003B7E2A0 19 VECSXP g0c7 [OBJ,NAM(2),ATT] (len=2, tl=100)
# @00000000040C2288 14 REALSXP g0c2 [NAM(2)] (len=2, tl=0) 1,2
# @00000000040C2250 14 REALSXP g0c2 [NAM(2)] (len=2, tl=0) 11,600
# ATTRIB: # ..snip..
これらの16進値は、DT
上記で見た元の値と同じです。example(copy)
を使用してtracemem
、と比較するその他の例を入力しますdata.frame
。
ところで、その場合はtracemem(DT)
、DT[2,b:=600]
1つのコピーが報告されます。これは、print
メソッドが行う最初の10行のコピーです。invisible()
関数またはスクリプト内でラップまたは呼び出された場合、print
メソッドは呼び出されません。
これはすべて関数の内部にも適用されます。すなわち、:=
とset()
さえ関数内で、書き込みにはコピーしないでください。ローカルコピーを変更する必要がある場合x=copy(x)
は、関数の開始時に呼び出します。ただし、覚えておくべきことdata.table
は、大きなデータ(および小さなデータのプログラミングの高速化)です。意図的に大きなオブジェクトを(絶対に)コピーしたくありません。その結果、通常の3 *ワーキングメモリファクターの経験則を考慮する必要はありません。必要なのは、1列程度のワーキングメモリのみです(つまり、ワーキングメモリ係数が3ではなく1 / ncolです)。
<-
代わりに使用することがインターネットで広く推奨されています=
(たとえば、Google:google.github.io/styleguide/Rguide.xml#assignmentによって)。しかし、これはdata.table操作がデータフレーム操作と同じように機能しないため、データフレームへのドロップイン置換とはほど遠いことを意味します。