Area-frame and dual-frame survey design under real field cost. Survey samples
are usually designed for precision alone; the cost that actually decides
whether a survey happens is the field work: travelling between sampling units
and interviewing. fieldopt puts that cost next to the variance of the
estimator so that both are visible when the design is chosen, and provides
the pieces an agricultural survey with an area frame (grid cells, points
inside them) and a list frame needs.
travel_matrix()builds the travel matrix between units from coordinates (great-circle or planar distances, optionally times a detour factor), from a road network through OSRM (durations or distances, in blocks), or wraps a matrix computed elsewhere.field_cost_model()turns travel, team-days, visits and interviews into money or time.route_fieldwork()routes the field work from a depot through the selected units, for one team or several, under daily limits of duration (travel plus the service time at each unit), stops and capacity, on symmetric or road-network matrices: exact up to 13 units, otherwise a hybrid genetic search with the optimal split of the tour and a granular local search (optimal on the classical TSPLIB instances and on 24 of the 27 Augerat CVRP set A instances, largest gap 0.15%), with the Held-Karp bound and a proof of optimality when it closes;engine = "vrpr"hands the same problem to the PyVRP solver.schedule_fieldwork()solves the multi-depot problem of several bases with their teams and days (assignment, routes and the number of team-days at once) and distributes the routes over the teams and the days available: a calendar that says whether the field work fits;schedule_calendar()redoes that distribution as an integer programme (throughhighs) with team availability, fixed assignments, precedences and shared team-days.select_units()draws a probability sample of segments or cells, within strata, by the local pivotal method (spatially balanced), by spatially ordered systematic sampling along a Hilbert curve with interpenetrating replicates, by the cube method balanced on auxiliaries, or by simple random sampling;spatial_balance()measures how evenly a sample covers the territory.select_points(),expected_hits()andpoint_estimator()implement point sampling inside the selected cells and the multiplicity estimator (each hit of an establishment counts, divided by its expected hits).segment_estimator()gives the closed, open and weighted segment estimators;design_variance()the Horvitz-Thompson total with the variance estimator that matches the design (local-mean, replicates, SRS);ratio_estimator()uses a known auxiliary total;dual_frame_estimator()combines the area and the list samples (Hartley with a fixed, screening or estimated weight; Fuller-Burmeister).frame_allocation()allocates across strata for a target variance or a budget;multivariate_allocation()does it for several study variables at once (Bethel);dual_frame_allocation()is Hartley's allocation for an area frame plus a list frame with overlap, with the optimal mixing weight or the screening design;two_stage_allocation()is Cochran's two-stage allocation with the cost functionc1 n + c2 n m.tidy()andglance()read them all.routed_unit_cost(),two_stage_design()anddual_frame_design()close the loop: the cost of an area unit is measured by routing a sample of the allocated size, and the allocation is repeated until it stabilises.point_design_effect()simulates the whole area design (cells, points, hits, estimator) and returns the bias, the variance and the design effect of point sampling, thedeff_athe dual-frame allocation asks for.cost_variance_frontier()simulates designs over a grid of sample sizes and returns the trade-off between field cost and variance.as_frame(),as_sf()andread_areaframe()move between spatial layers (or the cells exported by an area-frame service) and the plain frames the package works on;frame_overlap()matches a list frame to the cells and marks the overlap domain;as_svydesign()hands a sample to thesurveypackage for calibration, domains and nonresponse adjustment.
The numerical engine is the Rust crate
fieldopt-core, usable on
its own from Rust or from other languages.
The development version needs a Rust toolchain (cargo and rustc 1.70 or
later, from https://rustup.rs):
# install.packages("pak")
pak::pak("castlaboratory/fieldopt")library(fieldopt)
library(dplyr)
set.seed(1)
frame <- tibble(
unit = c("depot", paste0("s", 1:40)),
x = c(5, runif(40, 0, 10)), y = c(5, runif(40, 0, 10))
) |>
mutate(crop = if_else(unit == "depot", NA_real_, 20 + 3 * x + rnorm(n())))
model <- field_cost_model(
per_travel = 2, per_unit = 30, per_interview = 10,
interviews_per_unit = 4, currency = "BRL"
)
# one design: select, route, price, estimate
s <- frame |>
filter(unit != "depot") |>
select_units(n = 12)
r <- s |>
travel_matrix(bases = frame |> filter(unit == "depot"), method = "euclidean") |>
route_fieldwork(units = s, depot = "depot", max_stops = 5, cost_model = model)
r
design_variance(s, y = "crop")
# the frontier across sample sizes
f <- cost_variance_frontier(
frame,
depot = "depot", cost_model = model,
n_grid = c(8, 12, 16, 24), y = "crop",
method = "euclidean", max_stops = 5, n_rep = 10
)
autoplot(f)Spatially balanced sampling and its variance estimator follow Grafström,
Lundström and Schelin (2012) and Grafström and Schelin (2014), as implemented
in BalancedSampling; the allocations are Cochran's (1977) cost-optimal
allocations and Hartley's (1962, 1974) dual-frame design; the dual-frame
estimators (Hartley, Fuller-Burmeister, Kalton-Anderson, pseudo-maximum
likelihood, calibration) are in Frames2. What fieldopt adds is the
design side with the routing and the cost model, so that the field cost of a
design is computed instead of approximated by the sample size.
André Leite (UFPE), Raydonal Ospina (UFBA) and Cristiano Ferraz (UFPE), CAST Lab. Licence GPL (>= 3).
