Tips for working with big data
Hunter Stanke, Jeffrey W. Doser
2020 (last updated September 23, 2026)
Source:vignettes/bigData.Rmd
bigData.RmdLarger-than-RAM methods
The sheer size of the FIA Database can present a serious challenge
for many users interested in performing regional studies (requiring a
large subset of the database). Recent updates to rFIA are
intended to reduce these barriers.
Namely, we’ve implemented “larger-than-RAM” methods for all
rFIA estimator functions. In short, behind the scenes we
read the necessary tables for individual states into RAM one at a time
and summarize to the estimation unit level (always sub-state and
mutually exclusive populations, hence additive properties apply). We
save the estimation unit level results for each state in RAM, and
combine them into the final output once we’ve iterated over all states.
This may sound complicated, but fortunately these “larger-than-RAM”
methods use the exact same syntax as normal “in-memory”
operations.
To get started, we simply have to set up a
Remote.FIA.Database in place of our regular in-memory
FIA.Database by setting inMemory=FALSE in our
call to readFIA():
library(rFIA)
# Download data for two small states
getFIA(c('RI', 'CT'), dir = 'path/to/save/', load = FALSE)
# Now set up a Remote.FIA.Database with readFIA by setting inMemory = FALSE
# Instead of reading in the data now, readFIA will simply save a pointer
# and allow the estimator functions to read/process the data state-by-state
fia <- readFIA('path/to/save/', inMemory = FALSE)
class(fia)## [1] "Remote.FIA.Database"
Once set up, our Remote.FIA.Database will work exactly
the same as we are used to. That is, we can use the same syntax we have
been using for normal, in-memory operations. For example, to estimate
biomass using our Remote.FIA.Database:
# Estimate biomass with Remote.FIA.Database
biomass(db = fia)## # A tibble: 21 × 5
## YEAR BIO_ACRE BIO_ACRE_SE nPlots_TREE nPlots_AREA
## <dbl> <dbl> <dbl> <int> <int>
## 1 2005 70.6 3.19 219 223
## 2 2006 71.1 2.65 325 331
## 3 2007 71.0 2.26 436 442
## 4 2008 71.8 2.21 425 430
## 5 2009 73.6 2.24 419 425
## 6 2010 75.1 2.21 422 426
## 7 2011 76.1 2.18 435 441
## 8 2012 77.1 2.15 441 446
## 9 2013 77.3 2.12 438 443
## 10 2014 77.8 2.12 439 444
## # ℹ 11 more rows
# All the extra goodies work the same:
# By species
biomass(fia, bySpecies = TRUE)## # A tibble: 1,373 × 8
## YEAR SPCD COMMON_NAME SCIENTIFIC_NAME BIO_ACRE BIO_ACRE_SE nPlots_TREE
## <dbl> <dbl> <chr> <chr> <dbl> <dbl> <int>
## 1 2005 10 fir spp. Abies spp. 0.000761 100. 1
## 2 2005 43 Atlantic white-… Chamaecyparis … 0.00398 99.9 1
## 3 2005 68 eastern redcedar Juniperus virg… 0.517 29.4 20
## 4 2005 91 Norway spruce Picea abies 0.00445 100. 1
## 5 2005 97 red spruce Picea rubens 0.0155 100. 1
## 6 2005 125 red pine Pinus resinosa 0.0300 100. 1
## 7 2005 126 pitch pine Pinus rigida 0.417 58.4 6
## 8 2005 129 eastern white p… Pinus strobus 3.78 20.3 59
## 9 2005 261 eastern hemlock Tsuga canadens… 2.58 22.9 37
## 10 2005 315 striped maple Acer pensylvan… 0.00956 77.1 3
## # ℹ 1,363 more rows
## # ℹ 1 more variable: nPlots_AREA <int>
# Alternative estimators (linear moving average)
biomass(fia, method = 'LMA')## # A tibble: 21 × 5
## YEAR BIO_ACRE BIO_ACRE_SE nPlots_TREE nPlots_AREA
## <dbl> <dbl> <dbl> <int> <int>
## 1 2005 70.8 2.97 219 223
## 2 2006 71.5 2.52 320 326
## 3 2007 72.3 2.20 435 441
## 4 2008 73.6 2.38 412 417
## 5 2009 74.3 2.45 417 423
## 6 2010 76.2 2.29 421 425
## 7 2011 76.0 2.45 435 441
## 8 2012 77.6 2.52 441 446
## 9 2013 77.2 2.49 438 443
## 10 2014 78.6 2.50 439 444
## # ℹ 11 more rows
## # A tibble: 162 × 7
## YEAR STDORGCD SITECLCD BIO_ACRE BIO_ACRE_SE nPlots_TREE nPlots_AREA
## <dbl> <int> <int> <dbl> <dbl> <int> <int>
## 1 2005 0 3 105. 12.4 4 4
## 2 2005 0 4 86.5 7.52 39 39
## 3 2005 0 5 72.9 3.45 121 124
## 4 2005 0 6 55.5 7.37 63 65
## 5 2005 0 7 45.6 9.93 3 3
## 6 2005 1 3 84.7 0 1 1
## 7 2005 1 6 10.2 6.25 2 2
## 8 2006 0 3 103. 11.4 5 5
## 9 2006 0 4 80.9 6.96 51 51
## 10 2006 0 5 75.3 2.89 186 191
## # ℹ 152 more rows
In addition, you can still specify spatial-temporal subsets on
Remote.FIA.Database objects using
clipFIA():
# A most recent subset with the Remote.FIA.Database
fiaMR <- clipFIA(fia)
# Biomass in most recent inventory
biomass(fiaMR)## # A tibble: 1 × 5
## YEAR BIO_ACRE BIO_ACRE_SE nPlots_TREE nPlots_AREA
## <dbl> <dbl> <dbl> <int> <int>
## 1 2025 83.2 2.32 435 443
In practice, rFIA's larger-than-RAM methods make it
possible for nearly anyone to work with very large subsets of FIA
Database. In our testing, we have run tpa(),
biomass(), dwm(), and carbon()
for the entire continental US on a machine with just 16 GB of RAM (where
the FIA data total ~ 50GB).
The only challenge that the Remote.FIA.Database presents
is that it becomes difficult for users to modify variables in FIA tables
(e.g., make tree size classes). However, it is possible to read in,
modify, and save tables of interest prior to setting up a
Remote.FIA.Database. For example, we can extend our example
above to produce estimates of live tree biomass grouped by stand age
classes, where stand age classes can be computed with
makeClasses().
# Rather than read all tables into memory, just read those of interest
# In this case, we just need the COND table
modTables <- readFIA(dir = 'path/to/save/', tables = 'COND',
states = c('RI', 'CT'), inMemory = TRUE)
# Now we can modify the COND table in any way we like
# Here we just add a variable that we will want to group by later
modTables$COND$STANDAGEGROUP <- makeClasses(modTables$COND$STDAGE, interval = 50)
# Now we can save our changes to the modified tables on disk with writeFIA
# This will overwrite the COND tables previously stored in our target directory
# And allow us to use our new variables in a subsequent 'Remote.FIA.Database'
writeFIA(modTables, dir = 'path/to/save/', byState = TRUE)
# Now set up the Remote database again
fia <- readFIA('path/to/save/', inMemory = FALSE)
# And produce estimates grouped by our new variable
biomass(fia, grpBy = STANDAGEGROUP)## [1] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
## [16] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
## [31] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
## [46] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
## [61] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
## [76] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
## [91] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
## [106] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
## [121] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
## [136] TRUE
## # A tibble: 88 × 6
## YEAR STANDAGEGROUP BIO_ACRE BIO_ACRE_SE nPlots_TREE nPlots_AREA
## <dbl> <chr> <dbl> <dbl> <int> <int>
## 1 2005 [-49,1) 12.4 80.2 3 5
## 2 2005 [1,51) 33.6 14.2 35 36
## 3 2005 [101,151) 83.2 7.39 18 19
## 4 2005 [51,101) 74.7 3.19 178 179
## 5 2006 [-49,1) 12.9 67.9 3 7
## 6 2006 [1,51) 35.7 10.5 57 59
## 7 2006 [101,151) 79.9 6.64 23 25
## 8 2006 [51,101) 76.4 2.65 261 262
## 9 2007 [-49,1) 6.19 91.0 3 9
## 10 2007 [1,51) 35.5 9.45 74 76
## # ℹ 78 more rows
Simple, easy parallelization
All rFIA estimator functions (as well as
readFIA() and getFIA()) can be implemented in
parallel, using the nCores argument. By default, processing
is implemented serially with nCores = 1, although users may
find substantial increases in efficiency by increasing
nCores.
Parallelization is implemented with the parallel package. Parallel
implementation is achieved using a snow type cluster on any Windows OS,
and with multicore forking on any Unix OS (Linux, Mac). Implementing
parallel processing may substantially decrease free memory during
processing, particularly on Windows OS. Thus, users should be cautious
when running in parallel, and consider implementing serial processing
for this task if computational resources are limited
(nCores = 1).
# Check the number of cores available on your machine
# Requires the parallel package
parallel::detectCores()## [1] 16
# On our machine, we have a fun 16 cores to play with.
# To speed processing, we will split the workload
# across 3 of these cores using nCores = 3
tpaRI_par <- tpa(fiaRI, nCores = 3)