ใช่มันเป็นชุดย่อยใน R โดยใช้<-
(หรือ=
หรือ->
) ที่ทำสำเนาของวัตถุทั้งหมด คุณสามารถติดตามการใช้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
ไม่เปลี่ยนก็ตาม แม้แต่การ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 (เวกเตอร์ของจุดคอลัมน์และแต่ละคอลัมน์ 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..
ค่าฐานสิบหกเหล่านี้เหมือนกับค่าดั้งเดิมที่เราเห็นDT
ด้านบน พิมพ์example(copy)
ตัวอย่างเพิ่มขึ้นโดยใช้และเมื่อเปรียบเทียบกับtracemem
data.frame
Btw ถ้าคุณtracemem(DT)
แล้วDT[2,b:=600]
คุณจะเห็นหนึ่งสำเนารายงาน นั่นคือสำเนาของ 10 แถวแรกที่print
วิธีการทำ เมื่อห่อด้วยinvisible()
หรือเมื่อถูกเรียกภายในฟังก์ชั่นหรือสคริปต์print
วิธีการจะไม่ถูกเรียก
ทั้งหมดนี้ใช้ภายในฟังก์ชั่นเช่นกัน; คือ:=
และset()
ไม่คัดลอกเมื่อเขียนแม้ในฟังก์ชั่น หากคุณต้องการแก้ไขสำเนาในเครื่องให้โทรหาx=copy(x)
ตอนเริ่มต้นของฟังก์ชัน แต่จำไว้ว่าdata.table
สำหรับข้อมูลขนาดใหญ่ (เช่นเดียวกับข้อได้เปรียบการเขียนโปรแกรมได้เร็วขึ้นสำหรับข้อมูลขนาดเล็ก) เราตั้งใจไม่ต้องการคัดลอกวัตถุขนาดใหญ่ (เคย) ด้วยเหตุนี้เราจึงไม่จำเป็นต้องอนุญาตให้ใช้กฎหน่วยความจำแบบ 3 * โดยทั่วไปในการทำงาน เราพยายามที่จะต้องใช้หน่วยความจำในการทำงานที่มีขนาดใหญ่เท่ากับหนึ่งคอลัมน์ (เช่นหน่วยความจำที่ใช้งานได้ของ 1 / ncol มากกว่า 3)
<-
แทน=
การมอบหมายพื้นฐานใน R (เช่นโดย Google: google.github.io/styleguide/Rguide.xml#assignment ) แต่นี่หมายความว่าการจัดการ data.table จะไม่ทำงานเหมือนกับการจัดการ data frame และอยู่ไกลจากการแทนที่แบบดรอปดาวน์เป็น data frame