查找的链接因素 - 这是最有效的方法吗?

Chaining factors for lookup - is this the most efficient way?

我有两个因素用作查找表:

iState <- list("A" = "Alaska", "T" = "Texas", "G" = "Georgia")    
sCap <- list("Alaska" = "Juneau", "Texas" = "Austin", "Georgia" = "Atlanta")

以及要查找的向量:

foo <- c("T", "G", "A", "B", NA)

此代码将它们链接在一起并提供我想要的查找:

sCap[iState[foo] %>% as.character() %>%  na_if("NULL") ] %>% as.character() %>%  na_if("NULL")
# [1] "Austin"  "Atlanta" "Juneau"  NA        NA      

这是将这些因素联系在一起的最节省执行时间的方法吗?或者有更好的方法吗?

它可能不是很快,尤其是因为使用了函数 %>%na_if()

我不确定这是否是最快的方法,但是如果您只是将 sCapiState 变成原子向量而不是列表(使用 c() 而不是 list()), 你可以很容易地得到你想要的:

iState <- c(A = "Alaska", T = "Texas", G = "Georgia")    
sCap <- c(Alaska = "Juneau", Texas = "Austin", Georgia = "Atlanta")
foo <- c("T", "G", "A", "B", NA)

sCap[iState[foo]]
#    Texas   Georgia    Alaska      <NA>      <NA> 
# "Austin" "Atlanta"  "Juneau"        NA        NA 

如果结果未命名对您很重要,您可以使用 unname():

unname(sCap[iState[foo]])

如果使用查找向量而不是查找列表,您可以做得更好。基本上,我把list改成c(),然后把as.character位全部删掉。

vState <- c("A" = "Alaska", "T" = "Texas", "G" = "Georgia")    
vCap <- c("Alaska" = "Juneau", "Texas" = "Austin", "Georgia" = "Atlanta")

vCap[vState[foo]]

到目前为止的基准测试方法:

microbenchmark::microbenchmark(
  recode = foo %>%
    dplyr::recode(!!!iState, .default = NA_character_) %>%
    dplyr::recode(!!!sCap, .default = NA_character_),
  lists = sCap[iState[foo] %>% as.character() %>%  na_if("NULL") ] %>% as.character() %>%  na_if("NULL"),
  lists_no_pipe = na_if(as.character(sCap[na_if(as.character(iState[foo]), "NULL")]), "NULL"),
  vectors = unname(vCap[vState[foo]])
)
# Unit: microseconds
#           expr   min     lq    mean median     uq   max neval
#         recode 227.1 244.05 305.203 268.05 319.55 591.1   100
#          lists 182.2 198.85 244.964 222.10 254.20 562.6   100
#  lists_no_pipe  11.4  13.25  17.726  15.45  18.70  64.5   100
#        vectors   2.5   3.85   5.269   4.90   6.40  12.9   100

如果您希望事情尽可能快,请不要使用 %>% - 这是额外的开销。如果您正在做复杂的事情,那么管道的额外微秒并不重要。但在这种情况下,正在完成的操作已经非常快,以至于几微秒的管道实际上占了执行时间的很大一部分。

您可以走得更快——尤其是如果您的查找表很大,可以改为使用键控 data.table 的连接。

有些人可能会觉得这很傻,但我喜欢 dplyr::recode:

foo %>%
  dplyr::recode(!!!iState, .default = NA_character_) %>%
  dplyr::recode(!!!sCap, .default = NA_character_)
[1] "Austin"  "Atlanta" "Juneau"  NA        NA       

它适用于列表或向量。