为什么 R 的 sapply 和 switch 函数将字符值视为函数?

Aub*_*der 5 r switch-statement sapply

我正在尝试使用 sapply 和 switch 将描述性名称应用于数据。我已经多次使用这种方法,没有出现任何问题,但对于我最近的项目中的(只有一个!)专栏,它抛出了错误。我最好的猜测是,即使该值保存为字符串,该值也将是 R 中的保留字。我在下面创建了一个可重现的示例。

我的项目中的实际值与性别无关,并且可能有许多可能的选择。有人可以告诉我如何使用 sapply/switch 来避免代码中出现许多嵌套的 ifelse 语句吗?

# create test data
testdta <- as.data.frame(cbind(userid = c("1", "2", "3", "4"), gender = c("F", "M", "F", "M")))

# sapply/switch works with strings that are not reserved words
testdta$uiddescription <- sapply(testdta$userid, switch, "1" = "1 - first", "2" = "2 - second", "3+ - third or beyond")
testdta

# sapply/switch won't work when trying to interpret gender (possibly because F is reserved?)
testdta$gdescription <- sapply(testdta$gender, switch, "F" = "F - female", "M" = "M - male")
Run Code Online (Sandbox Code Playgroud)

我收到的错误是“get(as.character(FUN), mode = “function”, envir = envir) 中的错误:未找到模式“function”的对象“F - Female”。”

jor*_*ran 7

发生这种情况是因为sapply. 它将 读取"F" = FUN中的参数sapply。如果你明确并去做,FUN = switch它就会起作用。


r2e*_*ans 6

我认为@joran\的回答解决了为什么"F"会触发这个问题。

\n

然而......为此目的使用sapply/switch可能不是执行您正在做的事情的最有效方法(请参阅下面的基准以了解它们有多么不同)。

\n

字典查找

\n
vec <- c("F" = "F - female", "M" = "M - male")\nvec[testdta$gender]\n#            F            M            F            M \n# "F - female"   "M - male" "F - female"   "M - male" \n
Run Code Online (Sandbox Code Playgroud)\n

合并/加入

\n
genders <- data.frame(gender=c("F", "M"), gender2=c("F - female", "M - male"))\nmerge(testdta, genders, by="gender", all.x=TRUE)\n#   gender userid    gender2\n# 1      F      1 F - female\n# 2      F      3 F - female\n# 3      M      2   M - male\n# 4      M      4   M - male\n
Run Code Online (Sandbox Code Playgroud)\n

合并/连接的概念很棒,但如果您不熟悉,可能会变得很复杂,请参阅如何连接(合并)数据框(内部、外部、左、右)INNER JOIN、LEFT JOIN、RIGHT JOIN 和完全加入?, (data.table)使用 data.table 左连接

\n

基准

\n
bench::mark(\n  sapply = sapply(testdta$gender, FUN=switch, "F" = "F - female", "M" = "M - male"),\n  dict = vec[testdta$gender],\n  join = merge(testdta, genders, by="gender", all.x=TRUE),\n  check = FALSE)\n# # A tibble: 3 \xc3\x97 13\n#   expression      min   median `itr/sec` mem_alloc `gc/sec` n_itr  n_gc total_time result memory time                gc                   \n#   <bch:expr> <bch:tm> <bch:tm>     <dbl> <bch:byt>    <dbl> <int> <dbl>   <bch:tm> <list> <list> <list>              <list>               \n# 1 sapply       9.29\xc2\xb5s     11\xc2\xb5s    88949.        NA     8.90  9999     1    112.4ms <NULL> <NULL> <bench_tm [10,000]> <tibble [10,000 \xc3\x97 3]>\n# 2 dict         1.35\xc2\xb5s   1.48\xc2\xb5s   656398.        NA     0    10000     0     15.2ms <NULL> <NULL> <bench_tm [10,000]> <tibble [10,000 \xc3\x97 3]>\n# 3 join       165.12\xc2\xb5s 194.11\xc2\xb5s     5169.        NA     6.33  2450     3    473.9ms <NULL> <NULL> <bench_tm [2,453]>  <tibble [2,453 \xc3\x97 3]> \n
Run Code Online (Sandbox Code Playgroud)\n

一个易于直观使用的列是`itr/sec`或每秒迭代次数(越多越好)。

\n

当处理较大的数据时(4 行相当小),这会发生一些变化,但即使这真正代表了您的真实数据,它也会表现出明显的性能差异。

\n