요인 및 숫자 열이있는 큰 (많은 GB) 테이블에서 "가장 가까운"행을 반복적으로 조회해야합니다. 여기큰 데이터 세트의 빠른 하위 집합/조회/필터
df <- data.frame(factorA = rep(letters[1:3], 100000),
factorB = sample(rep(letters[1:3], 100000),
3*100000, replace = FALSE),
numC = round(rnorm(3*100000), 2),
numD = round(rnorm(3*100000), 2))
closest <- function(ValueA, ValueB, ValueC, ValueD) {
df_sub <- df %>%
filter(factorA == ValueA,
factorB == ValueB,
numC >= 0.9 * ValueC,
numC <= 1.1 * ValueC,
numD >= 0.9 * ValueD,
numD <= 1.1 * ValueD)
if (nrow(df_sub) == 0) stop("Oh-oh, no candidates.")
minC <- df_sub[which.min(abs(df_sub$numC - ValueC)), "numC"]
df_sub %>%
filter(numC == minC) %>%
slice(which.min(abs(numD - ValueD))) %>%
as.list() %>%
return()
}
을 위의 벤치 마크 : dplyr
를 사용하면, 다음과 같다
> microbenchmark(closest("a", "b", 0.5, 0.6))
Unit: milliseconds
expr min lq mean median uq max neval
closest("a", "b", 0.5, 0.6) 25.20927 28.90623 35.16863 34.59485 35.25468 108.3489 100
속도에 대한이 기능을 최적화 할 수있는 가장 좋은 방법은 무엇입니까? 메모리가 큰 df
인데도 불구하고 여분의 RAM이 있지만이 함수에 대한 호출이 많으면 가능한 빨리 작성하려고합니다.
dplyr
대신 data.table
을 사용 하시겠습니까?
여기에 내가 지금까지 노력이 최적화는 다음과 같습니다
dt <- as.data.table(df)
closest2 <- function(ValueA, ValueB, ValueC, ValueD) {
df_sub <- df %>%
filter(factorA == ValueA,
factorB == ValueB,
dplyr::between(numC, 0.9 * ValueC, 1.1 * ValueC),
dplyr::between(numD, 0.9 * ValueD, 1.1 * ValueD))
if (nrow(df_sub) == 0) stop("Oh-oh, no candidates.")
minC <- df_sub[which.min(abs(df_sub$numC - ValueC)), "numC"]
df_sub %>%
filter(numC == minC) %>%
slice(which.min(abs(numD - ValueD))) %>%
as.list() %>%
return()
}
closest3 <- function(ValueA, ValueB, ValueC, ValueD) {
dt_sub <- dt[factorA == ValueA &
factorB == ValueB &
numC %between% c(0.9 * ValueC, 1.1 * ValueC) &
numD %between% c(0.9 * ValueD, 1.1 * ValueD)]
if (nrow(dt_sub) == 0) stop("Oh-oh, no candidates.")
dt_sub[abs(numC - ValueC) == min(abs(numC - ValueC))][which.min(abs(numD - ValueD))] %>%
as.list() %>%
return()
}
벤치 마크 :
> microbenchmark(closest("a", "b", 0.5, 0.6), closest2("a", "b", 0.5, 0.6), closest3("a", "b", 0.5, 0.6))
Unit: milliseconds
expr min lq mean median uq max neval cld
closest("a", "b", 0.5, 0.6) 25.15780 25.62904 36.52022 34.68219 35.27116 155.31924 100 c
closest2("a", "b", 0.5, 0.6) 22.14465 22.46490 27.81361 31.40918 32.04427 35.79021 100 b
closest3("a", "b", 0.5, 0.6) 13.52094 13.77555 20.04284 22.70408 23.41452 142.73626 100 a
이 더 최적화 할 수 있습니까? rowwise를 실행해야합니다 다른 솔루션과 비교
C 및 D의 주문 색인을 받고 이진 검색을 사용하면 어떨까요? –
어떻게? 나는'setkey (dt, numC, numD)'를 시도했으나 차이를 만들지는 않았다. –
이들을 병렬로 (단일 값 대신 ValueA, ValueB, ValueC, ValueD로) 볼 수 있다면 순차적으로 훨씬 빠르게 수행 할 수있을 것입니다 (이는 분명히 어떻게 계획 할 것인가입니다 당신이 그런 식으로 벤치마킹을하고 있기 때문에 이것을 "반복해서"하는 것). – Frank