Frames, strata and cost-aware allocation
Source:vignettes/frames-and-allocation.Rmd
frames-and-allocation.RmdAgricultural and establishment surveys often combine a list frame
(known farms, cheap to reach by phone or on a planned visit) and an area
frame (segments of territory, expensive to reach, complete in coverage).
Even within one frame, strata differ in the cost of a unit.
frame_allocation() is Cochran’s (1977, Section 5.5)
allocation with a cost per unit in each stratum, in its two forms.
library(fieldopt)
library(dplyr, warn.conflicts = FALSE)
strata <- tibble(
stratum = c("list: large", "list: small", "area"),
size = c(300, 2500, 900),
sd = c(80, 12, 35),
cost = c(60, 35, 190)
)
strata
#> # A tibble: 3 × 4
#> stratum size sd cost
#> <chr> <dbl> <dbl> <dbl>
#> 1 list: large 300 80 60
#> 2 list: small 2500 12 35
#> 3 area 900 35 190Minimum cost for a target variance
Fix the precision wanted for the estimated total and find the
cheapest allocation that reaches it. The optimum has n_h
proportional to N_h S_h / sqrt(c_h), rounded up and kept
between 2 and N_h.
a <- frame_allocation(strata, target_variance = 2.5e7)
a
#>
#> ── Allocation ──────────────────────────────────────────────────────────────────
#> Minimum cost for target variance 2.5e+07: cost 22640, variance 24720000.
#> # A tibble: 3 × 5
#> stratum size sd cost n
#> <chr> <dbl> <dbl> <dbl> <int>
#> 1 list: large 300 80 60 88
#> 2 list: small 2500 12 35 143
#> 3 area 900 35 190 65Minimum variance for a budget
Fix the budget instead and find the allocation with the smallest variance within it. Rounding is repaired so that the cost never exceeds the budget.
b <- frame_allocation(strata, budget = 30000)
b
#>
#> ── Allocation ──────────────────────────────────────────────────────────────────
#> Minimum variance for budget 30000: cost 29980, variance 17830000.
#> # A tibble: 3 × 5
#> stratum size sd cost n
#> <chr> <dbl> <dbl> <dbl> <int>
#> 1 list: large 300 80 60 116
#> 2 list: small 2500 12 35 191
#> 3 area 900 35 190 86Where the field cost comes in
The cost column above is a planning value per unit. For
the area frame it should include the travel, and that is what the
routing part of the package estimates: run
cost_variance_frontier() on the area frame with a cost
model, read the mean cost per unit at the sample size under
consideration, and use it as the stratum cost. The allocation then
reflects how expensive the segments really are to visit, and the loop
can be iterated once or twice until the stratum costs and sample sizes
agree.
f <- cost_variance_frontier(
area_frame,
depot = "depot", cost_model = model,
n_grid = c(40, 60, 80, 100), y = "crop"
)
area_cost <- f |>
slice_min(abs(n - a$n[3]), n = 1) |>
pull(cost_per_unit)
strata |>
mutate(cost = if_else(stratum == "area", area_cost, cost)) |>
frame_allocation(target_variance = 2.5e7)Overlap between the frames (farms present in both) is not modelled here; the allocation treats the frames as strata of a single design.
Several study variables
A survey rarely has one target: crop area and cattle, or production
and the number of holdings, each with its own precision.
multivariate_allocation() finds the cheapest allocation
that meets every target at once (Bethel 1989); the multipliers say which
targets bind, and glance() shows the variance attained for
each.
multi <- tibble(
stratum = c("list", "area-high", "area-low"),
size = c(2000, 300, 500), cost = c(40, 200, 160),
sd_crop = c(12, 35, 18), sd_cattle = c(30, 10, 25)
)
ma <- multivariate_allocation(
multi,
sd = c("sd_crop", "sd_cattle"),
target_cv = c(0.04, 0.06), totals = c(120000, 90000)
)
ma
#>
#> ── Multivariate allocation ─────────────────────────────────────────────────────
#> Minimum cost 11200 for 2 targets.
#> sd_crop: target 23040000, attained 22600000 (binding).
#> sd_cattle: target 29160000, attained 28670000 (binding).
#> # A tibble: 3 × 4
#> stratum size cost n
#> <chr> <dbl> <dbl> <int>
#> 1 list 2000 40 169
#> 2 area-high 300 200 7
#> 3 area-low 500 160 19
glance(ma)
#> # A tibble: 2 × 7
#> variable target attained multiplier n cost bounded
#> <chr> <dbl> <dbl> <dbl> <int> <dbl> <lgl>
#> 1 sd_crop 23040000 22603942. 0.0000616 195 11200 FALSE
#> 2 sd_cattle 29160000 28668674. 0.000305 195 11200 FALSE