Draws a balanced sample using the cube method (Deville & Tillé, 2004), or a spatially balanced (well-spread) sample using the local pivotal method (Grafström, Lundström & Schelin, 2012) or spatially correlated Poisson sampling (Grafström, 2012). A balanced sample satisfies (approximately) the balancing equations \(\sum_{k \in S} x_k / \pi_k \approx \sum_{k \in U} x_k\) for each auxiliary variable \(x\); a well-spread sample selects units that are far apart in the space spanned by the spreading variables.
Usage
balanced_wor(
pik,
aux = NULL,
strata = NULL,
spread = NULL,
bounds = NULL,
method = c("cube", "lpm2", "scps"),
nrep = 1L,
...
)Arguments
- pik
A numeric vector of inclusion probabilities (length N).
sum(pik)must be an integer to floating-point accuracy; seeunequal_prob_wor()for the exact-0/1 handling of boundary values. The target sample size,sum(pik), must be at least 1.- aux
An optional numeric matrix (N x p) of auxiliary balancing variables. Each column defines a balancing constraint. The sample size constraint is always included automatically;
auxspecifies additional variables to balance on. WhenNULL, only the sample size is balanced (equivalent to an unbalanced fixed-size design).- strata
An optional integer vector (length N) of stratum indicators (positive integers). Uses the stratified cube method (Chauvet & Tillé, 2006; Chauvet, 2009) to preserve within-stratum sample sizes while balancing on
aux. Requiressum(pik)within each stratum to be close to an integer for exact sizes. If not, a warning is issued andfixed_sizeis set toFALSE.- spread
An optional numeric matrix (N x d) of spatial coordinates (or other spreading variables) for well-spread, spatially balanced sampling. Required by the built-in
"lpm2"and"scps"methods, and supported by methods registered viaregister_method()withsupports_spread = TRUE; the built-in"cube"method does not use it and will error. A non-matrix vector is treated as a single spreading variable.- bounds
An optional list with elements
B,lower, andupperdescribing linear inequality constraints on the realized sample (Tripet & Tillé, 2026):Bis a numeric matrix (N x q) whose columns are constraint variables, and the samplesis drawn so that \(lower_j \le \sum_{k \in s} B_{kj} \le upper_j\) for every constraintj.-Inf/Infentries make a constraint one-sided;lower[j] == upper[j]enforces an exact equality. The starting probabilities must be feasible:lower <= colSums(B * pik) <= upper. Only supported by the built-in"cube"method. See Inequality constraints below.- method
The sampling method.
"cube"(the default) balances onaux;"lpm2"(local pivotal method 2) and"scps"(spatially correlated Poisson sampling) spread onspread; or the name of a balanced method added viaregister_method().- nrep
Number of replicate samples (default 1). When
nrep > 1,$sampleholds a matrix (n x nrep) for fixed-size designs, or a list of integer vectors when within-stratum sizes are not exact.- ...
Additional arguments passed to methods:
epsBoundary tolerance (default
1e-10): decides when an updated working probability has numerically reached 0 or 1 (during the cube flight phase, or during the pivotal steps of"lpm2"or"scps"). It never reclassifies the input; suppliedpikinside(0, eps]or[1 - eps, 1)are rejected. Onlypikof exactly 0 or exactly 1 enter the algorithm as already-resolved units.condition_auxLogical; if
TRUE, pre-conditionsauxby weighted centering/scaling and QR-pivot rank pruning to improve numerical stability with ill-conditioned or collinear auxiliary variables (defaultFALSE).qr_tolTolerance for QR rank detection when
condition_aux = TRUE; must be one finite, non-negative number (defaultsqrt(.Machine$double.eps)).
Value
An object of class
c("balanced", "unequal_prob", "wor", "sondage_sample").
When nrep = 1, $sample is an integer vector of selected unit
indices. When nrep > 1, $sample is a matrix (n x nrep) for
fixed-size designs, or a list of integer vectors when fixed_size
is FALSE (e.g., stratified with non-integer per-stratum sizes).
Details
The cube method proceeds in two phases:
- Flight phase
Probabilities are moved toward 0 or 1 while maintaining all balancing constraints. Each step resolves at least one unit. Terminates when fewer than p+1 undecided units remain.
- Landing phase
Remaining undecided units are resolved by progressively relaxing balancing constraints, starting from the last column of
aux. Users should order auxiliary variables by importance (most important first).
The sample size constraint is always placed first (never relaxed during landing). For stratified designs, within-stratum size constraints are also placed first.
Joint inclusion probabilities are approximated via the high-entropy approximation (Brewer & Donadio, 2003), which is appropriate since the cube produces a near-maximum-entropy design.
Inequality constraints
bounds implements the cube method with inequality constraints of
Tripet & Tillé (2026). During the flight phase, steps
are capped so every constraint stays feasible, and a constraint
whose slack reaches zero becomes an equality from then on. The
inclusion probabilities are respected exactly (E(s) = pik),
unlike rejective procedures.
B applies to the realized sample directly (counts / raw sums);
it is not divided by pik. To bound a Horvitz-Thompson
estimator, pass x / pik as the constraint column.
The main application is controlled selection (Goodman & Kish,
1950): bounding category counts to the integers adjacent to their
expectation. With indicator columns B and
S <- colSums(B * pik), use lower = floor(S),
upper = ceiling(S). Categories may overlap (e.g. row and column
margins of a two-way control table, as in NAEP-style designs).
Integer-valued bound systems on partitions or two-way margins are
satisfied exactly. For structures with no exact integer solution,
some three-way controlled rounding problems, or continuous-valued
constraints that end the flight phase tight against a boundary,
bounds that provably block the landing phase are relaxed one at a
time, with a warning; E(s) = pik still holds. In other words,
the bounds are guaranteed whenever no relaxation warning is
raised.
The high-entropy approximation used by joint_inclusion_prob() is
less accurate under tight bounds, which distort the design away
from maximum entropy; Tripet & Tillé (2026) recommend
Monte Carlo estimation of joint inclusion probabilities in that
case.
Spatially balanced sampling (lpm2 and scps)
method = "lpm2" implements the local pivotal method 2 of
Grafström, Lundström & Schelin
(2012). Repeatedly, a randomly chosen undecided unit and its
nearest undecided neighbour in the spread space compete in a
pivotal step (Deville & Tillé, 1998) that resolves at
least one of them to 0 or 1 while preserving the inclusion
probabilities exactly (E(s) = pik). Nearby units thereby tend to
exclude each other, spreading the sample over the population.
Nearest-neighbour distance ties (common on gridded coordinates)
are broken uniformly at random.
Spreading variables should be on comparable scales, since
nearness is plain Euclidean distance in the spread columns;
rescale them (e.g. with scale()) when they are not. "lpm2" and
"scps" use spread only: they do not accept aux, strata, or
bounds. To exactly balance covariate totals and spread
spatially, register a method that supports both aux and spread
(for example, a local-cube implementation). Running "cube" with
coordinates in aux balances their totals but does not itself enforce
spatial spread.
method = "scps" implements spatially correlated Poisson sampling
with the maximal-weight strategy of Grafström (2012).
At each step, a randomly chosen undecided unit is accepted or rejected
using its current conditional probability. Its probability displacement
is then distributed to the nearest undecided units, subject to feasibility
bounds that keep every working probability in \([0, 1]\).
Equal-distance
units share weight as evenly as their bounds allow. Random selection of
the step unit avoids dependence on input row order.
Both spatial methods deliberately drive joint inclusion probabilities of
nearby units toward zero, so the design is not high
entropy and no joint-probability approximation is provided:
joint_inclusion_prob() errors for these designs. Variance for
well-spread samples is usually estimated with local-neighbourhood
estimators (e.g. Grafström & Schelin, 2014).
Both methods are spread-only: neither exactly balances the totals
of aux. They are dispatched by balanced_wor() because “spatially
balanced sampling” is the standard name for well-spread fixed-size
designs, and because the same interface accommodates local-cube methods
that combine exact balancing with spread. Capability metadata keeps the
distinction explicit: both report supports_aux = FALSE and
supports_spread = TRUE through method_spec().
LPM2 costs O(N^2 * d) time per draw. SCPS uses weighted quickselect to find the distance at which its maximal weights sum to one, avoiding a full sort of the remaining units at each step. Its expected cost is also O(N^2 * d). Both implementations use O(N) workspace and store no distance matrix; SCPS sorts only equal-distance cutoff groups to share their weight fairly.
References
Deville, J.C. and Tillé, Y. (1998). Unequal probability sampling without replacement through a splitting method. Biometrika, 85(1), 89-101.
Deville, J.C. and Tillé, Y. (2004). Efficient balanced sampling: the cube method. Biometrika, 91(4), 893-912.
Chauvet, G. and Tillé, Y. (2006). A fast algorithm for balanced sampling. Computational Statistics, 21(1), 53-62.
Chauvet, G. (2009). Stratified balanced sampling. Survey Methodology, 35, 115-119.
Grafström, A., Lundström, N.L.P. and Schelin, L. (2012). Spatially balanced sampling through the pivotal method. Biometrics, 68(2), 514-520. doi:10.1111/j.1541-0420.2011.01699.x
Grafström, A. (2012). Spatially correlated Poisson sampling. Journal of Statistical Planning and Inference, 142(1), 139-147. doi:10.1016/j.jspi.2011.07.003
Grafström, A. and Schelin, L. (2014). How to select representative samples. Scandinavian Journal of Statistics, 41(2), 277-290. doi:10.1111/sjos.12016
Tripet, A. and Tillé, Y. (2026). Balanced sampling with inequalities: application to category bounding, matrix rounding, and spread sampling. Journal of the American Statistical Association, 121(553), 796-806. doi:10.1080/01621459.2025.2550667
See also
unequal_prob_wor() for unbalanced designs,
inclusion_prob() to compute inclusion probabilities from size measures.
Examples
# Unequal probability balanced sample
pik <- c(0.3, 0.6, 0.2, 0.4, 0.5)
x <- matrix(c(10, 20, 15, 25, 30))
set.seed(1)
s <- balanced_wor(pik, aux = x)
s$sample
#> [1] 2 5
# Check balancing: HT estimate of aux totals vs population totals
colSums(x[s$sample, , drop = FALSE] / pik[s$sample]) - colSums(x)
#> [1] -6.666667
# Stratified balanced sample
N <- 20
pik <- rep(0.4, N)
x <- matrix(as.double(1:N), ncol = 1)
strata <- rep(1:4, each = 5)
set.seed(1)
s <- balanced_wor(pik, aux = x, strata = strata)
s$sample
#> [1] 1 2 6 8 13 15 16 19
# Controlled selection: bound category counts to the integers
# adjacent to their expectation (floor/ceil)
pik <- rep(0.5, 12) # n = 6
groups <- rep(c("a", "b", "c"), each = 4)
B <- sapply(unique(groups), function(g) as.double(groups == g))
S <- colSums(B * pik) # 2, 2, 2 per category
set.seed(1)
s <- balanced_wor(
pik,
bounds = list(B = B, lower = floor(S), upper = ceiling(S))
)
table(groups[s$sample]) # exactly 2 per category
#>
#> a b c
#> 2 2 2
# Spatially balanced (well-spread) sample: local pivotal method 2
N <- 100
coords <- cbind(runif(N), runif(N))
pik <- rep(0.1, N)
set.seed(1)
s <- balanced_wor(pik, spread = coords, method = "lpm2")
s$sample
#> [1] 2 5 15 21 38 40 46 49 81 85
# Spatially correlated Poisson sampling uses the same spread contract
set.seed(1)
s_scps <- balanced_wor(pik, spread = coords, method = "scps")
s_scps$sample
#> [1] 1 10 12 17 23 27 61 75 90 97