R 在data.table中查找最近的值

R 在data.table中查找最近的值,r,data.table,matching,R,Data.table,Matching,我试图为每一个处理过的观察值找到最近的值。数据如下(120万obs的部分数据): 对于每个治疗观察(即治疗=1),我希望得到一个未治疗的观察(即治疗=0),分数最接近,并将所选观察标记为其他治疗观察无法匹配 例如,第一次处理的观察(第10行)将与id=88(第16行)匹配,第12行与第17行匹配,依此类推。目前我正在运行floowing循环: smpl_treated = dta[treatment == 1] smpl_untreated = dta[treatment == 0] n_tm

我试图为每一个处理过的观察值找到最近的值。数据如下(120万obs的部分数据):

对于每个治疗观察(即治疗=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中实现这一点,或者加快循环速度?使用原来的120万obs,环路需要2个多小时。提前谢谢你的帮助

如果您对数据表进行排序,生成子集并使用合并功能,我可能会有一个解决方案。 不确定这是否是最好的解决方案,但它似乎符合我理解的您想要做的事情,而且它肯定会比您的循环更快:

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])]]
我不确定这正是你想要的,因为我意识到只有当你治疗的分数高于未治疗的分数时(在你的例子中就是这样),它才会起作用。 您可以添加一个条件,仅对得分高于未治疗者的治疗者使用建议的解决方案,其余的则使用其他方法(我看不到直接的简单解决方案)

这将使用
数据的实际可能性进行阐述。表
语法,例如。,加入时,请使用
参数上的
,而不是
setkey()

# 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

假设您有以下5个样本:{(id=1,治疗=0,得分=0),(id=2,治疗=1,得分=0.1),(id=3,治疗=1,得分=0.2),(id=4,治疗=1,得分=0.3),(id=5,治疗=0,得分=0.4)}。换句话说,您有3个经过处理的观察,夹在两个未经处理的观察之间。在这种情况下,什么映射到什么?在我的上下文中,它不会发生。然而,如果发生这种情况,我可能应该做相反的事情——这项工作的主要目的是获得一个经过处理和未经处理的观察结果的平衡样本。因此,这个解决方案比我的要好得多,并且实际起到了作用(它没有假设治疗和未治疗数据具有不同的评分范围)。谢谢你的帮助sharing@denis谢谢你的评论。然而,您的解决方案指向了正确的方向!
setkey(selecteddata, id)
setkey(dta, id)
selecteddata[dta] # do the merging
# 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