我正在尝试对一列进行突变,如果出现匹配项,则使用列表中的精确匹配项填充它;如果没有,则使用最接近的匹配项。
我的数据框如下:
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替代方法,但是我不确定这是问题所在。有任何想法吗?
答案 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)))]