2012-05-14 7 views
8

큰 data.table의 열 클래스를 결정하고 싶습니다.R : data.table의 열 위로 반복하십시오.

colClasses <- sapply(DT, FUN=function(x)class(x)[1]) 

작품,하지만 분명히 로컬 복사본은 메모리에 저장됩니다 "FALSE =와"는 data.table 항상 data.table 결과 때문에

> memory.size() 
[1] 687.59 
> colClasses <- sapply(DT, class) 
> memory.size() 
[1] 1346.21 

루프가 가능하지 보인다.

빠르고 매우 더러운 방법은 다음과 같습니다

DT1 <- DT[1, ] 
colClasses <- sapply(DT1, FUN=function(x)class(x)[1]) 

이 작업을 수행 할 수있는 가장 elegent하고 효율적인 방법은 무엇입니까? 나는이

colClasses <- sapply(head(DT1,1), FUN=class) 

은 기본적 quick'n'dirty 솔루션 그러나 아마 (심지어없는 경우 너무 많은) 조금 명확 같은 접근 방식에 뭔가 잘못 표시되지 않습니다

+1

나는 잘 모르겠다. 왜 '사프리 (DT, 클래스)'가 아닌가? –

+0

타이밍은 위의 텍스트에 추가 –

+3

@MatthewDowle : 나는 OP가 sapply가 각 열에 대해 FUN으로 전달할 data.table의 하위 집합으로 임시 변수를 만드는 것을 의미한다고 생각합니다. 그것의 data.table은 정말로 크고 많은 컬럼을 가지고 있기 때문에 효율적이지 않습니다. 이런 이유로 그의 해결 방법은 data.table을 한 행으로 줄이고 먼저 sapply를 호출하는 것입니다. – digEmAll

답변

10

간단히 조사한 결과 data.table 버그가있는 것 같습니다.

> DT = data.table(a=1:1e6,b=1:1e6,c=1:1e6,d=1:1e6) 
> Rprofmem() 
> sapply(DT,class) 
     a   b   c   d 
"integer" "integer" "integer" "integer" 
> Rprofmem(NULL) 
> noquote(readLines("Rprofmem.out")) 
[1] 4000040 :"as.list.data.table" "as.list" "lapply" "sapply"  
[2] 4000040 :"as.list.data.table" "as.list" "lapply" "sapply" 
[3] 4000040 :"as.list.data.table" "as.list" "lapply" "sapply" 
[4] 4000040 :"as.list.data.table" "as.list" "lapply" "sapply" 

> tracemem(DT) 
> sapply(DT,class) 
tracemem[000000000431A290 -> 00000000065D70D8]: as.list.data.table as.list lapply sapply 
     a   b   c   d 
"integer" "integer" "integer" "integer" 

그래서, as.list.data.table보고 :

> data.table:::as.list.data.table 
function (x, ...) 
{ 
    ans <- unclass(x) 
    setattr(ans, "row.names", NULL) 
    setattr(ans, "sorted", NULL) 
    setattr(ans, ".internal.selfref", NULL) 
    ans 
} 
<environment: namespace:data.table> 
> 

참고 첫 번째 줄에 성가신 unclass합니다. ?unclass은 인수의 전체 복사본이 필요함을 확인합니다. 이 빠른 모양에서 sapply 또는 lapply이 복사를하고있는 것처럼 보이지 않습니다. (R은 copy-on-write가 좋고 쓰기가 잘되지 않았기 때문에 생각하지 않았습니다.) as.listlapply입니다. (as.list.data.table으로 파견).

따라서 unclass을 피하면 속도가 빨라집니다. 의 시도하자

> DT = data.table(a=1:1e7,b=1:1e7,c=1:1e7,d=1:1e7) 
> system.time(sapply(DT,class)) 
    user system elapsed 
    0.28 0.06 0.35 
> system.time(sapply(DT,class)) # repeat timing a few times and take minimum 
    user system elapsed 
    0.17 0.00 0.17 
> system.time(sapply(DT,class)) 
    user system elapsed 
    0.13 0.04 0.18 
> system.time(sapply(DT,class)) 
    user system elapsed 
    0.14 0.03 0.17 
> assignInNamespace("as.list.data.table",function(x)x,"data.table") 
> data.table:::as.list.data.table 
function(x)x 
> system.time(sapply(DT,class)) 
    user system elapsed 
     0  0  0 
> system.time(sapply(DT,class)) 
    user system elapsed 
    0.01 0.00 0.02 
> system.time(sapply(DT,class)) 
    user system elapsed 
     0  0  0 
> sapply(DT,class) 
     a   b   c   d 
"integer" "integer" "integer" "integer" 
> 

그래서, 그래, 무한 더 나은.

나도 이미 data.tableis()list 때문에, as.list.data.table 방법을 제거 bug report #2000을 제기했습니다. 이것은 lapply(.SD,...)과 같이 실제로 상당히 숙달 될 수 있습니다. [편집 : 이것은 v1.8.1에서 수정되었습니다.]

고마워요 !!

+0

매우 유익한 소식입니다. 디버깅에 사용한 단계를 보여 주셔서 감사합니다. –

+0

감사합니다 Matthew! –

2

...

+0

그것은 실제로 좋은 해결책이지만, 내가 바라는만큼 우아하지는 않습니다. –

+0

@ user1393348 : 예, 아직 해결 방법이 있습니다. :) – digEmAll