Методы маскировки в 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

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


person shadow    schedule 04.06.2015    source источник
comment
FWIW dplyr не переопределяет этот метод в следующей версии.   -  person hadley    schedule 05.06.2015


Ответы (2)


Пакет conflicted (см. здесь) теперь предлагает потенциальное решение этой проблемы. проблема. С загруженным conflicted вы получаете более явные сообщения об ошибках о конфликтующих именах функций. Вы также можете использовать conflict_prefer (подробности здесь), чтобы укажите, какую функцию пакета вы хотите использовать по умолчанию, а какую следует замаскировать.

Например, вот недавняя ошибка, которую я получил при попытке использовать функцию parallel из пакета nFactors:

# Error: [conflicted] `parallel` found in 2 packages.
# Either pick the one you want with `::` 
# * nFactors::parallel
# * lattice::parallel
# Or declare a preference with `conflict_prefer()`
# * conflict_prefer("parallel", "nFactors")
# * conflict_prefer("parallel", "lattice")

Затем я добавил

conflict_prefer("parallel", "nFactors") 

сразу после того, как код загружает мои библиотеки в начале скрипта, чтобы убедиться, что parallel вызовет nFactors::parallel в моем коде.

person ktur    schedule 21.02.2020

Обновление Теперь на 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. На самом деле это не говорит вам, какой из них маскирует другой. Он просто указывает на возможные проблемы.

person shadow    schedule 04.06.2015
comment
Я действительно не понимаю, почему был создан этот беспорядок, так много проблем из-за включения конфликтующих имен объектов автором (очень хорошо в остальном) пакета dplyr - person Qbik; 12.02.2017