2017-10-23 8 views
5

각 처리 된 관측치에 가장 가까운 값을 찾으려고합니다. (1.2M OBS에서 부분 데이터)는 다음과 같이 데이터를 보면 각 처리 관측data.table에서 가장 가까운 값을 찾으십시오.

> dta 
    id treatment  score 
1: 5   0 0.02381024 
2: 10   0 0.05428605 
3: 22   0 0.02118124 
4: 27   0 0.01495214 
5: 45   0 0.01877916 
6: 50   0 0.02120360 
7: 58   0 0.02207263 
8: 60   0 0.02807019 
9: 61   0 0.05432927 
10: 65   1 0.59612077 
11: 68   0 0.02482168 
12: 72   1 0.14582400 
13: 73   0 0.02371670 
14: 77   0 0.02608826 
15: 87   0 0.06852409 
16: 88   0 0.07473471 
17: 94   0 0.07160314 
18: 97   0 0.02040747 
19: 104   1 0.09878789 
20: 108   0 0.02421807 

(즉, 치료 = 1) 내가 치료 관찰을 좀하고 싶습니다 (즉, 치료 = 0)와 가장 가까운 스코어 및 다른 관측 된 관측치와 비교할 수없는 것으로 선택된 관측치를 표시합니다.

예를 들어 첫 번째 처리 된 관찰 (행 10)은 id = 88 (행 16), 12 행에서 17 행 등과 일치합니다. 현재 floowing 루프를 실행 중입니다.

smpl_treated = dta[treatment == 1] 
smpl_untreated = dta[treatment == 0] 

n_tmp = nrow(smpl_treated) 
matched_id = matrix(0, n_tmp, 1) 

smpl_tmp = smpl_untreated 

for (i in 1:nrow(smpl_treated)) { 

    x = smpl_treated[i]$score 

    setkey(smpl_tmp, score) 
    tmp = smpl_tmp[J(x), roll = "nearest"] 
    matched_id[i] = tmp[[1]] 
    smpl_tmp = smpl_tmp[id != tmp[[1]]] 

} 

matched_smpl = smpl_untreated[id %in% matched_id] 

> matched_smpl 
    id treatment  score 
1: 87   0 0.06852409 
2: 94   0 0.07160314 
3: 88   0 0.07473471 

이 문제를 data.table 내에서 발생 시키거나 루프를 빠르게하려면 어떤 제안이 필요합니까? 원래 1.2M의 obs 루프 2 시간 이상 걸립니다. 미리 도움을 주셔서 감사합니다!

+0

다음과 같은 5 개 샘플을 가지고 가정 : {(ID = 1, 치료 = 0, 점수 = 0), (ID = 2 , 치료 = 1, 점수 = 0.1), (ID = 3, 치료 = 1, 점수 = 0.2), (ID = 4, 치료 = 1, 점수 = 0.3))}. 다른 말로하면 두 개의 치료되지 않은 관찰 사이에 3 개의 치료 된 관찰이 있습니다. 이 경우 무엇이 무엇에 매핑됩니까? – Ben

+0

내 맥락에서, 그것은 일어나지 않을 것입니다. 그러나 그것이 일어난다면, 아마도 나는 그 반대를 해봐야합니다 - 이것의 주요 목적은 치료되고 치료되지 않은 관찰의 균형 잡힌 표본을 얻는 것입니다. – jayc

답변

1

이것은을 사용하여 the already accepted answer of denis을 부연 (I 달리 직접 간단한 솔루션을 볼 수 없습니다) 비 처리 된 것보다 더 높은 점수를 처리 사람 만 제안 된 솔루션을 사용하는 조건을 추가하고, 그렇지 않으면 나머지를 할 수 실제 가능성은 data.table입니다. 예를 들어 합류 할 때 setkey() 대신 on 매개 변수를 사용하십시오.

# determine the minimum number of treated and untreated cases 
n <- min(dta[treatment == 0L, .N], dta[treatment == 1L, .N]) 
# order by descending score 
mdt <- dta[order(-score)][ 
    # and pick the ids of the top n treated and untreated cases 
    # so that the highest untreated score match the highest treated score, 
    # the 2nd highest untreated the 2nd highest treated and so forth 
    , .(id0 = head(.SD[treatment == 0L, id], n), id1 = head(.SD[treatment == 1L, id], n))] 
mdt 
id0 id1 
1: 88 65 
2: 94 72 
3: 87 104 
# join the ids two times to show the data of the treated and untreated cases 
dta[dta[mdt, on = .(id==id0)], on = .(id = id1)] 
id treatment  score i.id i.treatment i.score 
1: 65   1 0.59612077 88   0 0.07473471 
2: 72   1 0.14582400 94   0 0.07160314 
3: 104   1 0.09878789 87   0 0.06852409 
+0

이 솔루션은 내 것보다 훨씬 낫고 실제 업무를 수행합니다 (치료 및 비 치료 데이터가 다른 점수 범위를 갖는 것은 아닙니다). 공유 해 주셔서 감사합니다. – denis

+0

@denis 좋은 코멘트를 주셔서 감사합니다. 그러나 귀사의 솔루션은 올바른 방향으로 나아갔습니다! – Uwe

1

데이터 테이블을 주문하고 하위 집합을 만들고 병합 기능을 사용하면 해결책이 될 수 있습니다. 는 확실하지가 최선의 해결책이지만, 난 당신이 원하는 이해 무엇을 위해 일할 것, 그리고 더 빨리 루프보다 더 확실 할 것이다 : 여기

library(data.table) 
dta <- data.table(id = c(5,10,22,27,45,50,58,60,61,65,68,72,73,77,87,88,94,97,104,108), 
        treatment = c(0, 0 ,0 ,0, 0, 0, 0 ,0 , 0 , 1, 0 ,1 ,0, 0 ,0 ,0 ,0 ,0 ,1 ,0), 
        score = c(0.02381024, 0.05428605, 0.02118124, 0.01495214, 0.01877916, 0.02120360, 
          0.02207263, 0.02807019, 0.05432927, 0.59612077, 0.02482168, 0.14582400, 
          0.02371670, 0.02608826, 0.06852409, 0.07473471, 0.07160314, 0.02040747, 
          0.09878789, 0.02421807)) 

setkey(dta, score) # order by score 
treated_nbr <- dta[treatment == 1, .N] # just to simplify the next line 

selecteddata <- 
    dta[treatment == 0, 
     .SD[(.N - treated_nbr + 1):.N, 
      .(correspid = id, 
      correspscore = score, 
      id = dta[treatment == 1, id])]] 

우리가 아닌 주문의 같은 번호를 가지고 그래서 치료 사람 (.N-treated_nbr+1):.N) 그들은 명령 하나에 가장 가까운 점수를 가지고, 우리는 내가 때문에, 처리 한 (id = dta[,.SD[treatment == 1,id]])

setkey(selecteddata, id) 
setkey(dta, id) 
selecteddata[dta] # do the merging 

가 확실하지 당신이 원하는 것을 정확히의 ID에 ID를 병합 당신의 치료 점수가 치료받지 않은 점수보다 높을 때만 효과가 있다는 것을 깨달았습니다. 당신은

+0

덕분에 데니스! – jayc