| name | Data in R Packages |
| description | Comprehensive guide to including data in R packages, covering exported data, internal data, raw files, documentation, and CRAN size limits |
Data in R Packages
Overview
R packages can include data in several forms: exported datasets for users, internal data for package functions, raw data files, and dynamic package state. This skill covers all data types, documentation requirements, and CRAN restrictions.
Four Types of Package Data
1. Exported Data (data/)
User-accessible datasets loaded with data() or direct reference.
Location: data/ directory
Format: .rda or .RData files
Access: data(dataset_name) or direct reference (if LazyData: true)
Documentation: Required in R/data.R
2. Internal Data (R/sysdata.rda)
Data used by package functions, not accessible to users.
Location: R/sysdata.rda
Format: Single .rda file containing multiple objects
Access: Direct reference in package code
Documentation: Not required (internal only)
3. Raw Data Files (inst/extdata/)
Non-R data files (CSV, JSON, images, etc.) for users to access.
Location: inst/extdata/
Format: Any file format
Access: system.file("extdata", "file.ext", package = "pkg")
Documentation: Optional, usually in vignettes/examples
4. Dynamic Package State (environments)
Runtime state stored in package environments.
Location: Environment created in R code
Format: In-memory R objects
Access: Getter/setter functions
Documentation: Document the getter/setter functions
Exported Data (data/)
Creating Exported Data
my_dataset <- data.frame(
id = 1:100,
value = rnorm(100),
category = sample(LETTERS[1:3], 100, replace = TRUE)
)
usethis::use_data(my_dataset, overwrite = TRUE)
This creates data/my_dataset.rda.
Multiple Datasets
dataset1 <- mtcars[1:10, ]
dataset2 <- iris[1:50, ]
usethis::use_data(dataset1, dataset2, overwrite = TRUE)
Compression Options
usethis::use_data(my_dataset)
usethis::use_data(my_dataset, compress = "xz")
usethis::use_data(my_dataset, compress = "bzip2")
usethis::use_data(my_dataset, compress = FALSE)
CRAN recommendation: Use compress = "xz" for data >1MB.
LazyData
Add to DESCRIPTION to make data available without data() call:
LazyData: true
library(mypackage)
data(my_dataset)
head(my_dataset)
library(mypackage)
head(my_dataset)
Note: LazyData loads datasets into namespace but keeps them on disk until accessed (lazy loading).
Internal Data (R/sysdata.rda)
Creating Internal Data
Internal data is for package functions only, not exported to users.
internal_lookup <- list(
codes = c(A = 1, B = 2, C = 3),
thresholds = c(low = 0.05, high = 0.95)
)
internal_constants <- list(
api_version = "v2",
default_timeout = 30
)
usethis::use_data(
internal_lookup,
internal_constants,
internal = TRUE,
overwrite = TRUE
)
All objects saved with internal = TRUE go into a single file: R/sysdata.rda
Using Internal Data
my_function <- function(code) {
value <- internal_lookup$codes[code]
}
When to Use Internal Data
Good uses:
- Lookup tables
- Large constants
- Pre-computed values (avoid recomputation)
- Default configurations
Avoid:
- Data that changes (use environments instead)
- User-facing data (use data/ instead)
- Very large objects (consider lazy loading strategies)
Raw Data Files (inst/extdata/)
Adding Raw Data Files
dir.create("inst/extdata", recursive = TRUE)
usethis::use_directory("inst/extdata")
Common file types:
- CSV, TSV, Excel files
- JSON, XML, YAML
- Images (PNG, JPEG)
- Shapefiles, GeoJSON
- Text files, logs
- Binary formats
Accessing Raw Data Files
get_example_file <- function(filename) {
system.file("extdata", filename, package = "mypackage")
}
csv_path <- system.file("extdata", "example.csv", package = "mypackage")
data <- read.csv(csv_path)
read_my_data <- function(file) {
}
inst/ vs data/
inst/extdata/ # Raw files, any format
โโโ example.csv # Access with system.file()
โโโ sample.json
โโโ image.png
data/ # R objects only
โโโ dataset1.rda # Access with data() or direct reference
โโโ dataset2.rda
Use inst/extdata/ when:
- Non-R formats (CSV, JSON, etc.)
- Files users need paths to
- Multiple related files
- Files for examples/vignettes
Use data/ when:
- R objects for analysis
- Data ready to use in R
- Common datasets for package functions
Documenting Data
Documenting Exported Data
Create R/data.R to document all datasets:
"who"
Required tags:
@format - describe structure and columns
- Title and description (always)
Recommended tags:
@source - where data came from
@examples - how to use the data
Data Documentation Templates
Data Frame
"transactions"
List
"config_defaults"
Vector
"palette_colors"
Matrix
"correlation_matrix"
data-raw/ Workflow
Keep data preparation scripts separate from package code.
Setup
usethis::use_data_raw("dataset_name")
This creates:
data-raw/ directory
data-raw/dataset_name.R script
- Adds
^data-raw$ to .Rbuildignore
Data Preparation Script
library(dplyr)
library(lubridate)
raw_data <- read.csv("~/Downloads/raw_customer_data.csv")
customer_data <- raw_data %>%
janitor::clean_names() %>%
mutate(
transaction_date = ymd(transaction_date),
signup_date = ymd(signup_date)
) %>%
filter(
transaction_date >= "2020-01-01",
transaction_date <= "2023-12-31"
) %>%
select(
customer_id = id,
transaction_date,
amount = transaction_amount,
category = product_category,
region = customer_region
) %>%
distinct() %>%
arrange(transaction_date)
usethis::use_data(customer_data, overwrite = TRUE, compress = "xz")
Benefits of data-raw/
- Reproducibility: Anyone can recreate the data
- Documentation: Scripts document data transformations
- Version control: Track changes to data preparation
- Separation: Keep raw data separate from package
- Updates: Easy to update data with new source files
Multiple Datasets
source("data-raw/dataset1.R")
source("data-raw/dataset2.R")
dataset1 <- prepare_dataset1()
usethis::use_data(dataset1, overwrite = TRUE)
dataset2 <- prepare_dataset2()
usethis::use_data(dataset2, overwrite = TRUE)
CRAN Size Limits
Size Restrictions
CRAN limits:
- Total package size: 5 MB (compressed)
- Per subdirectory: 1 MB (recommended)
- Larger packages require justification
Check size:
pkgbuild::build()
file.size("../mypackage_1.0.0.tar.gz") / 1024^2
Reducing Data Size
1. Compression
usethis::use_data(dataset, compress = "xz")
save(dataset, file = "test_gzip.rda", compress = "gzip")
save(dataset, file = "test_bzip2.rda", compress = "bzip2")
save(dataset, file = "test_xz.rda", compress = "xz")
file.size("test_gzip.rda") / 1024
file.size("test_bzip2.rda") / 1024
file.size("test_xz.rda") / 1024
2. Subsetting
sample_data <- huge_dataset %>%
sample_n(1000) %>%
select(key_columns)
usethis::use_data(sample_data, compress = "xz")
3. Move to inst/extdata/
write.csv(large_dataset, "inst/extdata/large_dataset.csv.gz")
4. External Data Packages
For very large data, create separate data package:
mypackage/ # Main package
mypackage.data/ # Data-only package (optional dependency)
Suggests: mypackage.data
get_full_data <- function() {
if (!requireNamespace("mypackage.data", quietly = TRUE)) {
stop("Install mypackage.data: install.packages('mypackage.data')")
}
mypackage.data::full_dataset
}
5. Download on Demand
get_external_data <- function(cache = TRUE) {
cache_file <- rappdirs::user_cache_dir("mypackage")
data_file <- file.path(cache_file, "data.rds")
if (cache && file.exists(data_file)) {
return(readRDS(data_file))
}
url <- "https://example.com/data.rds"
data <- readRDS(url(url))
if (cache) {
dir.create(cache_file, recursive = TRUE, showWarnings = FALSE)
saveRDS(data, data_file)
}
data
}
Dynamic Package State
Use environments for runtime state, not exported data.
Package Environment Pattern
pkg_env <- new.env(parent = emptyenv())
.onLoad <- function(libname, pkgname) {
pkg_env$cache <- new.env(parent = emptyenv())
pkg_env$config <- list(
api_key = NULL,
verbose = FALSE
)
}
get_config <- function(key) {
pkg_env$config[[key]]
}
set_config <- function(key, value) {
pkg_env$config[[key]] <- value
invisible(value)
}
cache_get <- function(key) {
pkg_env$cache[[key]]
}
cache_set <- function(key, value) {
pkg_env$cache[[key]] <- value
invisible(value)
}
cache_clear <- function() {
rm(list = ls(pkg_env$cache), envir = pkg_env$cache)
invisible(NULL)
}
When to Use Environments vs data/
Use environments for:
- Runtime configuration
- Caches
- Mutable state
- Session-specific data
Use data/ for:
- Static datasets
- Examples and documentation
- Reference data
- Immutable package constants
Complete Example
Full Data Package Setup
usethis::use_data_raw("customers")
library(dplyr)
customers <- read.csv("raw/customers.csv") %>%
filter(active == TRUE) %>%
select(id, name, region, signup_date) %>%
arrange(signup_date)
usethis::use_data(customers, overwrite = TRUE, compress = "xz")
"customers"
LazyData: true
devtools::document()
devtools::check()
Common Pitfalls
1. Forgetting LazyData
Without LazyData, users must call data() explicitly:
LazyData: true
2. Not Documenting Data
CRAN requires documentation for all exported data:
3. Exceeding Size Limits
devtools::build()
4. Wrong File Extension
usethis::use_data(data, file = "data.RData")
usethis::use_data(data)
5. Including data-raw/ in Package
Should be in .Rbuildignore:
^data-raw$
usethis::use_data_raw() adds this automatically.
6. Using save() Instead of usethis::use_data()
save(dataset, file = "data/dataset.rda")
usethis::use_data(dataset)
7. Not Using system.file() for inst/extdata/
data <- read.csv("inst/extdata/example.csv")
path <- system.file("extdata", "example.csv", package = "mypackage")
data <- read.csv(path)
8. Documenting Internal Data
Internal data (R/sysdata.rda) should NOT be documented:
usethis::use_data(internal_obj, internal = TRUE)
9. Missing @format Tag
"mydata"
"mydata"
10. Hardcoding Paths in data-raw/
raw <- read.csv("C:/Users/Me/Desktop/data.csv")
raw <- read.csv("raw_data/data.csv")
raw <- read.csv(here::here("raw_data", "data.csv"))
Quick Reference
Creating Data
usethis::use_data(dataset, compress = "xz")
usethis::use_data(internal_obj, internal = TRUE)
usethis::use_data_raw("dataset")
Accessing Data
data(dataset)
dataset
internal_obj
system.file("extdata", "file.csv", package = "pkg")
Documentation Template
"dataset"
Size Management
devtools::build()
usethis::use_data(data, compress = "xz")
data_sample <- data[1:1000, ]
Resources