R стиль записи - требуется vs.::
Хорошо, мы все знакомы с оператором двойной толпы в R. Когда я собираюсь написать какую-то функцию, я использую require(<pkgname>)
, но я всегда думал об использовании ::
. Использование require
в пользовательских функциях лучше, чем library
, поскольку require
возвращает предупреждение и FALSE
, в отличие от library
, который возвращает ошибку, если вы указываете имя несуществующего пакета.
С другой стороны, оператор ::
получает переменную из пакета, а require
загружает весь пакет (по крайней мере, я надеюсь, что так), поэтому на мой взгляд возникли различия в скорости. ::
должен быть быстрее, чем require
.
И я сделал некоторый анализ, чтобы проверить это - я написал две простые функции, которые загружают функцию read.systat
из пакета foreign
, с require
и ::
соответственно, поэтому импортируйте набор данных Iris.syd
, который корабли с пакетом foreign
, реплицированные функции 1000 раз каждый (что было бесстыдно произвольно) и... хрустели некоторые цифры.
Странно (или нет) я обнаружил существенные различия с точки зрения пользовательского процессора и прошедшего времени, тогда как существенных различий в системном процессоре не было. И еще более странный вывод: ::
на самом деле медленнее! Документация для ::
очень тупая, и, просто взглянув на источники, очевидно, что ::
должен работать лучше!
требуется
#!/usr/local/bin/r
## with require
fn1 <- function() {
require(foreign)
read.systat("Iris.syd", to.data.frame=TRUE)
}
## times
n <- 1e3
sink("require.txt")
print(t(replicate(n, system.time(fn1()))))
sink()
двойной двоеточие
#!/usr/local/bin/r
## with ::
fn2 <- function() {
foreign::read.systat("Iris.syd", to.data.frame=TRUE)
}
## times
n <- 1e3
sink("double_colon.txt")
print(t(replicate(n, system.time(fn2()))))
sink()
Возьмите CSV-данные здесь. Некоторая статистика:
user CPU: W = 475366 p-value = 0.04738 MRr = 975.866 MRc = 1025.134
system CPU: W = 503312.5 p-value = 0.7305 MRr = 1003.8125 MRc = 997.1875
elapsed time: W = 403299.5 p-value < 2.2e-16 MRr = 903.7995 MRc = 1097.2005
MRr - средний ранг для require
, MRc ibid для ::
. Я, должно быть, сделал что-то не так. Это просто не имеет никакого смысла... Время выполнения для ::
кажется быстрее! Возможно, я что-то прикрутил, вы не должны отбрасывать этот вариант...
ОК... Я потратил свое время, чтобы увидеть, что есть какая-то разница, и я провел совершенно бесполезный анализ, поэтому вернемся к вопросу:
"Зачем нужно писать require
над ::
при записи функции?"
=)
Ответы
Ответ 1
"Зачем нужно больше: при написании функции?"
Я обычно предпочитаю require
из-за хорошего возвращаемого значения TRUE/FALSE, которое позволяет мне иметь дело с возможностью того, чтобы пакет не был доступен перед тем, как попасть в код. Сбой как можно раньше, а не на полпути через ваш анализ.
Я использую только ::
, когда мне нужно убедиться, что я использую правильную версию функции, а не версию из другого пакета, который маскирует имя.
С другой стороны,:: оператор получает переменная из пакета, в то время как требуют загрузки всего пакета (не менее Надеюсь, что так), поэтому произошли перемены скорости сначала на мой взгляд.:: должен быть быстрее чем требуется.
Я думаю, что вы можете игнорировать эффекты ленивой загрузки, которые используются пакетом foreign
в соответствии с первой страницей своего руководства, По сути, пакеты, которые используют ленивую загрузку, откладывают загрузку объектов, таких как функции, до тех пор, пока объекты не будут вызваны в первый раз. Поэтому ваш аргумент о том, что "::
должен быть быстрее, чем требуется", не обязательно истинен, поскольку foreign
не загружает все его содержимое в память, когда вы прикрепляете его с помощью require
. Полную информацию о ленивой загрузке см. Prof. Статья Рипли в номере RNews, том 4, выпуск 2.
Ответ 2
Поскольку время загрузки пакета почти всегда мало по сравнению с тем временем, которое вы потратили, пытаясь выяснить, что такое код, который вы написали шесть месяцев назад, в этом случае наиболее важна кодировка для ясности.
Для скриптов, имеющих вызов require
или library
в начале, вы можете сразу узнать, какие пакеты вам нужны.
Аналогично, вызов require
(или обертка типа requirePackage
в Hmisc
или try_require
в ggplot2
) в начале функции - это самый однозначный способ показать, что вам нужно использовать этот пакет.
::
должен быть зарезервирован для случаев, когда у вас есть конфликты имен между пакетами – сравните, например,
Hmisc::is.discrete
и
plyr::is.discrete