Использование пакета data.table внутри моего собственного пакета

Я пытаюсь использовать пакет data.table внутри своего собственного пакета. MWE выглядит следующим образом:

Я создаю функцию test.fun, которая просто создает небольшой объект data.table, а затем суммирует группировку столбцов "Val" столбцом "A". Код

test.fun<-function ()
{
    library(data.table)
    testdata<-data.table(A=rep(seq(1,5), 5), Val=rnorm(25))
    setkey(testdata, A)
    res<-testdata[,{list(Ct=length(Val),Total=sum(Val),Avg=mean(Val))},"A"]
    return(res)
}

Когда я создаю эту функцию в регулярном сеансе R, а затем запускаю функцию, она работает как ожидалось.

> res<-test.fun()
data.table 1.8.0  For help type: help("data.table")
> res
     A Ct      Total        Avg
[1,] 1  5 -0.5326444 -0.1065289
[2,] 2  5 -4.0832062 -0.8166412
[3,] 3  5  0.9458251  0.1891650
[4,] 4  5  2.0474791  0.4094958
[5,] 5  5  2.3609443  0.4721889

Когда я помещаю эту функцию в пакет, устанавливаю пакет, загружаю пакет, а затем запускаю функцию, я получаю сообщение об ошибке.

> library(testpackage)
> res<-test.fun()
data.table 1.8.0  For help type: help("data.table")
Error in `[.data.frame`(x, i, j) : object 'Val' not found

Может кто-нибудь объяснить мне, почему это происходит, и что я могу сделать, чтобы исправить это. Любая помощь очень ценится.

Ответ 1

Андри догадывается, +1. В нем есть часто задаваемые вопросы (см. vignette("datatable-faq")), а также новая виньетка при импорте data.table:

FAQ 6.9: я создал пакет, который зависит от data.table. Как я убедитесь, что мой пакет осведомлен о data.table, так что наследование от data.frame работает?

Либо i) включите data.table в поле Depends: вашего файла DESCRIPTION, либо ii) включите data.table в поле Imports: вашего файла DESCRIPTION И import(data.table) в своем файле NAMESPACE.

Дополнительная информация... в верхней части [.data.table (и других функций data.table) вы увидите переключатель в зависимости от результата вызова cedta(). Это означает вызов таблицы данных среды. Печатание data.table:::cedta показывает, как это было сделано. Он полагается на вызывающий пакет, имеющий пространство имен, и это пространство имен Import'ing или Depend'ing data.table. Вот как data.table можно передавать в пакеты, не поддерживающие data.table (например, функции в base), и эти пакеты могут использовать абсолютно стандартный синтаксис [.data.frame в data.table, к счастью, не зная, что data.frame is() a data.table тоже.

Именно поэтому наследование data.table раньше не было совместимым с пакетами без пространства имен, и поэтому по запросу пользователя мы должны были попросить авторов таких пакетов добавить пространство имен в их пакет для совместимости. К счастью, теперь, когда R добавляет пространство имен по умолчанию для пакетов, в которых отсутствует один (из v2.14.0), эта проблема исчезла:

ИЗМЕНЕНИЯ В R Версии 2.14.0
* Все пакеты должны иметь пространство имен, и один создается при установке, если он не указан в исходных кодах.

Ответ 2

Вот полный рецепт:

1) Добавьте data.table в Imports в ваш DESCRIPTION файл.

2) Добавьте @import data.table в ваш .R файл (т.е. файл .R, в котором находится ваша функция, которая выдает ошибку Error in [.data.frame(x, i, j) : object 'Val' not found).

3) Введите library(devtools) и установите рабочий каталог в основной каталог вашего пакета R.

4) Введите document(). Это гарантирует, что ваш файл NAMESPACE содержит строку import(data.table).

5) Тип build()

6) Тип install()

Для хорошего учебника о том, что build() и install() делать, см. http://kbroman.org/pkg_primer/.

Затем, как только вы закроете свой сеанс R и войдите в следующий раз, вы можете сразу же перейти прямо с помощью:

1) Тип library("my_R_package")

2) Введите имя вашей функции, размещенную в файле .R, упомянутом выше.

3) Наслаждайтесь! Вы больше не должны получать страшный Error in [.data.frame(x, i, j) : object 'Val' not found