2017-10-23 71 views
5

Her tedavi edilen gözlem için en yakın değeri bulmaya çalışıyorum. (1.2 M atıl bir kısmi veriler) verileri aşağıdaki gibidir bak: muamele edilen her bir gözlem içinBir data.table içinde en yakın değeri bulma

> 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 

(yani, tedavi = 1), bir muamele edilmemiş bir gözlem almak istiyorum (yani, tedavi = 0) ile En yakın skoru seçin ve seçilen gözlemi eşleştirilecek diğer tedavi edilen gözlemler için uygun olmayan şekilde işaretleyin. Örneğin, ilk tedavi edilen gözlem (sıra 10), id = 88 (satır 16), satır 12 ila satır 17, vb. Ile eşleşecektir.

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 

herhangi bir öneriniz bu data.table içinde gerçekleşmesi veya daha hızlı döngü yapmak yapmak: Şu anda floowing döngü koşuyorum? Orijinal 1.2M obs ile, döngü 2 saatten fazla sürüyor. Yardımınız için şimdiden teşekkür ederiz!

+0

aşağıdaki 5 örnekleri olduğunu varsayalım: {(id = 1, tedavi = 0, skor = 0), (id = 2 , tedavi = 1, skor = 0.1), (id = 3, tedavi = 1, skor = 0.2), (id = 4, tedavi = 1, skor = 0.3), (id = 5, tedavi = 0, skor = 0.4))}. Başka bir deyişle, iki muamele görmemiş gözlem arasında sıkışmış 3 tedavi gözleminiz var. Bu durumda ne için haritalar? – Ben

+0

Bağlamda, bu olmayacak. Öyle olsa, muhtemelen, tam tersini yapmalıyım - bunun temel amacı, tedavi edilmiş ve tedavi edilmemiş gözlemlerin dengeli bir örneğini almaktır. – jayc

cevap

1

Bu kullanılarak the already accepted answer of denis ayrıntılandırdığı (başka türlü doğrudan basit bir çözüm görmüyorum) olmayan tedavi olanlara göre daha yüksek puana sahip muamele kişi için yalnızca önerilen çözümü kullanmak bir koşul ekleyin, aksi takdirde geri kalan yapabilirdi gerçek olasılıkları data.table sözdizimi, örneğin, parametresini, katılma sırasında setkey() yerine kullanın.

# 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

Bu çözüm benimkinden çok daha iyidir ve aslında işi yapar (tedavi ve tedavi dışı verilerin farklı puan aralığına sahip olduğunu varsaymaz). Paylaşımınız için teşekkürler – denis

+0

@denis Güzel yorumunuz için teşekkür ederiz. Ancak, çözümünüz doğru yöne işaret etti! – Uwe

1

Veri tablonuzu sipariş ederseniz, bir alt küme oluşturup birleştirmenin gücünü kullanırsanız bir çözümüm olabilir. Değil emin iyi çözümdür, ama ben yapmak istediğiniz anlaşılan şey için çalışmak gibi görünüyor, ve daha hızlı döngü daha kesin olacaktır: Burada

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])]] 

biz olmayan sipariş aynı sürede böylece işlenmiş kişi (.N-treated_nbr+1):.N) onlar sipariş birine yakın puanı var ve çünkü ben, tedavi biri (id = dta[,.SD[treatment == 1,id]])

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

değil emin ne istediğinizi tam olarak bir id id birleştirme Sadece tedavi edilen puanların tedavi edilmemiş olanlardan daha yüksek olması durumunda çalıştığını fark ettiniz (örneğinizde durum böyledir). Sen

+0

Bu çok yardımcı oluyor - teşekkürler, denis! – jayc