2017-10-20 6 views
0

data.table을 사용하여 데이터 집합에 걸쳐 그룹별로 두 개의 매개 변수 함수를 빠르게 적용 할 수 있습니까? 1 백만 행의 데이터 세트에서 아래 정의 된 간단한 함수를 호출하는 것이 11 초를 넘기 때문에이 복잡성에 대해 예상하는 것보다 훨씬 길다는 것을 알았습니다.R data.table에 대한 빠른 쿼리 -이 두 인수 함수를 그룹별로 더 빠르게 적용 할 수 있습니까?

# generate data frame - 1 million rows 
library(data.table) 
set.seed(42) 
nn = 1e6 
daf = data.frame(aa=sample(1:1000, nn, repl=TRUE), 
       bb=sample(1:1000, nn, repl=TRUE), 
       xx=rnorm(nn), 
       yy=rnorm(nn), 
       stringsAsFactors=FALSE) 

# myfunc is the function to apply to each group 
myfunc = function(xx, yy) { 
    if (max(yy)>1) { 
    return(mean(xx)) 
    } else { 
    return(weighted.mean(yy, ifelse(xx>0, 2, 1))) 
    } 
} 

# running the function takes around 11.5 seconds 
system.time({ 
    dt = data.table(daf, key=c("aa","bb")) 
    dt = dt[,myfunc(xx, yy), by=c("aa","bb")] 
}) 

head(dt) 
# OUTPUT: 
# aa bb   V1 
# 1: 1 2 -1.02605645 
# 2: 1 3 -0.49318243 
# 3: 1 4 0.02165797 
# 4: 1 5 0.40811793 
# 5: 1 6 -1.00312393 
# 6: 1 7 0.14754417 

크게 이런 함수 호출 시간을 줄일 수있는 방법이 있나요 :

자체 포함 된 코드는 아래에 내가 뭘하려고 오전의 본질을 설명?

함수 호출을 완전히 다시 작성하지 않고 위의 계산을 수행하는 더 효율적인 방법이 있는지 또는 함수를 분리하여 data.table에 다시 써서 만 쓸 수 있는지 여부에 관심이 있습니다. 통사론.

답장에 미리 감사드립니다.

답변

1

또 다른 해결책은 감소 내 컴퓨터에서 약 0.2 초 정도. 아래를 참조하십시오. 시간이 많이 소요되는 각 그룹에 대해 sum (yyw)/sum (w)을 직접 계산하는 대신, 각 그룹에 대해 sum sum (yyw) 및 sum (w)을 계산하고 이후에 만 나누기를 수행합니다. 마법! 당신이 ifelse``을 제거하면

system.time({ 
    dt <- data.table(daf, key = c("aa","bb")) 
    dt[, w := 1][xx > 0, w := 2] 
    dt[, yyw := yy * w] 
    res <- dt[, .(maxy = max(yy), 
       meanx = mean(xx), 
       wm2num = sum(yyw), 
       wm2den = sum(w)), 
       by = c("aa","bb")] 
    res[, wm2 := wm2num/wm2den]    
    res[, V1 := wm2][maxy > 1, V1 := meanx] 

    res[, c("maxy", "meanx", "wm2num", "wm2den", "wm2") := NULL] 
}) # 0.19 

all.equal(res, dtInitial) 
# [1] TRUE 
2

귀하의 결과 :

system.time({ 
    dt = data.table(daf, key = c("aa","bb")) 
    dt = dt[,myfunc(xx, yy), by = c("aa","bb")] 
}) # 21.25 
dtInitial <- copy(dt) 

V1 :

myfunc2 = function(xx, yy) { 
    if (max(yy) > 1) { 
    return(mean(xx)) 
    } else { 
    w <- ifelse(xx > 0, 2, 1) 
    return(sum((yy * w)[w != 0])/sum(w)) 
    } 
} 

system.time({ 
    dt = data.table(daf, key = c("aa","bb")) 
    dtM = dt[, myfunc2(xx, yy), by = c("aa","bb")] 
}) # 6.69 
all.equal(dtM, dtInitial) 
# [1] TRUE 

V2 : NA 값을 염려하지 않는 경우, 당신은이 같은 함수를 수정할 수 있습니다 또한, 당신은 빨리이 같은 그것을 할 수 있습니다 :

system.time({ 
dt3 <- data.table(daf, key = c("aa","bb")) 
dt3[, maxy := max(yy), by = c("aa","bb")] 
dt3[, meanx := mean(xx), by = c("aa","bb")] 
dt3[, w := ifelse(xx > 0, 2, 1)] 
dt3[, wm2 := sum((yy * w)[w != 0])/sum(w), by = c("aa","bb")] 
r2 <- dt3[, .(aa, bb, V1 = ifelse(maxy > 1, meanx, wm2))] 
r2 <- unique(r2) 
}) #2.09 
all.equal(r2, dtInitial) 
# [1] TRUE 

20 SEK

을 나를 위해 SEK 2 대 691,363,210

업데이트 :

또는 빠른 조금 :

system.time({ 
    dt3 <- data.table(daf, key = c("aa","bb")) 
    dt3[, w := ifelse(xx > 0, 2, 1)] 
    dt3[, yyw := yy * w] 
    r2 <- dt3[, .(maxy = max(yy), 
       meanx = mean(xx), 
       wm2 = sum(yyw)/sum(w)), 
      , by = c("aa","bb")] 
    r2[, V1 := ifelse(maxy > 1, meanx, wm2)] 
    r2[, c("maxy", "meanx", "wm2") := NULL] 
}) # 1.51 

all.equal(r2, dtInitial) 
# [1] TRUE 
+2

당신은 좀 더 속도 향상을 데리러 갈게 (예를 들어'DT3 [= 1, w] [▼, XX> 0 : = 2] ') – eddi

+1

그것은이다 'dt [, mean (a), by = b]'가'mymean = function (x) mean (x)보다 훨씬 빠르다는 것을 의미합니다. ; dt [, mymean (a), by = b]' – eddi

1

나는 8 배 더 속도 향상을 얻을 수있는 방법을 발견했습니다

system.time({ 
    dat <- data.table(daf, key = c("aa","bb")) 
    dat[, xweight := (xx > 0) * 1 + 1] 
    result <- dat[, list(MaxY = max(yy), Mean1 = mean(xx), Mean2 = sum(yy*xweight)/sum(xweight)), keyby=c("aa", "bb")] 
    result[, FinalMean := ifelse(MaxY > 1, Mean1, Mean2)] 
}) 

    user system elapsed 
    1.964 0.059 1.348