The get_*() metrics answer “how does this organization look on this ratio?” The fiscal-health index answers a harder question: “how does this organization look overall?” It combines many standardized indicators into a small number of empirical dimensions and, optionally, a single composite score.
Rather than hard-code a formula, fiscal builds a reusable measurement model in explicit stages. Each stage is a separate function that returns an inspectable object, so the pipeline is auditable and the fitted model can be re-applied to later panel years without re-estimating anything.
fiscal_diagnostics() -> fiscal_triage() -> fiscal_dimensions()
(screen indicators) (decide keep/drop) (discover structure)
|
fiscal_health_index() <- fiscal_weights() <- fiscal_health_score() <- fiscal_health_fit()
(composite score) (combine) (apply model) (freeze the model)
Two stages deliberately require human judgment — fiscal_triage() recommends but lets you override, and fiscal_dimensions() discovers but does not name dimensions. The wrapper fiscal_health() chains the mechanical stages once you have reviewed the structure.
This subsystem uses the
psychpackage for factor-analytic diagnostics; make sure it is installed.
Prepare indicators
Indicators should be the standardized (_z) versions of the metrics, so they share a common scale. Compute them with compute_all() and select a curated, non-redundant set spanning the fiscal-health domains:
scored <- compute_all(dat10k, metrics = "z", verbose = FALSE)
indicators <- scored[, c(
"current_z", "cash_assets_z", "cash_burn_z", # liquidity
"debt_assets_z", "equity_z", # solvency
"surplus_margin_z", "op_reserve_z", # performance / reserves
"prog_exp_z", "overhead_z", # expense structure
"donations_rev_z", "earned_income_z", # revenue structure
"netassets_growth_z" # growth
)]
dim(indicators)
#> [1] 10000 12Stage 1 — diagnose
fiscal_diagnostics() computes variable-level diagnostics that distinguish indicators participating in a shared multivariate structure from those that are redundant, standalone, or noisy (correlation summaries, KMO/MSA, communalities, and so on).
diagnostics <- fiscal_diagnostics(indicators)
diagnostics
#> Fiscal indicator diagnostics
#> Indicators: 12
#> Redundant pairs: 1
#> Near-zero variance: 0Stage 2 — triage
fiscal_triage() turns those diagnostics into an auditable recommendation: which indicators to retain for dimension estimation, which to keep as standalone measures, and which to drop as redundant or noise. Recommendations can be overridden with the overrides argument.
triage <- fiscal_triage(diagnostics)
triage
#> Fiscal indicator triage
#> Dimension candidates: 7
#> Standalone indicators: 3
#> Redundant exclusions: 1
#> Noise exclusions: 1Stage 3 — discover dimensions
fiscal_dimensions() uses PCA (or exploratory factor analysis) to propose empirical dimensions from the retained indicators. It discovers and describes groupings; it does not name them or orient the scores — that is your call.
dimensions <- fiscal_dimensions(
indicators,
triage = triage,
method = "pca",
nfactors = 3,
seed = 42
)
dimensions
#> Fiscal dimension discovery
#> Method: PCA
#> Dimensions: 3 ( specified )
#> Multi-indicator dimensions: 3
#> Cross-loading indicators: 0
#> Unassigned indicators: 0Stage 4 — fit a reusable model
fiscal_health_fit() freezes the reviewed dimensions into a scoring specification. The fitted object stores indicator orientation, centers, scales, missing-value treatment, and dimension coefficients — everything needed to score new data identically later.
fit <- fiscal_health_fit(indicators, dimensions = dimensions)
fit
#> Fitted fiscal-health measurement model
#> Dimensions: 3
#> Standalone indicators: 3
#> Reference observations: 10000
#> Missing-value rule: median
#> Direction warnings: 1Stage 5 — score
fiscal_health_score() applies the fitted model. No parameters are re-estimated; it just transforms and combines indicators into dimension scores (prefixed fh_). Because the model is frozen, the same fit can score a different panel year on the same scale.
scored_dims <- fiscal_health_score(indicators, fit)
head(grep("^fh_Dimension", names(scored_dims), value = TRUE))
#> [1] "fh_Dimension1" "fh_Dimension2" "fh_Dimension3"
#> [4] "fh_Dimension1_coverage" "fh_Dimension2_coverage" "fh_Dimension3_coverage"Stage 6 — weight
fiscal_weights() defines how dimension scores and standalone indicators combine into the composite. The default is equal weighting; min_coverage controls how much of an observation’s weighted inputs must be present before it receives a score.
weights <- fiscal_weights(fit, min_coverage = 0.5)
weights
#> Fiscal-health weights
#> Method: equal
#> Measures: 6
#> Missing-score rule: reweight
#> measure measure_type original_weight weight
#> Dimension1 dimension 1 0.1666667
#> Dimension2 dimension 1 0.1666667
#> Dimension3 dimension 1 0.1666667
#> cash_assets_z standalone 1 0.1666667
#> cash_burn_z standalone 1 0.1666667
#> overhead_z standalone 1 0.1666667Stage 7 — the composite index
fiscal_health_index() produces the single composite score (and a coverage column recording how much information each score is based on).
indexed <- fiscal_health_index(scored_dims, weights)
summary(indexed$fiscal_health)
#> Min. 1st Qu. Median Mean 3rd Qu. Max.
#> -2.235332 -0.233509 0.007322 0.000000 0.202435 1.984951The shortcut: fiscal_health()
Once you have reviewed the triage and dimensions, fiscal_health() runs the mechanical stages — fit, score, weight, index — in one call:
result <- fiscal_health(indicators, dimensions = dimensions)
result
#> Fiscal-health result
#> Mode: fit_and_score
#> Observations: 10000
#> Dimensions: 3
#> Standalone indicators: 3
#> Composite index: yesIt deliberately does not automate diagnostics, triage, or dimension discovery, because those stages require substantive review.
Scoring new data with a fitted model
The payoff of separating fit from score is reuse. Fit the model once on a reference sample (say, one panel year), then score every other year on the same scale by passing the stored fit:
fit <- fiscal_health_fit(indicators_2019, dimensions = reviewed_dims)
scores_2020 <- fiscal_health_score(indicators_2020, fit)
scores_2021 <- fiscal_health_score(indicators_2021, fit)This keeps scores comparable across years — exactly what you need when the index feeds a longitudinal analysis of the panel you built in vignette("panel-workflow").