在 R 中使用 switch() 替换向量值
Posted
技术标签:
【中文标题】在 R 中使用 switch() 替换向量值【英文标题】:Use of switch() in R to replace vector values 【发布时间】:2015-09-18 08:28:09 【问题描述】:这应该很简单,但即使在检查了所有文档和在线示例之后,我还是不明白。
我想使用 switch() 来替换字符向量的值。
一个虚假的、极其简单的、可重现的例子:
test<-c("He is", "She has", "He has", "She is")
假设我想将“1”分配给包括动词“to be”在内的句子,将“2”分配给包括动词“to have”的句子。以下方法不起作用:
test<-switch(test,
"He is"=1,
"She is"=1,
"He has"=2,
"She has"=2)
错误信息:
+ + + + Error in switch(test, `He is` = 1, `She is` = 1, `He has` = 2, `She has` = 2) :
EXPR must be a length 1 vector
我认为EXPR确实是一个长度为1的向量,那么有什么问题?
我认为也许 R 期望字符作为替换,但既没有将 switch() 包装成“as.integer”,也没有以下工作:
test<-switch(test,
"He is"="1",
"She is"="1",
"He has"="2",
"She has"="2")
也许它没有矢量化,我应该做一个循环?是这样吗?会令人失望,考虑到 R 的优势在于矢量化。提前致谢!
【问题讨论】:
向量“测试”的长度为 4。它不能工作。见test <- "He is"
。
你想达到这个目的code <- c("He is"=1, "She is"=1, "He has"=2, "She has"=2); code[test]
?
哇@ExperimenteR,这很优雅...我不知道如果我使用字符选择具有名称属性的数字向量的对象,R 将使用名称属性来匹配数字的数值向量到我的字符向量。这是我最喜欢的解决方案,但我不能选择它作为答案,因为问题是如何正确使用 switch()。竖起大拇指
【参考方案1】:
这是矢量化函数的正确方法,例如切换:
# Data vector:
test <- c("He is",
"She has",
"He has",
"She is")
# Vectorized SWITCH:
foo <- Vectorize(vectorize.args = "a",
FUN = function(a)
switch(as.character(a),
"He is" = 1,
"She is" = 1,
"He has" = 2,
2))
# Result:
foo(a = test)
He is She has He has She is
1 2 2 1
我希望这会有所帮助。
【讨论】:
【参考方案2】:你可以试试
test_out <- sapply(seq_along(test), function(x) switch(test[x],
"He is"=1,
"She is"=1,
"He has"=2,
"She has"=2))
或者等价
test_out <- sapply(test, switch,
"He is"=1,
"She is"=1,
"He has"=2,
"She has"=2)
【讨论】:
这似乎是解决方案,谢谢,实际上以更简单的形式,其中“test”是 sapply 的对象 对不起,另一个答案包括对问题背后概念的广泛解释。但我保证,只要我的声誉在几周内允许,我会立即为你投票。【参考方案3】:if
的矢量化形式是ifelse
:
test <- ifelse(test == "He is", 1,
ifelse(test == "She is", 1,
ifelse(test == "He has", 2,
2)))
或
test <- ifelse(test %in% c("He is", "She is"), 1, 2)
switch
基本上是一种编写嵌套if
-else
测试的方式。您应该将if
和switch
视为控制流 语句,而不是数据转换运算符。您可以使用它们来控制算法的执行,例如测试收敛性或选择要采用的执行路径。在大多数情况下,您不会使用它们直接操作数据。
【讨论】:
【参考方案4】:我发现这种方法最易读:
# input
test <-c("He is", "She has", "He has", "She is", "Unknown", "She is")
# mapping
map <- c(
"He is" = 1,
"She has" = 2,
"He has" = 2,
"She is" = 1)
answer <- map[test]
# output
answer
He is She has He has She is <NA> She is
1 2 2 1 NA 1
如果test
是数字,则必须将值转换为character
才能使用它。
【讨论】:
【参考方案5】:虽然我通常更喜欢基本 R 方法,但有一个带有矢量化开关功能的包。
library(broman)
switchv(c("horse", "fish", "cat", "bug"),
horse="fast",
cat="cute",
"what?")
根据评论添加以使用 OP 数据。
library(broman)
test<-c("He is", "She has", "He has", "She is")
test<-switchv(test,
"He is"="1",
"She is"="1",
"He has"="2",
"She has"="2")
test
【讨论】:
【参考方案6】:“Vectorize”基于“mapply”函数,而“ifelse”是一个应该已经向量化的基本函数。因此,就性能而言,“矢量化”可能会更慢。 使用“apply”系列对 R 函数进行矢量化很容易,但性能通常是大容量的问题。最好使用经过优化以处理向量的基函数。
【讨论】:
【参考方案7】:这是来自car
的recode()
的解决方案:
# Data vector:
x <- c("He is", "She has", "He has", "She is")
library("car")
recode(x, "'He is'=1; 'She is'=1; 'He has'=2; 'She has'=2") # or
recode(x, "c('He is', 'She is')=1; c('He has', 'She has')=2")
【讨论】:
在这里提一下:recode
也在 dplyr
包中。【参考方案8】:
CRAN 上的包kit
有一个用C 语言编写的向量化开关函数vswitch
。您可能还想知道它有一个名为 nif
的嵌套 if 函数和一个名为 iif
的快速 ifelse
函数。请查看文档,这些功能与基础 R 相比非常快。
【讨论】:
【参考方案9】:只是为了好玩:
vSwitch <- function(vExpr,...)
l <- list(...)
if(names(l)[[length(l)]] != '') stop('Last item in match list must be unnamed')
i <- 0
recurse <- function(v)
i <<- i + 1
if(names(l[i+1]) != "")
ifelse(v == names(l)[[i]],l[[i]], recurse(v))
else
ifelse(v == names(l)[[i]],l[[i]], l[[i+1]])
recurse(vExpr)
【讨论】:
【参考方案10】:您可以使用命名向量和简单的基本子集方法。例如
test <- c("He is", "She has", "He has", "She is")
named_vec <- c(
"He is" = 1,
"She is" = 1,
"He has" = 2,
"She has" = 2
)
named_vec[test]
#> He is She has He has She is
#> 1 2 2 1
由reprex package (v0.3.0) 于 2020 年 4 月 11 日创建
【讨论】:
【参考方案11】:使用purrr
包的花哨和整洁的方式是这样的:
purrr::map_int(c("He is", "She has", "He has", "She had", "She is", NA),
~ purrr::when(.,
.x %in% c("He is", "She is") ~ 1L,
.x %in% c("He has", "She has") ~ 2L,
~ NA))
这里,purrr::map()
迭代第一个参数并返回第二个参数返回的任何值。第二个参数是一个函数,其中purrr
允许以一种不太复杂的方式编写它:而不是编写function(x) x
,可以简单地编写~ .
、~ .x
或~ .1
(最后一个工作无限变量数)。
然后,我们得到了purrr::when()
,它采用单个值并作为一系列ifelse
语句起作用。这些语句采用LHS ~ RHS
的形式。 LHS应该是一个逻辑表达式,它也可以使用与上面相同的引用变量的方式; RHS 是与此条件关联的值。返回的值是第一个适合的值。当 LHS 为空时(如最后一行),则将其视为else
子句。
purrr::map_int()
与purrr::map()
的不同之处仅在于它保证返回整数向量(对于数字、逻辑和字符串也有类似的函数)。
【讨论】:
以上是关于在 R 中使用 switch() 替换向量值的主要内容,如果未能解决你的问题,请参考以下文章