Enumerate the candidate family on a DGM's population frame
Source:R/fs_oc_family.R
fs_oc_family_enumerate.RdBuilds the family of candidate subgroups that forestsearch
would search over, but on the DGM's super-population frame
dgm$df_super rather than on a sampled trial, so that every cut lands
at a population quantile and every prevalence, purity and overlap is a
population proportion. The result carries the nine quantities the
operating-characteristics prediction of fs_oc_predict consumes.
Arguments
- dgm
An object of class
"glm_dgm"fromgenerate_glm_dgm, with the true-region indicator indf_super$flag_harm.- forestsearch_args
Named list of
forestsearcharguments.confounders.nameis required; the cut,maxk,minp,rmin,n.minandn.min.fracentries are read, and any omitted entry takesforestsearch()'s default.- n
Integer. Trial size at which the family is evaluated: sets the size floor
n.min / nand thesqrt(1000 / n)rescaling of the anchored standard errors.- max_M
Integer. Size guard: if more than
max_Mcandidates survive the floors, the function stops before allocating the M-by-M overlap matrix (the downstream symmetric root is O(M^3)).- verbose
Logical. Print the enumeration counts at each stage.
Value
An object of class c("fs_oc_family", "list") with elements
labCharacter, length M: the rule of each candidate.
PgPopulation prevalence
P(g).PQgPurity
P(g & Q) / P(g).beta_gOriented mixture mean
s * (m_tau[Qc] + (m_tau[Q] - m_tau[Qc]) * PQg), withs = sign(m_tau[Q])the harm direction.se_gAnchored standard error at
n.sens_gP(g & Q) / P(Q).spec_g1 - P(g & Qc) / P(Qc).ovlM-by-M matrix of
P(g_i & g_j).MNumber of candidates.
PQP(Q), the prevalence of the true region.membLogical matrix,
nrow(df_super)by M, the population membership of each candidate.nullLogical:
TRUEwhen the null branch was taken (Q empty).orientationAlternative branch only: list with the harm-direction sign
s, the signed region effectsm_tau_Qandm_tau_Qc, and the oriented mixture coefficientstauQc = s * m_tau_Qc(may be negative for opposite-sign families) andbint = s * (m_tau_Q - m_tau_Qc). Absent on the null branch.scaleThe
fs_dgm_scaleobject used.nThe trial size.
args_usedThe
forestsearch_argsentries consumed, with the resolvedn.min.cutsThe cut expressions
get_FSdata()produced.countsNamed integer vector: candidates at each stage.
Details
Cuts. The cut-related entries of forestsearch_args
(confounders.name, conf.cont_jcuts, cut_type,
cont.cutoff, conf.cont_medians, conf.cont_medians_force,
conf_force, defaultcut_names, exclude_cuts,
collapse_cuts, collapse_cuts_args) are handed to the package's
own get_FSdata() on df_super. Both directions of every cut are
generated, as the search does. LASSO, GRF and DINA cut sources are off: they
are sample-fitted screens, not part of the cut specification.
Combinations. All combinations of up to maxk indicator
columns are enumerated with generate_combination_indices(), in the
order forestsearch() uses when it composes the MR family.
Structural floors (all on the population frame, in the order of
evaluate_combination_with_status()):
combinations with a constant column or an empty pairwise intersection are skipped (the search's status 0);
minp: every constituent factor must have population prevalence>= minp;rmin: each added factor must shrink the membership by more thanrminsubjects of a trial of size n, i.e. by more thanrmin / nin population proportion;size:
Pg >= n.min / n, wheren.minis resolved asforestsearch()resolves it – the supplied value (default 60), ormax(60, ceiling(n.min.frac * n))whenn.min = NULL.
The GRF variable-importance pre-screen, the effect screen, the consistency screen and the near-duplicate removal are not applied. Candidates whose population membership vectors are identical are collapsed to the first one enumerated.
Null DGMs. A DGM whose df_super$flag_harm has no member
(Q empty; generate_glm_dgm(model = "null")) is detected
structurally, cross-checked against dgm$model when present. Under
the null every candidate has the same true effect, so the fields become:
beta_g = the common effect (the DGM's effect_Qc =
effect_ITT, oriented as the alternative path orients);
se_g from the whole-population effective variance
(fs_dgm_scale(dgm, regions = list(S = ...)), the S row) at
(n, Pg) with the same prevalence scaling; PQg = 0;
sens_g = NA (0/0, undefined – not zero); spec_g = 1 - Pg;
PQ = 0 (from which NPV = 1 follows downstream). Enumeration, floors,
ovl and the covariance are unchanged. The element null
records the branch taken.
Scale. Every mean and standard error is derived from
fs_dgm_scale(dgm). The orientation is the harm direction
s = sign(m_tau[Q]), so the planted effect is oriented positive:
with Q the true harm region, tauQc = s * m_tau[Qc],
bint = s * (m_tau[Q] - m_tau[Qc]),
seQ1000 = sqrt(V_eff[Q] / (1000 * P(Q))), and for each candidate
beta_g = tauQc + bint * PQg – the signed mixture
s * (m_tau[Qc] + (m_tau[Q] - m_tau[Qc]) * PQg) – and
se_g = seQ1000 * sqrt(1000 / n) * sqrt(P(Q) / Pg) (sign-free, from
V_eff[Q]). Opposite-sign families (sign(m_tau[Qc]) != s)
are supported: benefit-direction candidates carry oriented-negative
beta_g, and tauQc may be negative for such families. When
both region effects share a sign the values coincide exactly with the
former oriented-absolute reading. A DGM with m_tau[Q] exactly zero
is rejected (no harm direction to orient by): plant a nonzero Q effect or
use the null path.
Examples
# \donttest{
set.seed(1)
N <- 2000
age <- round(rnorm(N, 35, 9)); pre <- round(rexp(N, 1 / 500))
V <- factor(rbinom(N, 1, 0.42), levels = 0:1)
inQ <- as.integer(age > 34 & pre <= 745)
mu0 <- 40 + 0.2 * age
dgm <- structure(list(
df_super = data.frame(age = age, preanti = pre, V = V,
mu0 = mu0, mu1 = mu0 - 26 - 14 * inQ,
flag_harm = inQ),
outcome_type = "continuous", effect_measure = "MD",
model_params = list(sigma = 127.5)), class = c("glm_dgm", "list"))
fam <- fs_oc_family_enumerate(
dgm, list(confounders.name = c("age", "preanti", "V"),
conf.cont_jcuts = list(age = 4, preanti = 4), n.min = 60),
n = 500)
fam
#> Population-enumerated candidate family (fs_oc_family)
#> M : 104 candidates (from 18 cut columns, maxk = 2)
#> n : 500
#> floors : n.min = 60 (Pg >= 0.1200), minp = 0.025, rmin = 5
#> prevalence : 0.1205 to 0.8215
#> P(Q) : 0.3980; purity range 0.000 to 1.000
#> dropped : empty 21, minp 0, rmin 12, size 22, duplicate 12
# }