2017-10-26 5 views
3

두 벡터가 있다고 가정합니다. 하나는 관심있는 모든 값과 가능한 모든 값을 포함 할 수있는 하나의 샘플 벡터를 포함하는 참조 벡터/목록입니다. 지금은 벡터 내부의 비교 값의 특정 고정되지 관용과 depentent의 참조 목록 안에 내 샘플의 일치를 찾으려면 :허용 오차 (매우 빠르지 만 작업 공간 절약)가있는 두 개의 매우 큰 벡터를 일치 시키십시오.

matches: abs(((referencelist - sample[i])/sample[i])*10^6)) < 0.5 

두 벡터를 반올림있는 옵션입니다! 예를 들어

고려 :
referencelist <- read.table(header=TRUE, text="value name 
154.00312 A 
154.07685 B 
154.21452 C 
154.49545 D 
156.77310 E 
156.83991 F 
159.02992 G 
159.65553 H 
159.93843 I") 

sample <- c(154.00315, 159.02991, 154.07688, 156.77312) 

그래서 난 결과를 얻을 :

name value  reference 
1 A 154.00315 154.00312 
2 G 159.02991 159.02992 
3 B 154.07688 154.07685 
4 E 156.77312 156.77310 

나는 예를 들어, 사용 할 수있는 일

myDist <- outer(referencelist, sample, FUN=function(x, y) abs(((x - y)/y)*10^6)) 
matches <- which(myDist < 0.5, arr.ind=TRUE) 
data.frame(name = referencelist$name[matches[, 1]], value=sample[matches[, 2]]) 

과 같은 외부 함수 또는 for() 루프를 사용할 수 있습니다.

하지만 내 특별한 문제는 약 1 * 10^12 엔트리의 참조 벡터와 1 * 10^7 주위의 샘플 벡터입니다. 그래서 outer()를 사용하여 모든 작업 공간 제한을 쉽게 파기하고 for() 또는 연결 for() 루프를 사용하여이 작업을 완료하는 데 일/주가 소요될 것입니다.

누구나 R에서이 작업을 빠르게 수행하는 방법에 대한 아이디어가 있지만 여전히 정확하지만 최대 컴퓨터를 사용하고 있습니다. 64 GB RAM?

도움 주셔서 감사합니다.

최저 whishes data.table를 사용

+1

참조 벡터가 정렬 되었습니까? 그렇다면 가장 가까운 숫자를 찾기 위해 이분법을 사용할 수 있습니다. 그렇지 않다면 - 그것을 정렬하십시오! 또한 어떻게 저장됩니까? RAM에 너무 큽니다. 단일 파일입니까 아니면 여러 파일에 걸쳐 있습니까? –

+0

사용자가 지정한 예제에서 모든 값은 좁은 범위 (154, 160)로 표시됩니다. '(x-y)/y' 대신'(x-y)/154'를 계산함으로써 문제를 단순화 할 수 있습니까? –

+0

@john Coleman : 예. 오름차순으로 정렬됩니다. 이분법이란 무엇입니까? 전에는 들리지 않았고, 나는 아프다. 참조 벡터가 내 RAM에 들어가면 약 64GB의 여유 공간이 있습니다. – JmO

답변

3

귀하의 일치 ​​조건은

abs(((referencelist - sample[i])/sample[i])*10^6)) < 0.5 

eps = 0.5E-6

sample[i] * (1 - eps) < referencelist < sample[i] * (1 + eps) 

로 다시 쓸 수 있습니다. 이 사용

, 우리는 모든 일치 (뿐만 아니라 가까운을 찾기 위해이 비 조인을 사용할 수 있습니다!) 각 sample에 대한 referencelist에서 : 예상 결과를 재현

library(data.table) 
options(digits = 10) 
eps <- 0.5E-6 # tol * 1E6 
setDT(referencelist)[.(value = sample, 
         lower = sample * (1 - eps), 
         upper = sample * (1 + eps)), 
        on = .(ref > lower, ref < upper), .(name, value, reference = x.ref)] 

:

OP's comment에 대응
name  value reference 
1: A 154.00315 154.00312 
2: G 159.02991 159.02992 
3: B 154.07688 154.07685 
4: E 156.77312 156.77310 

, 다음이 될 것입니다 우리가 F = 154.00320referencelist2을 수정 한의 말을하자 잡히다 :

setDT(referencelist2)[.(value = sample, 
         lower = sample * (1 - eps), 
         upper = sample * (1 + eps)), 
        on = .(ref > lower, ref < upper), .(name, value, reference = x.ref)] 
name  value reference 
1: A 154.00315 154.00312 
2: F 154.00315 154.00320 
3: G 159.02991 159.02992 
4: B 154.07688 154.07685 
5: E 156.77312 156.77310 
4

(그리고 @ EDDI의 binary search (또한 양분에서, CF @ 존 콜먼의 코멘트) - 붙여 넣기를 복사) :

library(data.table) 

dt <- as.data.table(referencelist) 
setattr(dt, "sorted", "value") 

tol <- 0.5 
dt2 <- dt[J(sample), .(.I, ref = value, name), roll = "nearest", by = .EACHI] 
dt2[, diff := abs(ref - value)/value * 1e6] 
dt2[diff <= tol] 

#  value I  ref name  diff 
# 1: 154.0032 1 154.0031 A 0.19480121 
# 2: 159.0299 7 159.0299 G 0.06288125 
# 3: 154.0769 2 154.0769 B 0.19470799 
# 4: 156.7731 5 156.7731 E 0.12757289 

I 메모리 사용이나 실행을 벤치마킹하지 않은 하지만 data.table은 두 가지 모두에 매우 뛰어나다는 평판을 얻고 있습니다. 그것이 당신을 위해 작동하지 않는다면, 그렇게 말하면 아마도 벤치마킹을 시도 할 것입니다.

참고 : data.table을 사용하는 것은 매우 순진합니다.

https://stackoverflow.com/a/29552922/6197649 바로 아래에 findInterval을 사용하는 해결책이 있지만 성능이 좋지 않을 것으로 예상됩니다 (다시 : 벤치 마크가 필요할 것입니다).

+0

많은 것을 고맙습니다. 이것은 매우 좋은 것 같습니다. 나는 가능한 한 빨리 테스트 할 것이지만, 벡터의 크기 때문에 이것이 시간/일이 걸릴 수도 있다고 말하는 것이 끔찍하다. 곧 돌아오고 다시 감사드립니다! – JmO

+0

간단한 질문을하기 전에 샘플은 단일 벡터 여야하며 아니면 값이있는 열 샘플을 선택할 수있는 데이터 프레임 또는 매트릭스 일 수 있습니까? – JmO

+1

@JmO 선형 검색은'O (n)'입니다. 'n = 10^12'는 금지되어 있습니다. 특히 10^7을 곱하려고 할 때 특히 그렇습니다. 반면, 바이너리 검색은'O (log_2 (n))'입니다. 10^12의 기본 2 로그는 약 40입니다. 10^12가 아닌 40 단계의 검색이 250 억의 속도 향상입니다. 며칠 또는 몇 시간이 걸리지 않습니다. 몇 분이면 충분합니다. –