2016-08-31 2 views
12

나는 총 관측 수와 관측치 수를 임계치보다 많이 계산하려는 많은 그룹 (+ 2mil)을 가진 시뮬레이션 된 데이터 세트를 사용하고 있습니다. 2) 각 그룹마다.각 그룹 내에서 조건이 참인 횟수를 계산하십시오.

플래그 변수를 만들 때 훨씬 더 빠르게 나타납니다. 특히 dplyr에 대해 더 빠르며 data.table에 대해 조금 더 빠릅니다.

왜 이런 일이 발생합니까? 각각의 경우 백그라운드에서 어떻게 작동합니까?

아래 예제를 확인하십시오. 사용

모의 집합

# create an example dataset 
set.seed(318) 

N = 3000000 # number of rows 

dt = data.frame(id = sample(1:5000000, N, replace = T), 
       value = runif(N, 0, 10)) 

library(dplyr) 

# calculate summary variables for each group 
t = proc.time() 
dt2 = dt %>% group_by(id) %>% summarise(N = n(), 
             N2 = sum(value > 2)) 
proc.time() - t 

# user system elapsed 
# 51.70 0.06 52.11 


# calculate summary variables for each group after creating a flag variable 
t = proc.time() 
dt2 = dt %>% mutate(flag = ifelse(value > 2, 1, 0)) %>% 
    group_by(id) %>% summarise(N = n(), 
          N2 = sum(flag)) 
proc.time() - t 

# user system elapsed 
# 3.40 0.16 3.55 

을 사용 dplyr data.table

library(data.table) 

# set as data table 
dt2 = setDT(dt, key = "id") 


# calculate summary variables for each group 
t = proc.time() 
dt3 = dt2[, .(N = .N, 
       N2 = sum(value > 2)), by = id] 
proc.time() - t 

# user system elapsed 
# 1.93 0.00 1.94 


# calculate summary variables for each group after creating a flag variable 
t = proc.time() 
dt3 = dt2[, flag := ifelse(value > 2, 1, 0)][, .(N = .N, 
               N2 = sum(flag)), by = id] 
proc.time() - t 

# user system elapsed 
# 0.33 0.04 0.39 
+8

'data.table' 용'합 (VAR) '와'.N' 최적화 gforce이다. 그러나'sum (expr)'에 대해서는 아직 없습니다 ..'verbose = TRUE'를 추가하고 최적화 된 표현의 차이점을보십시오. 앞으로이 사례를 더 잘 포착하기 위해 노력할 것입니다. – Arun

+1

참고 : 더 이상 그룹화/결합 작업을위한 키를 설정할 필요가 없습니다. 키를 원한다면 괜찮습니다.하지만 꼭 알 필요는 없습니다. – Arun

+2

'data.table'에서 나는 data.table이 이미 두 번째 인스턴스에서 정렬되어 있다는 것을 의심합니다. 각 인스턴스 위에'dt2 = setDT (dt, key = "id")'를 넣으십시오. – lmo

답변

1

dplyr의 문제점은 sum 함수가 표현식과 많은 수의 ID/그룹과 함께 사용된다는 것입니다. Arun이 언급 한 내용에서 data.table의 문제는 비슷하다고 생각합니다.

아래 코드를 살펴보십시오. 문제를 설명하는 데 필요한 최소한으로 줄였습니다. expression이 신원 함수 만 포함한다고해도 dplyr은 표현식을 합산 할 때 속도가 느리기 때문에 성능 문제는 비교 연산자보다 중요하지 않습니다. 대조적으로, dplyr은 벡터를 합산 할 때 빠릅니다. ID/그룹 수를 100 만 개에서 10 개로 줄임으로써 훨씬 더 큰 성능 향상을 얻을 수 있습니다.

왜냐하면 hybrid evaluation, 즉 C++의 평가는 합계가 벡터와 함께 사용되는 경우에만 작동하기 때문입니다. 인수를 표현식으로 사용하면 평가가 R로 수행되므로 각 그룹에 오버 헤드가 가중됩니다. 세부 정보는 연결된 비 네트에 있습니다. 코드의 프로파일에서, 오버 헤드는 주로 tryCatch 에러 처리 함수에서 오는 것으로 보인다.

########################## 
### many different IDs ### 
########################## 

df <- data.frame(id = 1:1e6, value = runif(1e6)) 

# sum with expression as argument 
system.time(df %>% group_by(id) %>% summarise(sum(identity(value)))) 
# user system elapsed 
# 80.492 0.368 83.251 

# sum with vector as argument 
system.time(df %>% group_by(id) %>% summarise(sum(value))) 
# user system elapsed 
# 1.264 0.004 1.279 


######################### 
### few different IDs ### 
######################### 

df$id <- rep(1:10, each = 1e5) 

# sum with expression as argument 
system.time(df %>% group_by(id) %>% summarise(sum(identity(value)))) 
# user system elapsed 
# 0.088 0.000 0.093 

# sum with vector as argument 
system.time(df %>% group_by(id) %>% summarise(sum(value))) 
# user system elapsed 
# 0.072 0.004 0.077 


################# 
### profiling ### 
################# 

df <- data.frame(id = 1:1e6, value = runif(1e6)) 

profvis::profvis({ df %>% group_by(id) %>% summarise(sum(identity(value))) }) 

코드 정보 :

Code profile

관련 문제