dplyr变量列,其外部列表中的值最近

时间:2018-11-16 20:57:41

标签: r dplyr match

我正在尝试对一列进行突变,如果出现匹配项,则使用列表中的精确匹配项填充它;如果没有,则使用最接近的匹配项。

我的数据框如下:

index <- seq(1, 10, 1)
blockID <- c(100, 120, 132, 133, 201, 207, 210, 238, 240, 256)
df <- as.data.frame(cbind(index, blockID))

   index blockID
1      1     100
2      2     120
3      3     132
4      4     133
5      5     201
6      6     207
7      7     210
8      8     238
9      9     240
10    10     256

我想mutate新建一列,以检查blockID是否在列表中。如果是,则应仅保留blockID的值。如果不是,则应返回blocklist中最接近的值:

blocklist <- c(100, 120, 130, 150, 201, 205, 210, 238, 240, 256) 

因此其他列应包含

100 (match), 
120 (match), 
130 (no match for 132--nearest value is 130), 
130 (no match for 133--nearest value is 130), 
201, 
205 (no match for 207--nearest value is 205), 
210, 
238, 
240, 
256 

这是我尝试过的:

df2 <- df %>% mutate(blockmatch = ifelse(blockID %in% blocklist, blockID, ifelse(match.closest(blockID, blocklist, tolerance = Inf), "missing")))

我只是输入"missing"来完成ifelse()语句,但是实际上不应在任何地方返回它,因为上述情况会为blockID的每个值都满足。但是,生成的df2在所有应替换最接近的数字的单元格中都只是“丢失”。我知道match.closest有基本的R替代方法,但是我不确定这是问题所在。有任何想法吗?

1 个答案:

答案 0 :(得分:2)

您不需要if..else。通过说与blocklist相比,我们总是得到{strong> 最小绝对差blockID元素可以简化您的规则。如果值匹配,则绝对差为0(将始终为最小)。

有了这,这是一个简单的基础R解决方案-

df$blockmatch <- sapply(df$blockID, function(x) blocklist[order(abs(x - blocklist))][1])

   index blockID blockmatch
1      1     100        100
2      2     120        120
3      3     132        130
4      4     133        130
5      5     201        201
6      6     207        205
7      7     210        210
8      8     238        238
9      9     240        240
10    10     256        256

dplyr的几种方法-

df %>% 
  rowwise() %>% 
  mutate(
    blockmatch = blocklist[order(abs(blockID - blocklist))][1]
  )

df %>% 
  mutate(
    blockmatch = sapply(blockID, function(x) blocklist[order(abs(x - blocklist))][1])
  )

感谢@Onyambu,这是一种更快的方法-

df$blockmatch <- blocklist[max.col(-abs(sapply(blocklist, '-', df$blockID)))]