data.table이 다른 data.table에 대한 참조(복사본)일 때 정확하게 이해
참조별 특성을 이해하는 데 약간 어려움이 있습니다.data.table
일부 작업은 참조를 '파기'하는 것으로 보이며, 정확히 무슨 일이 일어나고 있는지 알고 싶습니다.
생성 시data.table
다른 곳에서data.table
(을 통해)<-
그런 다음 새 테이블을 업데이트합니다.:=
원래 테이블도 변경됩니다.이는 다음과 같이 예상됩니다.
?data.table::copy
및 스택 오버플로: 데이터 테이블 패키지의 참조별 전달
다음은 예입니다.
library(data.table)
DT <- data.table(a=c(1,2), b=c(11,12))
print(DT)
# a b
# [1,] 1 11
# [2,] 2 12
newDT <- DT # reference, not copy
newDT[1, a := 100] # modify new DT
print(DT) # DT is modified too.
# a b
# [1,] 100 11
# [2,] 2 12
하지만, 만약 제가 비-:=
사이의 기반 수정<-
할당 및:=
위의 선,DT
이제 더 이상 수정되지 않음:
DT = data.table(a=c(1,2), b=c(11,12))
newDT <- DT
newDT$b[2] <- 200 # new operation
newDT[1, a := 100]
print(DT)
# a b
# [1,] 1 11
# [2,] 2 12
그래서 그것은newDT$b[2] <- 200
선은 어떻게든 참조를 '수정'합니다.이것이 어떻게든 복사본을 호출한다고 생각하지만, 저는 R이 이러한 작업을 어떻게 처리하고 있는지 완전히 이해하여 제 코드에 잠재적인 버그가 발생하지 않도록 하고 싶습니다.
누군가 저에게 이것을 설명해 주시면 대단히 감사하겠습니다.
예, Ring에서 하위 할당입니다.<-
(또는)=
또는->
) 전체 개체의 복사본을 만듭니다.다음을 사용하여 추적할 수 있습니다.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 ..
세 개의 16진수 값(열 점의 벡터 및 두 개의 각 열)은 모두 변경되지 않습니다.그래서 사본이 전혀 없이 참조에 의해 수정되었습니다.
또는 원본을 수정할 수 있습니다.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]
한 부가 보고되는 것을 볼 수 있습니다.그것은 처음 10개 행의 복사본입니다.print
방법은 그렇습니다.로 시invisible()
함수나 때, 는함수또내호때출에될서트크스는또립,▁or,때될,print
메서드가 호출되지 않았습니다.
이 모든 것은 함수 내부에서도 적용됩니다.:=
그리고.set()
함수 내에서도 쓰기 시 복사하지 마십시오.로컬 복사본을 수정해야 하는 경우, 다음으로 전화하십시오.x=copy(x)
기능이 시작될 때.하지만, 기억하세요.data.table
는 대용량 데이터를 위한 것입니다(소형 데이터를 위한 더 빠른 프로그래밍 이점도 있음).우리는 일부러 큰 물체를 복사하고 싶지 않습니다.따라서 일반적인 3* 작동 메모리 팩터 규칙을 고려할 필요가 없습니다.하나의 열만큼 큰 작업 메모리(즉, 3이 아닌 1/ncol의 작업 메모리 팩터)만 필요합니다.
간단히 요약하면 됩니다.
<-
와 함께data.table
즉, 에 베스와같다로 하위 .<-
: 열 이름 변경 )DT[i,j]<-v
그리고 나서 그것은 베이스와 마찬가지로 전체 물체의 복사본을 얻습니다.이를 쓰기 시 복사라고 합니다.내 생각에 카피 온 서브 배정으로 더 잘 알려져 있을 것 같습니다!특수 기능을 사용할 때 복사되지 않습니다.:=
연자또는set*
에서 data.table
데이터가 크면 데이터를 대신 사용할 수 있습니다. :=
그리고.set*
을 .data.table
기능 내에서도 가능합니다.
이 예제 데이터를 고려할 때:
DT <- data.table(a=c(1,2), b=c(11,12))
다음은 다른 이름을 "바인딩"하는 것뿐입니다.DT2
있습니다.DT
:
DT2 <- DT
이것은 절대 복사하지 않으며 베이스에서도 복사하지 않습니다.두 이름R이 두 개다이의알른데수개있이표터체뿐시도입를다할니록름을▁(▁it뿐r▁marks▁just▁object입▁that)을 알 수 있도록 데이터 개체를 표시할 뿐입니다.DT2
그리고.DT
) 동일한 개체를 가리킵니다.따라서 R은 나중에 둘 중 하나가 하위 할당되면 개체를 복사해야 합니다.
에딱맞다니에 딱 .data.table
. 그그. ▁too.:=
그렇게 하기 위한 것이 아닙니다.인 오류입니다.:=
이름을 것이 . : 체이름바것아이닙다니개는인하딩.
DT2 := DT # not what := is for, not defined, gives a nice error
:=
참조에 의한 하위 할당을 위한 것입니다.하지만 당신은 베이스에서처럼 그것을 사용하지 않습니다.
DT[3,"foo"] := newvalue # not like this
당신은 그것을 이렇게 사용합니다:
DT[3,foo:=newvalue] # like this
그것은 변했습니다DT
참고로새 열을 추가한다고 가정합니다.new
객체를 할 가 없습니다. : 이터개참체이수필없요습다니가데할행작을업여조.
DT <- DT[,new:=1L]
RHS가 변경되었기 입니다.DT
참고로엑스트라DT <-
무엇을 오해하는 것입니다.:=
쓸 수 은 불필요합니다. 거기에 쓸 수는 있지만, 불필요합니다.
DT
됩니다.:=
FUNCTION :EVEN FUNCTION :
f <- function(X){
X[,new2:=2L]
return("something else")
}
f(DT) # will change DT
DT2 <- DT
f(DT) # will change both DT and DT2 (they're the same data object)
data.table
대규모 데이터셋을 위한 것입니다. 20GB가 있는경data.table
기억 속에서 당신은 이것을 할 수 있는 방법이 필요합니다.이것은 매우 의도적인 설계 결정입니다.data.table
.
물론 복사도 가능합니다.data에 data.table을 데이터셋을 만 하면 . data.table은 20GB 데이터셋을 복사할 수 있습니다.copy()
함수:
DT3 <- copy(DT) # rather than DT3 <- DT
DT3[,new3:=3L] # now, this just changes DT3 because it's a copy, not DT too.
복사를 방지하려면 기본 유형 할당 또는 업데이트를 사용하지 마십시오.
DT$new4 <- 1L # will make a copy so use :=
attr(DT,"sorted") <- "a" # will make a copy use setattr()
하려면 참조업중인확인하면려지를 합니다..Internal(inspect(x))
구성 요소의 메모리 주소 값을 확인합니다(Matthew Dowle의 답변 참조).
기:=
j
이와 같이 그룹별로 참조하여 하위 할당할 수 있습니다.그룹별로 참조하여 새 열을 추가할 수 있습니다.그래서 그런 거지.:=
안에서 그런 식으로 행해집니다.[...]
:
DT[, newcol:=mean(x), by=group]
언급URL : https://stackoverflow.com/questions/10225098/understanding-exactly-when-a-data-table-is-a-reference-to-vs-a-copy-of-another
'source' 카테고리의 다른 글
대형 R 프로그램을 어떻게 구성합니까? (0) | 2023.06.13 |
---|---|
루비 전송 vs __send__ (0) | 2023.06.13 |
Firebase Auth ID 토큰에 잘못된 "aud" 클레임이 있습니다. (0) | 2023.06.13 |
UIPageViewController에서 프로그래밍 방식으로 페이지를 넘길 수 있습니까? (0) | 2023.06.13 |
NSData를 6진수 문자열로 직렬화하는 가장 좋은 방법 (0) | 2023.06.13 |