Count the degrees of freedom the variance estimator of a planned design
will have, before any data are collected. The planning analogue of
survey::degf(), which reports the same quantity for a design that has
already been fielded.
Usage
design_df(x = NULL, ...)
# Default S3 method
design_df(x = NULL, ..., n_psu = NULL, n_strata = 1, n = NULL)
# S3 method for class 'svyplan_cluster'
design_df(x, ...)
# S3 method for class 'svyplan_n'
design_df(x, ...)
# S3 method for class 'svyplan_strata'
design_df(x, ...)
# S3 method for class 'svyplan_twophase'
design_df(x, ...)Arguments
- x
A
svyplanresult to count from: an_cluster()orprec_cluster()allocation, an_alloc()allocation, astrata_bound()stratification, an_twophase()allocation, or a single-indicatorn_prop()orn_mean()size.NULL(default) counts from the components below.- ...
Additional arguments passed to methods. Unused arguments are rejected.
- n_psu
Number of PSUs the design will select, across all strata.
- n_strata
Number of strata, default 1 (unstratified).
- n
Number of ultimate units, for an element design. Supply this or
n_psu, not both.
Value
A svyplan_df object: a numeric scalar carrying the counts it
was formed from. Use it directly wherever a df argument is expected,
as.double() to strip it to a plain number, and $strata and
$domains for the per-stratum and per-domain tables.
Details
The degrees of freedom of a design-based variance estimator are the number of independent units contributing to it, less the number of constraints the design imposes: for a stratified design, sampled units minus strata. In a clustered design the units are the PSUs, not the ultimate units, which is why a survey of 12,000 households in 300 clusters across 20 strata has 280 degrees of freedom rather than 11,999.
That number is what a t quantile needs, what a Korn-Graubard interval
widens on, and what decides whether a domain estimate can be published
at all. Nothing reports it for a design that has only been planned, and
the plan is the only place it can be known before fielding.
What is counted, per design shape
| Design | Counted | df |
| Unstratified element | units | \(n - 1\) |
| Unstratified cluster | PSUs | \(m - 1\) |
| Stratified element | units per stratum | \(\sum_h n_h - H\) |
| Stratified cluster | PSUs per stratum | \(\sum_h m_h - H\) |
| Two-phase | phase-2 units per stratum | \(\sum_h n_{2h} - H\) |
The counts are read from the whole-unit columns a plan reports
(n_int, n_psu_int, operational$n), never from the continuous
optimum, since a degree of freedom is a unit that will be fielded. They
are the planned counts and are not netted down for element nonresponse:
a response rate is already priced into the size the plan reports, and
element nonresponse does not reduce the number of PSUs, which is what
the df of a clustered design counts.
A stratum that carries no sampling variance drops out of both terms. In
element mode a take_all stratum is a census and contributes nothing.
In cluster mode take_all marks an element-level census inside the
stratum, which leaves the PSU stage sampling as before, so such a
stratum still contributes \(m_h - 1\). A phase-2 take_all stratum
likewise still contributes, since following up every phase-1 unit in a
stratum does not remove the phase-1 sampling variance.
Per-domain degrees of freedom
$domains is exact rather than an approximation. The allocation API
expresses a domain as a set of whole strata, so a domain's df is that
union's own contribution, \(\sum_{h \in d} m_h - H_d\), and the
per-domain values sum to the overall df whenever the domains partition
the frame.
The case that is not derivable is an analytic domain cutting across strata, such as an age group or sex. Its df is bounded above by the design df, and the Korn-Graubard counting rule for it (PSUs containing domain members, minus strata containing them) needs frame information that a plan does not carry. It is a limit of what is knowable before fielding, not an omission.
What the count cannot see
Certainty, or self-representing, PSUs contribute no between-PSU variance
and should not count toward df. The API expresses certainty through
take_all and strata_bound()(take_all_above = ) at the stratum
level rather than as a PSU-level flag, so sampled PSUs are counted as
they stand. A design with a material number of certainty PSUs has fewer
degrees of freedom than reported here.
A stratum holding a single PSU supports no within-stratum variance
estimate at all, and warns, naming the stratum. Its own contribution is
zero and $strata marks it "singleton". Whether a small but positive
df is a problem is a judgment call, so it is reported and never warned
about.
Methods (by class)
design_df(default): Count from the design's own numbers. Supplyn_psufor a clustered design ornfor an element design, withn_stratawhere the design is stratified.design_df(svyplan_cluster): Count the PSUs an_cluster()orprec_cluster()allocation selects. Unstratified, so the count is one design.design_df(svyplan_n): Count an_alloc()allocation, at the PSU stage when the frame carried cluster columns and at the element stage otherwise, or the units of a singlen_prop()orn_mean()size.design_df(svyplan_strata): Count astrata_bound()stratification, whose strata are element-stage and whose take-all strata are censuses.design_df(svyplan_twophase): Count the phase-2 units an_twophase()allocation measures. A take-all phase-2 stratum still carries the phase-1 sampling variance, so it contributes as any other does.
References
Valliant, R., Dever, J. A., and Kreuter, F. (2018). Practical Tools for Designing and Weighting Survey Samples (2nd ed.). Springer. Ch. 3.
Korn, E. L. and Graubard, B. I. (1998). Confidence intervals for proportions with small expected number of positive counts estimated from survey data. Survey Methodology, 24(2), 193–201.
See also
design_effect() for the other property of a design read off a
plan, n_prop() and n_mean(), whose df argument this is the input
to, and varcomp() for the components a clustered plan is built from.
Examples
# A stratified cluster allocation: PSUs minus strata
frame <- data.frame(
stratum = c("a", "b", "c"),
N = c(12000, 30000, 8000),
sd = c(5, 8, 3),
mean = c(10, 20, 5),
icc_psu = 0.05,
n_per_psu = 12
)
alloc <- n_alloc(frame, n = 3000)
design_df(alloc)
#> Design degrees of freedom (planning)
#>
#> df = 246 (249 PSUs - 3 strata)
design_df(alloc)$strata
#> stratum n_units df .status
#> 1 a 46 45 ok
#> 2 b 185 184 ok
#> 3 c 18 17 ok
# Drop-in wherever a df is expected
n_prop(p = 0.02, moe = 0.01, method = "beta", df = design_df(alloc))
#> Sample size for proportion (beta)
#> n = 867 (p = 0.02, moe = 0.010, deff = 1)
#> expected cases = 17.3
# From counts, with no plan in hand
design_df(n_psu = 300, n_strata = 20)
#> Design degrees of freedom (planning)
#>
#> df = 280 (300 PSUs - 20 strata)