Skip to contents

stratify_by() specifies stratification variables and an optional allocation method for a sampling design, so that every subgroup the variables define is represented. It applies to the current stage and comes before that stage's draw(), which closes it.

Usage

stratify_by(
  .data,
  ...,
  alloc = NULL,
  variance = NULL,
  cost = NULL,
  cv = NULL,
  importance = NULL,
  power = NULL
)

Arguments

.data

A sampling_design object (piped from sampling_design(), add_stage(), or cluster_by()), before the stage's draw().

...

Stratification variables as bare column names. A name given here is a label and does not rename the variable. A label resembling one of the arguments below (allocc, varianc) is refused, because those arguments follow ... and are matched exactly.

alloc

Character string naming the allocation method. With a method, n in draw() is the total sample size to distribute. One of:

  • NULL (default): No allocation. n in draw() is per stratum

  • "equal": Splits the total as evenly as integer rounding, min_n, max_n and the stratum populations allow, so the final sizes can differ

  • "proportional": Proportional to the number of the stage's sampling units in each stratum, or to importance when it is supplied

  • "neyman": Neyman optimal allocation (requires variance)

  • "optimal": Cost-variance optimal allocation (requires variance and cost)

  • "power": Power allocation (requires cv and importance)

Every method caps a stratum at its population and redistributes the surplus, so "equal" on populations \((10, 490, 500)\) with n = 300 gives 10/145/145 rather than 100/100/100. execute() reports this with a message of class samplyr_message_allocation_capped (see execution_conditions).

An input the method does not read is refused with class samplyr_error_alloc_unused_aux rather than ignored: variance next to "proportional", cost next to "neyman", or any of variance, cost, cv, importance, power with no alloc.

variance

Stratum variances for Neyman or optimal allocation. Either a data frame with every stratification column (the join keys) plus a var column, or, with a single stratification variable only, a named numeric vector whose names match the values of the stratification column (for example c(A = 1.2, B = 0.8)).

cost

Stratum costs for optimal allocation, in the same two forms as variance with a cost column.

cv

Stratum coefficients of variation (\(C_h\)) for power allocation, in the same two forms as variance with a cv column.

importance

A positive size per stratum (\(X_h\)), in the same two forms as variance with an importance column. It is what "proportional" allocates in proportion to, such as each stratum's household total, or the importance measure of power allocation.

power

Power exponent \(q\) for power allocation. Must satisfy \(0 \le q \le 1\). Defaults to 0.5.

Value

A modified sampling_design object with stratification specified.

Details

Equal allocation

Each stratum receives n/H units, where H is the number of strata.

Proportional allocation

Each stratum receives \(n \times N_h/N\) units, where \(N_h\) is the number of the stage's sampling units in stratum h and N their total. At a clustered stage \(N_h\) counts PSUs, not the elements inside them, and mos does not enter the allocation.

With importance, each stratum receives \(n \times X_h / \sum X_h\) units instead, so a clustered stage can allocate its PSUs in proportion to the households they hold. This gives the same sizes as power allocation with every \(C_h = 1\) and \(q = 1\). A two-stage plan allocated on the ultimate units, from svyplan::n_alloc() with a cluster model, is passed to draw() directly.

Neyman allocation

Minimizes variance for a fixed sample size. Each stratum receives \(n \times (N_h \times S_h) / \sum(N_h \times S_h)\) units, where S_h is the stratum standard deviation. At a clustered stage the units allocated are PSUs, so S_h is the standard deviation of PSU totals.

Optimal allocation

Minimizes variance for fixed cost (or cost for fixed variance). Each stratum receives \(n \times (N_h \times S_h / \sqrt{C_h}) / \sum(N_h \times S_h / \sqrt{C_h})\) units, where C_h is the per-unit cost in stratum h.

Power allocation

A compromise allocation (Bankier, 1988) with \(n_h \propto C_h \times X_h^q\), where \(C_h\) is the stratum CV, \(X_h\) a stratum importance measure, and \(q \in [0, 1]\).

Population bounds and redistribution

For an allocation method the realized sizes satisfy \(\sum_h n_h = n\) and \(0 \le n_h \le N_h\) whenever the request is feasible. The population cap is always present, and min_n and max_n add user bounds on top of it.

Saturated strata are fixed at their bound and removed, and the remaining total is reallocated over the other strata with the method's own factors (\(N_h\) for proportional, \(N_h \sqrt{S_h^2}\) for Neyman, and so on), which keeps the stated criterion after saturation. When the free strata all carry zero factors, the remainder is split equally in stratum order.

Real-valued targets become integers by largest remainder, which keeps the total. Among strata with equal remainders the larger target is served first, and strata still tied are served in a fixed order of their labels, the "stratum order" above. It depends on neither the order of the frame's rows nor the session locale, so a permuted frame gets the same allocation.

Requesting more than the frame holds allocates every unit rather than failing, and execute() warns with class samplyr_warning_census, or samplyr_warning_nominal_cap for a random-size method (see execution_conditions). Bounds that make the request impossible are errors of class samplyr_error_alloc_min_infeasible or samplyr_error_alloc_max_infeasible.

With-replacement (srswr, pps_multinomial) and minimum-replacement (pps_chromy) methods can select a unit more than once, so the number of distinct units does not bound the draws, and only min_n and max_n bind.

Per-stratum sizes given directly, through a scalar or named n, a frac, or a data frame, are never redistributed. Selection caps an impossible one and reports it.

Custom allocation

For sizes or rates chosen per stratum, pass draw() a data frame as n or frac, with every stratification column plus an n or frac column.

References

Bankier, M.D. (1988). Power allocations: determining sample sizes for subnational areas. The American Statistician, 42(3), 174-177.

See also

sampling_design() for creating designs, draw() for specifying sample sizes, cluster_by() for cluster sampling

Other design specification: add_stage(), cluster_by(), draw(), sampling_design(), selection_methods

Examples

# Simple stratification: 20 EAs per region
sampling_design() |>
  stratify_by(region) |>
  draw(n = 20) |>
  execute(bfa_eas, seed = 1234)
#> # A tbl_sample: 260 × 18
#> # Sampling:     1 stage | 260/44,570 units
#> # Weights:      171.42 [80.6, 275.25]
#>    ea_id region      province commune urban_rural population households area_km2
#>  * <int> <fct>       <fct>    <fct>   <fct>            <int>      <int>    <dbl>
#>  1  9635 Boucle du … Banwa    Sanaba  Rural              357         45     0.77
#>  2  9908 Boucle du … Bale     Siby    Rural              113         17     8.92
#>  3 20945 Boucle du … Mouhoun  Bondok… Rural              395         52     7.58
#>  4 34029 Boucle du … Banwa    Sami    Rural              363         55     8.85
#>  5 31936 Boucle du … Sourou   Kiemba… Rural              683         89     0.6 
#>  6 26038 Boucle du … Mouhoun  Dédoug… Rural              351         50     8.67
#>  7 41793 Boucle du … Kossi    Dokui   Rural              184         25     8.27
#>  8  5643 Boucle du … Mouhoun  Kona    Rural              101         16     8.38
#>  9 21026 Boucle du … Mouhoun  Bondok… Rural               64          8     7.92
#> 10 33091 Boucle du … Kossi    Nouna   Rural               28          4     8.55
#> # ℹ 250 more rows
#> # ℹ 10 more variables: pop_density <dbl>, longitude <dbl>, latitude <dbl>,
#> #   remoteness <fct>, fieldwork_cost <int>, .weight <dbl>, .sample_id <int>,
#> #   .stage <int>, .weight_1 <dbl>, .fpc_1 <dbl>

# With an allocation method the same n is a total: 20 EAs in all,
# shared as evenly as possible across the 13 regions
shared <- sampling_design() |>
  stratify_by(region, alloc = "equal") |>
  draw(n = 20) |>
  execute(bfa_eas, seed = 1234)
#> Stage 1: 6 strata take a single unit outside certainty.
#> ℹ Strata with one unit: "Est", "Hauts-Bassins", "Nord", "Plateau-Central",
#>   "Sahel", and 1 more.
#> ℹ These sizes come from `alloc = "equal"`, which shares `n` across the strata.
#>   Without `alloc`, `n` is taken in each stratum.
#> ℹ A stratum needs two selections for its variance to be estimated. survey stops
#>   on a stratum with one unless its strata are collapsed, and a replicate method
#>   has nothing to resample in it.
#> ℹ To estimate within each stratum, allocate at least two units outside
#>   certainty to it. `min_n` bounds a stratum's whole take, certainty units
#>   included.
table(shared$region)
#> 
#> Boucle du Mouhoun          Cascades            Centre        Centre-Est 
#>                 2                 2                 2                 2 
#>       Centre-Nord      Centre-Ouest        Centre-Sud               Est 
#>                 2                 2                 2                 1 
#>     Hauts-Bassins              Nord   Plateau-Central             Sahel 
#>                 1                 1                 1                 1 
#>         Sud-Ouest 
#>                 1 

# Proportional allocation across regions
sampling_design() |>
  stratify_by(region, alloc = "proportional") |>
  draw(n = 200) |>
  execute(bfa_eas, seed = 123)
#> # A tbl_sample: 200 × 18
#> # Sampling:     1 stage | 200/44,570 units
#> # Weights:      222.85 [217.78, 237.43]
#>    ea_id region      province commune urban_rural population households area_km2
#>  * <int> <fct>       <fct>    <fct>   <fct>            <int>      <int>    <dbl>
#>  1 33181 Boucle du … Kossi    Nouna   Rural              133         17     0.07
#>  2 33229 Boucle du … Kossi    Nouna   Rural               48          6     4.53
#>  3 21506 Boucle du … Kossi    Doumba… Rural              485         83     4.82
#>  4 45264 Boucle du … Bale     Pâ      Rural              825         95     0.66
#>  5 26201 Boucle du … Sourou   Di      Rural               95         17    21.1 
#>  6 26077 Boucle du … Mouhoun  Dédoug… Rural              176         25     8.96
#>  7 25510 Boucle du … Kossi    Bombor… Rural              246         36     0.44
#>  8 23774 Boucle du … Banwa    Solenzo Rural              158         21     2.9 
#>  9  8332 Boucle du … Mouhoun  Ouarko… Rural               55          8     5.68
#> 10 43713 Boucle du … Mouhoun  Safané  Rural               97         14     6.46
#> # ℹ 190 more rows
#> # ℹ 10 more variables: pop_density <dbl>, longitude <dbl>, latitude <dbl>,
#> #   remoteness <fct>, fieldwork_cost <int>, .weight <dbl>, .sample_id <int>,
#> #   .stage <int>, .weight_1 <dbl>, .fpc_1 <dbl>

# Neyman allocation using pre-computed variances
sampling_design() |>
  stratify_by(region, alloc = "neyman", variance = bfa_eas_variance) |>
  draw(n = 200) |>
  execute(bfa_eas, seed = 12)
#> # A tbl_sample: 200 × 18
#> # Sampling:     1 stage | 200/44,570 units
#> # Weights:      222.85 [209, 243]
#>    ea_id region      province commune urban_rural population households area_km2
#>  * <int> <fct>       <fct>    <fct>   <fct>            <int>      <int>    <dbl>
#>  1 31987 Boucle du … Sourou   Kiemba… Rural               24          3     7.24
#>  2  4968 Boucle du … Sourou   Kassoum Rural              303         41     4.13
#>  3  4958 Boucle du … Sourou   Kassoum Rural              142         19     8.24
#>  4 23903 Boucle du … Banwa    Solenzo Rural               94         13    13.5 
#>  5 25996 Boucle du … Mouhoun  Dédoug… Rural              538         76     8.63
#>  6 21501 Boucle du … Kossi    Doumba… Rural              247         42     7.93
#>  7 43794 Boucle du … Mouhoun  Safané  Rural               87         12     8.96
#>  8  9724 Boucle du … Banwa    Sanaba  Rural               51          6     8.02
#>  9 10979 Boucle du … Banwa    Tansila Rural               71          9     7.72
#> 10  8893 Boucle du … Bale     Pompoï  Rural              522         77     0.48
#> # ℹ 190 more rows
#> # ℹ 10 more variables: pop_density <dbl>, longitude <dbl>, latitude <dbl>,
#> #   remoteness <fct>, fieldwork_cost <int>, .weight <dbl>, .sample_id <int>,
#> #   .stage <int>, .weight_1 <dbl>, .fpc_1 <dbl>

# Optimal allocation considering both variance and cost
sampling_design() |>
  stratify_by(region, alloc = "optimal",
              variance = bfa_eas_variance,
              cost = bfa_eas_cost) |>
  draw(n = 200) |>
  execute(bfa_eas, seed = 1)
#> # A tbl_sample: 200 × 18
#> # Sampling:     1 stage | 200/44,570 units
#> # Weights:      222.85 [194.4, 243.76]
#>    ea_id region      province commune urban_rural population households area_km2
#>  * <int> <fct>       <fct>    <fct>   <fct>            <int>      <int>    <dbl>
#>  1  9648 Boucle du … Banwa    Sanaba  Rural              279         35     8.37
#>  2 11547 Boucle du … Sourou   Toéni   Rural               49          7    21.4 
#>  3 41824 Boucle du … Kossi    Dokui   Rural               75         10    15.8 
#>  4 11012 Boucle du … Banwa    Tansila Rural              592         71     0.95
#>  5 32308 Boucle du … Sourou   Lanfiè… Rural               57          8     9.49
#>  6  7017 Boucle du … Kossi    Madouba Rural              599         74     0.74
#>  7 36700 Boucle du … Bale     Fara    Rural              402         59     6.36
#>  8 11611 Boucle du … Nayala   Yaba    Rural              111         15     8.97
#>  9  8342 Boucle du … Mouhoun  Ouarko… Rural               94         13     8.1 
#> 10 11626 Boucle du … Nayala   Yaba    Rural               56          7     8.31
#> # ℹ 190 more rows
#> # ℹ 10 more variables: pop_density <dbl>, longitude <dbl>, latitude <dbl>,
#> #   remoteness <fct>, fieldwork_cost <int>, .weight <dbl>, .sample_id <int>,
#> #   .stage <int>, .weight_1 <dbl>, .fpc_1 <dbl>

# Power allocation (Bankier, 1988)
sampling_design() |>
  stratify_by(
    region,
    alloc = "power",
    cv = data.frame(
      region = levels(bfa_eas$region),
      cv = c(0.40, 0.35, 0.12, 0.20, 0.30, 0.18,
             0.15, 0.38, 0.22, 0.32, 0.17, 0.45, 0.25)
    ),
    importance = data.frame(
      region = levels(bfa_eas$region),
      importance = c(60, 40, 120, 70, 80, 65,
                     50, 55, 90, 75, 45, 35, 30)
    ),
    power = 0.5
  ) |>
  draw(n = 200) |>
  execute(bfa_eas, seed = 7)
#> # A tbl_sample: 200 × 18
#> # Sampling:     1 stage | 200/44,570 units
#> # Weights:      222.85 [139.52, 388.8]
#>    ea_id region      province commune urban_rural population households area_km2
#>  * <int> <fct>       <fct>    <fct>   <fct>            <int>      <int>    <dbl>
#>  1 10970 Boucle du … Banwa    Tansila Rural              488         59    10.7 
#>  2 32313 Boucle du … Sourou   Lanfiè… Rural               45          6     8.78
#>  3 21006 Boucle du … Mouhoun  Bondok… Rural              102         13     3.08
#>  4 20930 Boucle du … Mouhoun  Bondok… Rural              792        104     9.76
#>  5 26158 Boucle du … Mouhoun  Dédoug… Rural              214         30     5.38
#>  6 10975 Boucle du … Banwa    Tansila Rural              141         17    16.0 
#>  7 44747 Boucle du … Nayala   Toma    Rural               73         12    10.2 
#>  8  9030 Boucle du … Bale     Poura   Urban              562        107     8.94
#>  9  4080 Boucle du … Sourou   Gomboro Rural              163         23     0.2 
#> 10 34042 Boucle du … Banwa    Sami    Rural              100         15     7.46
#> # ℹ 190 more rows
#> # ℹ 10 more variables: pop_density <dbl>, longitude <dbl>, latitude <dbl>,
#> #   remoteness <fct>, fieldwork_cost <int>, .weight <dbl>, .sample_id <int>,
#> #   .stage <int>, .weight_1 <dbl>, .fpc_1 <dbl>

# EAs allocated in proportion to each region's households rather than to
# its number of EAs
households <- stats::aggregate(households ~ region, bfa_eas, sum)
names(households)[2] <- "importance"
sampling_design() |>
  stratify_by(region, alloc = "proportional", importance = households) |>
  cluster_by(ea_id) |>
  draw(n = 100) |>
  execute(bfa_eas, seed = 7)
#> # A tbl_sample: 100 × 18
#> # Sampling:     1 stage | 100 units
#> # Weights:      445.7 [243, 836]
#>    ea_id region      province commune urban_rural population households area_km2
#>  * <int> <fct>       <fct>    <fct>   <fct>            <int>      <int>    <dbl>
#>  1  9030 Boucle du … Bale     Poura   Urban              562        107     8.94
#>  2 10970 Boucle du … Banwa    Tansila Rural              488         59    10.7 
#>  3 10975 Boucle du … Banwa    Tansila Rural              141         17    16.0 
#>  4 20930 Boucle du … Mouhoun  Bondok… Rural              792        104     9.76
#>  5 21006 Boucle du … Mouhoun  Bondok… Rural              102         13     3.08
#>  6 26158 Boucle du … Mouhoun  Dédoug… Rural              214         30     5.38
#>  7 44747 Boucle du … Nayala   Toma    Rural               73         12    10.2 
#>  8  4080 Boucle du … Sourou   Gomboro Rural              163         23     0.2 
#>  9 32313 Boucle du … Sourou   Lanfiè… Rural               45          6     8.78
#> 10 20713 Cascades    Comoe    Banfora Rural              935        107     0.52
#> # ℹ 90 more rows
#> # ℹ 10 more variables: pop_density <dbl>, longitude <dbl>, latitude <dbl>,
#> #   remoteness <fct>, fieldwork_cost <int>, .weight <dbl>, .sample_id <int>,
#> #   .stage <int>, .weight_1 <dbl>, .fpc_1 <dbl>

# Custom sample sizes per stratum using a data frame
custom_sizes <- data.frame(
  region = levels(bfa_eas$region),
  n = c(20, 12, 25, 18, 22, 16, 14, 15, 20, 18, 12, 10, 8)
)
sampling_design() |>
  stratify_by(region) |>
  draw(n = custom_sizes) |>
  execute(bfa_eas, seed = 2026)
#> # A tbl_sample: 210 × 18
#> # Sampling:     1 stage | 210/44,570 units
#> # Weights:      212.24 [115.14, 414.4]
#>    ea_id region      province commune urban_rural population households area_km2
#>  * <int> <fct>       <fct>    <fct>   <fct>            <int>      <int>    <dbl>
#>  1 34795 Boucle du … Sourou   Tougan  Rural               45          7    14.0 
#>  2 44496 Boucle du … Mouhoun  Tchéri… Rural              180         29    16.6 
#>  3  9624 Boucle du … Banwa    Sanaba  Rural              177         23     6.56
#>  4  7012 Boucle du … Kossi    Madouba Rural              387         48     6.18
#>  5 44420 Boucle du … Mouhoun  Tchéri… Rural               63         10    22.3 
#>  6   515 Boucle du … Kossi    Barani  Rural              651         85     1.11
#>  7  1144 Boucle du … Bale     Boromo  Rural               75         11     8.92
#>  8  8378 Boucle du … Bale     Ouri    Rural              693         98     9.26
#>  9  4909 Boucle du … Sourou   Kassoum Rural              662         90     0.65
#> 10 21094 Boucle du … Kossi    Bouras… Rural               25          4     5.1 
#> # ℹ 200 more rows
#> # ℹ 10 more variables: pop_density <dbl>, longitude <dbl>, latitude <dbl>,
#> #   remoteness <fct>, fieldwork_cost <int>, .weight <dbl>, .sample_id <int>,
#> #   .stage <int>, .weight_1 <dbl>, .fpc_1 <dbl>

# Multiple stratification variables
sampling_design() |>
  stratify_by(region, urban_rural, alloc = "proportional") |>
  draw(n = 300, min_n = 2) |>
  execute(bfa_eas, seed = 2025)
#> # A tbl_sample: 300 × 18
#> # Sampling:     1 stage | 300/44,570 units
#> # Weights:      148.57 [14.5, 176]
#>    ea_id region      province commune urban_rural population households area_km2
#>  * <int> <fct>       <fct>    <fct>   <fct>            <int>      <int>    <dbl>
#>  1 34056 Boucle du … Banwa    Sami    Rural              136         20     7.25
#>  2 12794 Boucle du … Kossi    Djibas… Rural               61          9     8.98
#>  3 36709 Boucle du … Bale     Fara    Rural              341         50     6.47
#>  4 11042 Boucle du … Banwa    Tansila Rural              118         14     8.43
#>  5  1167 Boucle du … Bale     Boromo  Rural              120         17   181.  
#>  6 23952 Boucle du … Banwa    Solenzo Rural              106         14     7.32
#>  7 32327 Boucle du … Sourou   Lanfiè… Rural              108         15     8.21
#>  8 44753 Boucle du … Nayala   Toma    Rural               72         12     7.27
#>  9 12732 Boucle du … Kossi    Djibas… Rural              772        110     8.62
#> 10 11071 Boucle du … Banwa    Tansila Rural               26          3     7.28
#> # ℹ 290 more rows
#> # ℹ 10 more variables: pop_density <dbl>, longitude <dbl>, latitude <dbl>,
#> #   remoteness <fct>, fieldwork_cost <int>, .weight <dbl>, .sample_id <int>,
#> #   .stage <int>, .weight_1 <dbl>, .fpc_1 <dbl>