不使用data.frame的数值的透明查找表?

时间:2019-03-04 20:11:28

标签: r

Advanced R dicusses the idea of using character subsetting for lookup tables.

x <- c("m", "f", "u", "f", "f", "m", "m")
lookup <- c(m = "Male", f = "Female", u = NA)
lookup[x]
#>        m        f        u        f        f        m        m 
#>   "Male" "Female"       NA "Female" "Female"   "Male"   "Male"

reprex package(v0.2.1)于2019-03-04创建

但是,这种想法不适用于数字查询,因为names是特殊属性,必须是 character 向量。

什么是不需要data.frame的数字查找的简单等效解决方案?

我想避免使用data.frame解决方案,因为键和值之间的映射仅基于顺序,而不是更加透明的3 = 'Excellent', 2 = 'Good', 1 = 'Poor'


字符查找表后面的段落建议使用data.frame的解决方案。

grades <- c(1, 2, 2, 3, 1)

info <- data.frame(
  grade = 3:1,
  desc = c("Excellent", "Good", "Poor"),
  fail = c(F, F, T)
)

info[grades, 'desc']
#> [1] Excellent Good      Good      Poor      Excellent
#> Levels: Excellent Good Poor

reprex package(v0.2.1)于2019-03-04创建

3 个答案:

答案 0 :(得分:2)

如果键只能是正整数,则可以使用Soren在他们对以下问题的答案中建议的索引值:https://stackoverflow.com/a/54990917


如果没有,您仍然可以使用上述基于names的策略,将数字作为字符存储在names(lookup)中,然后使用as.character将数字键的向量转换为正确的匹配形式:

y <- c(1, -2, 1.3, -5)
lookup_num <- c('1' = 'Cat', '-2' = 'Dog', '1.3' = 'Fish', '-5' = 'Hedgehog')
lookup_num[as.character(y)]
         1         -2        1.3         -5 
     "Cat"      "Dog"     "Fish" "Hedgehog" 

此方法的一个缺点是,由于数字将作为字符串处理,因此无法正确地将0.0与0匹配,或将3.00与3匹配,因此您需要确保数字值是干净的


如果性能不是很重要,则可以反转键和值的顺序,将数字键作为值,并将字符查找值作为名称,然后使用sapply查找每个键:

lookup_num <- c('Cat' = 1, 'Dog' = -2, 'Fish' = 1.3, 'Hedgehog' = -5)
keys <- c(-2, 1.3, -2, 1)
sapply(keys, function(x) which(lookup_num == x))
 Dog Fish  Dog  Cat 
   2    3    2    1 

这具有使用数字匹配的优势,它可以抵抗由可变数字格式引起的问题,并为您提供很大的灵活性(例如,您可以执行以下操作:abs(lookup_num - x) < 0.1在您的空间中添加摆动空间数字匹配)

缺点是时间复杂度很差,但是如果键和/或查找表的列表不多,您根本不会注意到。

答案 1 :(得分:1)

您可以考虑改用查找功能。例如,以下是一个简单的辅助函数,可以为您创建一个查找函数:

create.lookup = function(name, value) {
  function(lookup.name) value[match(lookup.name, name)]
}

使用此示例:

grades <- c(1, 2, 2, 3, 1)
lookup = create.lookup(c(3, 2, 1), c("Excellent", "Good", "Poor"))
lookup(grades)
# [1] "Poor"      "Good"      "Good"      "Excellent" "Poor"     

还可以使用负值和非整数值

grades <- c(2, 1.1, 2, -3, 1.1)
lookup = create.lookup(c(1.1, 2, -3), c("Excellent", "Good", "Poor"))
lookup(grades)
# [1] "Good"      "Excellent" "Good"      "Poor"      "Excellent"

即使数字写的不同,它仍然有效

grades <- c(2.000, 1.10, 2, -3e0, 001.1)
lookup(grades)
# [1] "Good"      "Excellent" "Good"      "Poor"      "Excellent"

作为补充,相同的方法也适用于字符类型查找,从而为各种用例提供​​了一种单一方法

grades <- c('p', 'g', 'g', 'e', 'p')
lookup = create.lookup(c('e', 'g', 'p'), c("Excellent", "Good", "Poor"))
lookup(grades)
# [1] "Poor"      "Good"      "Good"      "Excellent" "Poor"     

答案 2 :(得分:0)

您可以将数字值分配给列表中的索引,并分配列表索引中的值。使用数字索引(等级),您可以按以下方式查找值:

lookups <- list()
lookups[[1]] <- "Excellent"
lookups[[2]] <- "Good"
lookups[[3]] <- "Fair"
lookups[[4]] <- "Poor"
lookups[[5]] <- "Fail"

grades <- c(1, 2, 2, 3, 1)
lookups[grades]

这会产生成绩类别:

> lookups[grades]
[[1]]
[1] "Excellent"

[[2]]
[1] "Good"

[[3]]
[1] "Good"

[[4]]
[1] "Fair"

[[5]]
[1] "Excellent"

或者进一步简化为命名向量:

grades <- c(1, 2, 2, 3, 1)
lookups[grades]

setNames(grades,unlist(lookups[grades]))

收益:

> setNames(grades,unlist(lookups[grades]))
Excellent      Good      Good      Fair Excellent 
        1         2         2         3         1