【问题标题】:Replace values by lookup table通过查找表替换值
【发布时间】:2015-08-19 19:42:03
【问题描述】:

很长一段时间以来,我使用类似于以下的代码来根据“查找”表中的匹配替换向量中的值。在此示例中,如果 input 对象中的值与 key 的第二列中的任何值匹配,我将用 key 对象中的相应值替换它们。

key<-cbind(c("one","one","two","three","four","five"),c("one1","one11","two2","three3","over","over"))

input<-c("one1","one11","three","four","five")

input[which(!is.na(match(key[,2],input)))]<-key[!is.na(match(key[,2],input)),1]

有没有更有效的方法来实现这一点? merge 函数似乎不起作用。当keyinput 之间没有一对一匹配时,方法here 不起作用。

【问题讨论】:

  • 一个更好的方法是使用像dplyr::left_join这样的连接

标签: r


【解决方案1】:

您的代码不太正确:

  • 请注意,LHS 索引中的match(key[, 2], input) 的长度为6(key 的长度)而不是5(input 的长度),因此!is.na() 的长度为6 而不是5,而which(!is.na())key 的索引,而不是input 的索引。
  • 您还失去了比赛的顺序。通过在右侧使用!is.na()(它在您的示例中有效,因为key 的行恰好与input 中要替换的事物的索引相同,并且顺序相同)。

作为一个说明性示例,让我们将您的 key 洗牌

key <- key[c(3,2,4,5,6,1), ]
input[which(!is.na(match(key[,2],input)))]<-key[!is.na(match(key[,2],input)),1]
input
[1] "one1"  "one"   "three" "four"  "five"  "one"  

注意您的新 input 现在有 6 个变量,而第一个 one1 没有被替换。查看match(key[,2], input)is.na(...)which(is.na(...)) 了解原因。

input[i]key 匹配时,您需要使用非NA 的match(input, key[,2]),并且索引的值在key 中。所以现在你可以在 LHS 上使用!is.na() 来做分配,但不要在右边使用!is.na(),否则你会丢失key 中的匹配索引。

m <- match(input, key[,2]) # 6 2 NA NA NA for the shuffled `key`
input[!is.na(m)] <- key[na.omit(m), 1]

# or a one-liner
input[!is.na(match(input, key[,2]))] <- key[na.omit(match(input, key[,2])), 1]

就“更高效”而言,我认为这已经差不多了——merge 在内部调用match,所以肯定会更慢。它并不“优雅”,但速度很快。

我看到的唯一改进是先存储匹配项(就像我在上面所做的那样,将匹配项存储在 m 中)以避免调用它两次。

【讨论】:

  • 感谢na.omit 的提示。我的主要问题是,在阅读代码时很难一眼看出这些行发生了什么。
  • 是的,我同意,回读时很难说出发生了什么。这就是为什么我在做这类事情时通常会选择双线,当有很多match(..) 进行时,我也倾向于发表大量评论。
猜你喜欢
  • 2016-09-06
  • 1970-01-01
  • 1970-01-01
  • 2017-07-01
  • 1970-01-01
  • 2018-07-26
  • 1970-01-01
  • 2012-02-12
  • 1970-01-01
相关资源
最近更新 更多