예, 전체 객체 의 복사본을 만드는 <-
(또는 =
또는 ->
)를 사용하는 R의 하위 할당입니다 . 당신이 사용하는 것을 추적 할 수 있습니다 및 다음과 같습니다. 기능 과 무엇을 참조하여 할당은 전달되는 객체. 따라서 해당 객체가 이전에 (하위 할당 또는 explicit ) 복사 된 경우 참조로 수정 된 사본입니다.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
더라도 벡터가 어떻게 복사 되었는지 (다른 16 진수 값은 새로운 벡터 사본을 나타냄)에 주목하십시오 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 개의 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
.
BTW, 당신이 경우 tracemem(DT)
다음 DT[2,b:=600]
당신은 볼 하나 개의 사본이 보도했다. 이것은 print
메소드가 수행 하는 처음 10 행의 사본입니다 . 랩핑 invisible()
되거나 함수 또는 스크립트 내에서 호출 될 때 print
메소드가 호출되지 않습니다.
이 모든 것은 내부 함수에도 적용됩니다. 즉, :=
그리고 set()
심지어 기능 내에서 쓰기에 복사하지 마십시오. 로컬 사본을 수정해야하는 경우 x=copy(x)
함수 시작시 호출 하십시오. 그러나 data.table
큰 데이터 (작은 데이터의 프로그래밍 이점이 더 빠름)를 기억하십시오. 우리는 의도적으로 큰 객체를 복사하고 싶지 않습니다. 결과적으로 우리는 일반적인 3 * 작업 메모리 요소 규칙을 허용 할 필요가 없습니다. 하나의 열만큼 큰 작업 메모리 만 필요합니다 (즉, 작업 메모리 계수가 3이 아닌 1 / ncol).
<-
대신 사용하는 것이 널리 권장됩니다=
(예 : Google : google.github.io/styleguide/Rguide.xml#assignment ). 그러나 이는 data.table 조작이 데이터 프레임 조작과 동일한 방식으로 작동하지 않으므로 데이터 프레임을 대체하는 것과는 거리가 멀다는 것을 의미합니다.