我喜欢能够使用==
和|
等运算符在R中的矩阵元素中进行操作:
(m <- matrix(1:4, nrow=2))
# [,1] [,2]
# [1,] 1 3
# [2,] 2 4
m == 2 | m == 3
# [,1] [,2]
# [1,] FALSE TRUE
# [2,] TRUE FALSE
不幸的是,%in%
没有同样好的行为,并返回一个向量而不是矩阵:
m %in% c(2, 3)
# [1] FALSE TRUE TRUE FALSE
注意到%in%
被定义为function(x, table) match(x, table, nomatch = 0L) > 0L
,我想我可以重新定义match
以获得我想要的行为:
match <- function(x, table, nomatch = NA_integer_, incomparables = NULL) {
m <- base:::match(x, table, nomatch, incomparables)
if (is.matrix(x)) matrix(m, nrow(x))
else m
}
虽然如果我明确地致电match
,这确实有效,但在运行m %in% c(2, 3)
时我仍然无法获得所需的结果:
match(m, c(2, 3), nomatch=0L) > 0L
# [,1] [,2]
# [1,] FALSE TRUE
# [2,] TRUE FALSE
m %in% c(2, 3)
# [1] FALSE TRUE TRUE FALSE
为什么现在没有%in%
返回矩阵?
答案 0 :(得分:3)
我不确定为什么你的尝试没有用,但我想%in%
无论你重新定义base:::match
都会match
使用%in%
。但为什么不重新定义`%in%` <- function(x, table) {
m <- base::match(x, table, nomatch = 0L) > 0L
if (is.matrix(x)) matrix(m, nrow(x))
else m
}
m <- matrix(1:4, nrow=2)
m %in% c(2, 3)
# [,1] [,2]
# [1,] FALSE TRUE
# [2,] TRUE FALSE
本身?
%inm%
正如评论中所建议的那样,通常在良好做法方面,使用其他名称会更安全,例如%min%
或{{1}}。
答案 1 :(得分:3)
感谢@joran指点我this excellent article,其中向我澄清了为什么%in%
没有使用我新定义的match
函数。以下是我对正在发生的事情的理解:
用户定义的match
函数存储在全局环境中,而原始match
函数仍存储在namespace:base
中:
environment(match)
# <environment: R_GlobalEnv>
environment(base::match)
# <environment: namespace:base>
现在,考虑一下当我致电m %in% c(2, 3)
时会发生什么:
%in%
函数,该函数定义为function(x, table) match(x, table, nomatch = 0L) > 0L
。match
函数,因此它首先在其作为函数调用的一部分创建的本地环境中进行搜索。那里没有定义match
。match
的下一个地方是该函数的封闭环境。我们可以弄明白这是什么:
environment(`%in%`)
# <environment: namespace:base>
match
的原始版本(不是用户定义的版本)在namespace:base
中定义,因此这是被调用函数的版本。要让%in%
的矩阵版本生效,最简单的方法是遵循@Molx的建议并重新定义%in%
,以便将其存储在全局环境中(请注意, #39;仍然是namespace:base
)中函数的相同版本:
`%in%` <- function(x, table) match(x, table, nomatch = 0L) > 0L
environment(`%in%`)
# <environment: R_GlobalEnv>
现在m %in% c(2, 3)
将首先在其本地函数环境中搜索match
函数,然后在封闭环境(R_GlobalEnv
)中查找{{1}的用户定义版本功能:
match
我们可以让m %in% c(2, 3)
# [,1] [,2]
# [1,] FALSE TRUE
# [2,] TRUE FALSE
使用用户定义的%in%
函数的另一种方法是将match
的封闭环境更改为全局环境:
base::"%in%"
正如评论者对@ Molx的回答所提到的,最明智的做法是通过将我的新函数命名为rm(`%in%`) # Remove user-defined %in%
environment(`%in%`) <- .GlobalEnv # Can be reversed with environment(`%in%`) <- asNamespace("base")
m %in% c(2, 3)
# [,1] [,2]
# [1,] FALSE TRUE
# [2,] TRUE FALSE
之类的东西来避免所有这些问题。