2013-03-07 2 views
10

data.table (우수한 패키지 !!!)에서 일부 집계를 수행하고 있으며 .SD 변수가 많은 것들에 매우 유용하다는 것을 알았습니다. 그러나 그룹을 많이 사용하면 계산 속도가 크게 느려집니다. 다음 예를 참조하십시오 :R data.table .SD를 사용할 때 느린 집계

# A moderately big data.table 
x = data.table(id=sample(1e4,1e5,replace=T), 
       code=factor(sample(2,1e5,replace=T)), 
       z=runif(1e5) 
      ) 

setkey(x,id,code) 

system.time(x[,list(code2=nrow(.SD[code==2]), total=.N), by=id]) 
## user system elapsed 
## 6.226 0.000 6.242 

system.time(x[,list(code2=sum(code==2), total=.N), by=id]) 
## user system elapsed 
## 0.497 0.000 0.498 

system.time(x[,list(code2=.SD[code==2,.N], total=.N), by=id]) 
## user system elapsed 
## 6.152 0.000 6.168 

내가 잘못하고 있나? 개별 열을 선호하는 SD를 피해야합니까? 미리 감사드립니다. 빨리보다는 즉, ~ 200 배를 내 컴퓨터에

system.time({ 
    x2 <- x[code==2, list(code2=.N), by=id] 
    xt <- x[, list(total=.N), by=id] 
    print(x2[xt]) 
}) 

7.42 초에 반대는 0.04 초에서 실행 : 다음 두 단계로 계산을 깨는 결과 데이터 프레임을 병합하여이 문제를 해결

답변

11

오전 내가 개별 열 찬성 .SD을 피해야한다 뭔가 잘못 즉거야?

예. 실제로 .SD 안에있는 모든 데이터를 사용하는 경우에만 .SD을 사용하십시오. nrow()에 대한 호출과 [.data.table에 대한 보조 쿼리 호출이 j 안에있는 것을 확인할 수도 있습니다. Rprof을 사용하여 확인하십시오.

자주 묻는 질문 2.1의 마지막 몇 문장을 참조하십시오

자주 묻는 질문 2.1은 어떻게 정말로 긴 J 식을 작성하지 않도록 할 수 있습니까? 컬럼 이름을 사용해야한다고 말했지만 많은 컬럼이 있습니다.
하면 j 표현 당신이 알고 으로, 변수로 열 이름을 사용할 수 있습니다, 그룹화, 그러나 또한 예약 된 기호 각 그룹에 대해 에 Data.table의 하위 집합을 의미 .SD를 사용할 수있는 경우 (그룹화 열을 제외). 따라서 모든 항목을 요약하려면 DT[,lapply(.SD,sum),by=grp]입니다. 까다로울 수도 있지만 쓰기가 빠르며 실행 속도가 빠릅니다. 익명의 함수를 만들지 않아도됩니다. 다른 방법과 비교하여 타이밍 비 네트 및 위키를 참조하십시오. .SD 개체는 내부적으로 효율적으로 구현되며 함수에 인수를 전달하는 것보다 더 효과적입니다. 그래도하지 마십시오 : DT[,sum(.SD[,"sales",with=FALSE]),by=grp]. 그게 효과가 있지만 매우 비능률적이고 우아합니다. 이것은 의도 한 것입니다 : DT[,sum(sales),by=grp] 그리고 100 배 빠른 수 있습니다.

FAQ I 3.1 20 열을 가지며 다수의 행 :

또한 FAQ 3.1 제 탄환 참조. 한 열의 표현이 왜 그렇게 빠른가요?
몇 가지 이유 :
- data.tablej 표현을 검사하고 다른 열을 사용하지 않습니다 실현 때문에 해당 열이 그룹화, 다른 19 무시됩니다.data.tablej을 검사하고 .SD 기호를 볼 때

는 그 효율성 이득은 창 밖을 간다. 모든 열을 사용하지 않아도 각 그룹에 대해 .SD 하위 집합 전체를 채워야합니다. data.table이 실제로 사용하고있는 .SD의 열 (jif을 포함 할 수 있음)을 알아내는 것은 매우 어렵습니다. 그러나 어쨌든 모두 필요하면 DT[,lapply(.SD,sum),by=...]과 같이 중요하지 않습니다. 그것은 .SD의 이상적인 사용법입니다.

그래, 가능하면 .SD을 피하십시오. 열 이름을 직접 사용하여 data.table의 최적화 j을 가장 좋은 기회로 지정하십시오. 심볼 .SD의 존재는 j에 중요합니다.

이것이 .SDcols 인 이유입니다. 따라서 하위 집합 만 원할 경우 data.table에 어떤 열이 .SD인지 알려줄 수 있습니다. 그렇지 않으면 data.tablej에서 필요로하는 모든 열과 함께 .SD을 채 웁니다.

+0

고마워요! 나는 ".SD 객체가 내부적으로 효율적으로 인수를 함수에 전달하는 것보다 효율적으로 구현되었다"는 구절에 속아서 "제발하지 마세요. DT [, sum (.SD [," sales =, with = FALSE]), by = grp]로 표시됩니다. 이렇게하면 많은 코드가 빨라집니다! – vsalmendra

+0

@vsalmendra 아, 그렇습니다. 과거에 커뮤니티 토론에 맡겨져있는 일종의 것입니다. 궁극적으로 우리는'j' 최적화를 개선하여 사용자가 이와 같은 것을 알 필요가 없도록하고자합니다. –

+0

@vsalmendra 이제 다음 릴리스에서 FAQ 2.1을 개선했습니다. –

3

시도 원래 코드 :

  id code2 total 
    1:  1  6 14 
    2:  2  8 10 
    3:  3  7 13 
    4:  4  5 13 
    5:  5  9 18 
    ---     
9995: 9996  4  9 
9996: 9997  3  6 
9997: 9998  6 10 
9998: 9999  3  4 
9999: 10000  3  6 
    user system elapsed 
    0.05 0.00 0.04 
+0

(+1)''x2''를'x2 <- x [J (unique (id), 2 "), list (code2 = .N)] [, code : = NULL, keyby = "id"]'. 코드는 주어진 id에 대해 코드! = 2 인 행을 제거합니다. – Arun

+0

+1 실제로'x [, list (sum (code == 2), N), by = id]'(예제 2)보다 훨씬 빠릅니다! 왜냐하면 각 그룹에 대해'=='를 반복적으로 호출하는 것을 피하기 때문입니다 (작은 벡터에 대한 할당 할당 등). –

+0

@Arun 확실합니까? 'x2 [xt] [is.na (code2)]'에는 몇 개의 행이 있습니다. 당신은'0' 대신에'NA'를 얻습니다. 잘못되었을 수도 있습니다. –