Урок 4 Добавление данных в пакет


В этом уроке мы разберёмся с тем для чего вам может понадобиться добавить в ваш пакет помимо кода функций ещё и данные, и рассмотрим 5 способов это сделать.


Данный урок основан на главе "Data" книги "R Packages (2e)", под авторством Хедли Викхема и Дженни Брайан.


4.1 Видео

4.1.1 Тайм коды

00:00 Введение
00:35 Зачем добавлять данные в пакет
02:08 Экспортируемые данные
05:20 Внутренние данные пакета
07:57 Необработанные данные
13:51 Состояние пакета (внутренняя среда пакета)
16:30 Постоянные пользовательские данные
18:30 Прочие каталоги пакета
19:33 Заключение

4.2 Презентация

4.3 Конспект

4.3.1 Какие типы данных можно добавить в пакет

Есть 5 способов добавления данных в ваш пакет, в зависимости от того, как эти данные далее будут использоваться:

4.3.2 Экспортируемые данные

Это данные, которые экспорптируются при подключении пакета, и подразумевают их дальнейшее использование конечными пользователями вашего пакета. Зачастую в пакет добавляют несколько наборов данных, которые используются в примерах использования функционала пакета, иногда встречаются пакеты, которые состоят исключительно из данных.

Экспортируемые данные хнятся в виде .rda файлов в специальном каталоге data/. Наиболее простой способ включить экспортируемые данные в ваш пакет предоставляет функция usethis::use_data().

# создаём набор данных
board_of_directors <- tibble::tibble(
  id            = 1:5,
  name          = c("Alex", "John", "Bill", "Stiv", "Michael"),
  position      = c("CEO", "CTO", "CMO", "CDO", "CFO"),
  department    = rep("Board of Directors", 5),
  year_of_birth = c(1984, 1971, 1987, 1980, 1978),
  rate          = c(5000, 4200, 3500, 4500, 3500),
  office        = c("New York", "New York", "Chicago", "Washington", "Washington")
)

# сохраняем его в каталог data
usethis::use_data(board_of_directors)

Функция usethis::use_data() выполняет следующее:

  1. Создаёт каталогdata/, если его ещё нет
  2. Добавляет в каталог data/ .rda файлы
  3. Добавляет блок LazyData: true в DESCRIPTION файл

Не смотря на то, что у вас есть возможность созранить любе количество наборов данных в один .rda файл рекомендуется под каждый экспортируемый набор данных создавать отдельный файл в папке data/.

4.3.3 Внутренние данные

Данные, которые используются искобчительно функциями вашего пакета, являются исключительно технической, а не функциональнйо частью вашего пакета, и для конечного пользователя эти данные недоступны. Соответвенно внутренние данные не экспортируются при подключения пакета. Такие данные хрантся в специальном файле sysdata.rda в каталоге R/, т.е. вместе с кодом функций пакета.

Добавить в пакет внутренние данные можно той же функцией usethis::use_data(), но указав значение аргумента internal = TRUE.

# создаём наборы данных
board_of_directors <- tibble::tibble(
  id            = 1:5,
  name          = c("Alex", "John", "Bill", "Stiv", "Michael"),
  position      = c("CEO", "CTO", "CMO", "CDO", "CFO"),
  department    = rep("Board of Directors", 5),
  year_of_birth = c(1984, 1971, 1987, 1980, 1978),
  rate          = c(5000, 4200, 3500, 4500, 3500),
  office        = c("New York", "New York", "Chicago", "Washington", "Washington")
)

office_coef <- tibble::tibble(
  office = c("New York", "Chicago", "Washington"),
  coef   = c(1.2, 0.85, 1.1)
)

# сохраняем его в файл R/sysdata.rda
usethis::use_data(board_of_directors, office_coef, internal = T)

В отличае от экспортируемых данных, все внутренние наборы данных помещаются в один файл sysdata.rda, поэтому все их необходимо одновременно указать в функции usethis::use_data().

4.3.4 Необработанные данные

Такие данные могут использоваться для предоставления тестовых данных, для примеров использования функций пакета. Например, в пакет readxl, предназначенный для чтения данных из Excel книг, включены несколько Excel книг, исключительно для того, что бы пользователи могли протестировать его работу, описанную в примерах к функциям пакета.

Необработанные данные необходимо хранить в специальном каталоге по пути inst/extdata, т.е. создаёте каталог inst, и внутри него подкаталог extdata.

dir.create('inst/extdata', recursive = T)

Далее в эту папку добавляете файлы с данными.

для обращения к добавленным необработанным данным необходимо использовать функцию system.file(), но тут есть один нюанс. Дело в том, что ваш пакет может иметь разные состояни. в момент разработки это просто проект, который может находится в любом месте на вашем жестком диске, а функция system.file() ищет файлы исключительно в уже установленных пакетах, и если вы её просто будете использовать в вашем пакете, она вернёт пустую строку, вместо пути к файлу с необработанными данными. Но, как вы помните команда load_all() имитирует процесс загрузки вашего разрабатываемого пакета в память. очень близко к тому, как это делает команда library() с уже установленными пакетами. Поэтому, для того, что бы команда system.file() успешно работала в момент разработки вашего пакета, вам всегда необходимо держать пакет в состоянии загруженном в память, т.е. до того, как вы будете тестировать ваши функции нажмите сочетание клавиш Ctrl + Shift + L.

# Пример обращения к сырым данным пакета firstpackage
# предварительно обязательно надо загрузить пакет в память через load_all()
system.file('extdata', 'board_of_directors.csv', package = 'firstpackage')

4.3.5 Среда пакета

Данный приём используется если вам необходимо динамически изменять состояние вашего пакета. В таком случае вам необходимо создать внутри пакета отдельную среду, добавьте файл aaa.R в каталог R/, в котором создайте пустую среду, и добавльте в неё нужные объекты:

the <- new.env(parent = emptyenv())
the$favorite_letters <- letters[1:3]

Далее в случае необходимости обращения, или изменения значений созданных внутри среды объектов добавьте специальные функции:

#' Report my favorite letters
#' @export
mfl2 <- function() {
  the$favorite_letters
}

#' Change my favorite letters
#' @export
set_mfl2 <- function(l = letters[24:26]) {
  old <- the$favorite_letters
  the$favorite_letters <- l
  invisible(old)
}

Код заимствован из книги "R Packages 2e", Hadley Wickham, глава Data, раздел Internal state

Такие данные могут динамически изменяться в ходе одного R сеанса, но при повторном сеансе будут стартовать со своих исходных значений.

4.3.6 Постоянные пользовательские данные

Иногда вам может понадобится хранить какие то данные, которые будут использоваться между различными R сеансами. Например, я в своих пакетах таким образом храню авторизационные данные пользователя, для того, что бы пользователям моих пакетов не требовалось в ходе каждой новой R сессии проходить авторизацию через браузер, они один раз проходят весь процесс авторизации, полученные данные кешируются на жестком диске конечного пользователя, и во всех следующих сеансах читаются из кеша, что поволяет избегать повторной пользовательской авторизации.

Конечно данные, которые будут использоваться между различными R сессиями необходимо хранить локально. на жестком диске пользователя пакета. При этом обязательно необходимо соблюдать спецификацию каталогов принятую для вашей операционной системы, для определения директорий в которых вы будете хранить файлы вашего пакета используйте функцию tools::R_user_dir():

  • tools::R_user_dir("pkg", which = "data") – хранение данных
  • tools::R_user_dir("pkg", which = "config") – хранение конфигов
  • tools::R_user_dir("pkg", which = "cache") – хранение кешированных данных

Но, следует учитывать что функция tools::R_user_dir() появилась в R 4.0, если вашему пакету необходимо иметь совместимость с более старыми версиями R, то в качестве альтернативного варианта используйте функционал пакета rappdirs, о котором я отдельно рассказывал в видео уроке "Работа с секретными данными в R".

4.4 Тест