重新定义矩阵的%in%

时间:2015-07-17 20:51:27

标签: r matrix

我喜欢能够使用==|等运算符在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%返回矩阵?

2 个答案:

答案 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)时会发生什么:

  1. 执行%in%函数,该函数定义为function(x, table) match(x, table, nomatch = 0L) > 0L
  2. 该函数需要找到match函数,因此它首先在其作为函数调用的一部分创建的本地环境中进行搜索。那里没有定义match
  3. 寻找match的下一个地方是该函数的封闭环境。我们可以弄明白这是什么:
  4. environment(`%in%`)
    # <environment: namespace:base>
    
    1. 由于match的原始版本(不是用户定义的版本)在namespace:base中定义,因此这是被调用函数的版本。
    2. 要让%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 之类的东西来避免所有这些问题。