Методы маскирования в R

Этот вопрос, и в частности этот ответ поднял следующий вопрос: как я могу получить предупреждение о маскировке методов в R?

Если вы запустите следующий код в чистом сеансе R, вы заметите, что загрузка dplyr изменяет метод по умолчанию для lag.

lag(1:3, 1)
## [1] 1 2 3
## attr(,"tsp")
## [1] 0 2 1
require(dplyr)
lag(1:3, 1)
## [1] NA  1  2

Если вы прикрепляете пакет dplyr, вы получаете предупреждения для нескольких объектов с маскировкой, но никаких предупреждений о методе по умолчанию для lag не отображается. Причина в том, что при вызове lag вызывается общая функция из пакета stats.

lag
## function (x, ...) 
## UseMethod("lag")
## <bytecode: 0x000000000c072188>
## <environment: namespace:stats>

И methods(lag) просто говорит мне, что существует метод lag.default. Я вижу, что есть два метода, использующих getAnywhere:

getAnywhere(lag.default)
## 2 differing objects matching ‘lag.default’ were found
## in the following places
## registered S3 method for lag from namespace dplyr
## namespace:dplyr
## namespace:stats
## Use [] to view one of them

Но для этого требуется, чтобы я знал, чтобы проверить, был ли метод lag по умолчанию изменен на dplyr. Есть ли способ проверить, маскированы ли методы? Возможно, есть такая функция:

checkMethodMasking(dplyr)
## The following methods are masked from 'package:dplyr':
##    lag.default

Примечание. Недостаточно иметь предупреждение при загрузке dplyr с помощью require(dplyr). Метод также перегружается, если я просто загружаю пространство имен без присоединения пакета (например, я вызываю dplyr::mutate, или даже использую функцию из другого пакета, который вызывает функцию dplyr, которая была импортирована с помощью importFrom)).

Ответы

Ответ 1

Обновление Теперь на github появился пакет R, который пытается решить эти проблемы. Это еще далеко не идеальное решение, но оно идет в сторону решения проблемы. В настоящее время он имеет функции require, library и warnS3Methods.

devtools::install_github("blasern/warnS3")
require(warnS3)

# Examples
require2(dplyr)
## Loading required package: dplyr
##
## Attaching package: ‘dplyr’
##
## The following object is masked from ‘package:stats’:
##  
##  filter
##
## The following objects are masked from ‘package:base’:
##   
##  intersect, setdiff, setequal, union
## 
## The following methods are masked by 'package:dplyr':
##  
##  'lag.default' from 'package:stats'

require2(roxygen2)
## Loading required package: roxygen2
## The following methods are masked by 'package:roxygen2':
##  
##  'escape.character' from 'package:dplyr'

warnS3Methods()
## The following methods are available in multiple packages: 
##  
##  'escape.character' in packages: dplyr, roxygen2
##  'lag.default' in packages: dplyr, stats

Это только идея о том, как можно найти маскированные методы S3. Это ни в коем случае не идеальное решение, но я думаю, пока кто-нибудь придумает лучшую идею, это, по крайней мере, поможет в отладке.

#' Get all S3 methods from a package
#' 
#' Find all S3 methods from a package
#' 
#' @param pkg can be either the name of an installed package
#' or the path of a package
getPkgS3Methods <- function(pkg){
  if (basename(pkg) == pkg) pkg <- path.package(pkg)
  ns <- parseNamespaceFile(basename(pkg), 
                           dirname(pkg), 
                           mustExist = FALSE)
  if (length(ns$S3methods) == 0) return(NULL)
  df <- cbind.data.frame(basename(pkg), ns$S3methods)
  colnames(df) <- c("package", "method", "class", "other")
  df
}

#' Get masked S3 methods
#' 
#' Finds all S3 methods that are currently available that are
#' duplicated
getMaskedS3Methods <- function(){
  paths <- as.character(gtools::loadedPackages(silent = TRUE)[, "Path"])
  lst <- lapply(paths, getPkgS3Methods)
  all_methods <- do.call(rbind, lst)
  duplicates <- 
  duplicated(all_methods[, c("method", "class")]) |
    duplicated(all_methods[, c("method", "class")], fromLast = TRUE)
  res <- all_methods[duplicates, ]
  res[order(res$method, res$class, res$package), ]
}

Вызывается из чистой рабочей области (с указанными выше функциями, но без пакетов), вы можете наблюдать следующее:

getMaskedS3Methods()
## [1] package method  class   other  
## <0 rows> (or 0-length row.names)

require(dplyr)
getMaskedS3Methods()
## package method   class other
## 143   dplyr    lag default  <NA>
## 438   stats    lag default  <NA>

Это просто говорит вам, что здесь два метода lag.default. На самом деле это не говорит вам, какой из них маскирует другой. Это просто указывает на потенциальные проблемы.