Có, đó là cấp dưới trong R bằng cách sử dụng <-
( =
hoặc ->
) tạo bản sao của toàn bộ đối tượng. Bạn có thể theo dõi bằng cách sử dụng tracemem(DT)
và .Internal(inspect(DT))
, như dưới đây. Các data.table
tính năng :=
và set()
gán bằng cách tham chiếu đến bất kỳ đối tượng nào chúng được thông qua. Vì vậy, nếu đối tượng đó đã được sao chép trước đó (bằng cách đăng ký phụ <-
hoặc rõ ràng copy(DT)
) thì đó là bản sao được sửa đổi bằng tham chiếu.
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..
Lưu ý rằng ngay cả a
vectơ đã được sao chép (giá trị hex khác nhau biểu thị bản sao mới của vectơ), mặc dù a
không thay đổi. Ngay cả toàn bộ b
đã được sao chép, thay vì chỉ thay đổi các yếu tố cần phải thay đổi. Đó là điều quan trọng để tránh dữ liệu lớn, và tại sao :=
và set()
được giới thiệu data.table
.
Bây giờ, với bản sao của newDT
chúng tôi, chúng tôi có thể sửa đổi nó bằng cách tham khảo:
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 ..
Lưu ý rằng tất cả 3 giá trị hex (vectơ của các điểm cột và mỗi cột trong 2 cột) không thay đổi. Vì vậy, nó đã thực sự được sửa đổi bằng cách tham khảo mà không có bản sao nào cả.
Hoặc, chúng tôi có thể sửa đổi bản gốc DT
bằng cách tham khảo:
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..
Các giá trị hex này giống như các giá trị ban đầu mà chúng ta đã thấy DT
ở trên. Nhập example(copy)
để biết thêm ví dụ sử dụng tracemem
và so sánh với data.frame
.
Btw, nếu tracemem(DT)
sau đó DT[2,b:=600]
bạn sẽ thấy một bản sao được báo cáo. Đó là bản sao của 10 hàng đầu tiên mà print
phương thức thực hiện. Khi được bao bọc bởi invisible()
hoặc khi được gọi trong một hàm hoặc tập lệnh, print
phương thức không được gọi.
Tất cả điều này áp dụng bên trong các chức năng quá; tức là :=
và set()
không sao chép trên ghi, ngay cả trong các hàm. Nếu bạn cần sửa đổi một bản sao cục bộ, sau đó gọi x=copy(x)
khi bắt đầu chức năng. Nhưng, hãy nhớ data.table
là dành cho dữ liệu lớn (cũng như lợi thế lập trình nhanh hơn cho dữ liệu nhỏ). Chúng tôi cố tình không muốn sao chép các đối tượng lớn (bao giờ). Kết quả là chúng ta không cần phải cho phép quy tắc ngón tay cái làm việc 3 * thông thường. Chúng tôi cố gắng chỉ cần bộ nhớ làm việc lớn bằng một cột (tức là hệ số bộ nhớ làm việc là 1 / ncol chứ không phải 3).
<-
thay vì chỉ=
định cơ bản trong R (ví dụ: bởi Google: google.github.io/styleguide/Rguide.xml#assocation ). Nhưng điều này có nghĩa là thao tác data.table sẽ không hoạt động giống như thao tác khung dữ liệu và do đó không phải là sự thay thế thả vào khung dữ liệu.