I may have a solution if you order your data table, compose a subset and use the merge feature. Not sure if this is the best solution, but it seems to work for me to understand what you want to do, and it will be exactly faster than your loop:
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)
here we take the same number of ordered .N-treated_nbr+1):.N persons ( .N-treated_nbr+1):.N ) so that they have the closest result to the ordered one, and we combine id with the identifier of the processed one ( id = dta[,.SD[treatment == 1,id]] )
setkey(selecteddata, id) setkey(dta, id) selecteddata[dta] # do the merging
Not sure if this is exactly what you want, because I realized that it only works if your processed points are higher than not processed (which is the case in your example). You can add a condition to use the solution offered only for the processed person with a bar higher than not processed ones, and do the rest otherwise (I do not see a direct simple solution otherwise)