Sufficient Condition Analysis (SCA) in R.
A condition is sufficient for an outcome when having the condition guarantees the outcome. In data, a sufficiency claim makes a definite prediction: the cases that would contradict it do not occur. Plot the condition X against the outcome Y and those cases sit in one corner of the scatter plot. "High X is sufficient for high Y" predicts that the lower-right corner -- high X with low Y -- is empty.
Sufficient Condition Analysis estimates that empty corner. It fits the boundary of the empty space, measures how large the empty space is, tests whether it is larger than random pairing of X and Y would produce, and turns the boundary into thresholds: the level of X that guarantees each level of Y.
A sufficiency claim can run in four directions, and each predicts a different empty corner:
| Direction | Claim | Empty corner |
|---|---|---|
HH |
high X is sufficient for high Y | lower-right |
LH |
low X is sufficient for high Y | lower-left |
HL |
high X is sufficient for low Y | upper-right |
LL |
low X is sufficient for low Y | upper-left |
You state the claim; the package finds the corner.
sca_compare() reports both side by side, so a
study can say which of the two its data show.sca_power() estimates how many observations a
sufficiency effect of a given size needs.install.packages("SCAtools")
The package includes four simulated datasets that show the four ways a regression effect and a sufficiency effect can combine.
library(SCAtools)
# Configuration II: a flat regression slope, but an empty lower-right corner
dat <- subset(sca_four_configurations, configuration == "II")
# 1. Fit the claim "high X is sufficient for high Y"
fit <- sca_analysis(dat, x = "X", y = "Y", direction = "HH",
scope = c(0, 100, 0, 100), test.rep = 1000)
fit # summary, with every setting the result rests on
# 2. Read the results
sca_table(fit) # effect size, p value and support for each condition
sca_thresholds(fit) # the X level that guarantees each Y level
sca_plot(fit) # the scatter plot, the frontier and the empty corner
# 3. Set it beside regression
sca_compare(fit) # here: slope near zero, large sufficiency effect
sca() runs the same analysis with a permutation test and draws the plot in
one step:
sca(dat, x = "X", y = "Y", direction = "HH")
| Function | What it shows |
|---|---|
sca_test_plot() |
the permutation distribution beside the observed effect size |
sca_scope() |
the scope each effect size was divided by |
sca_scope_sensitivity() |
how the effect size changes with the scope |
sca_resample() |
how much the effect size varies across subsamples |
sca_outliers() |
which observations hold up the frontier |
sca_locationshift() |
whether the frontier is a level shift or a threshold |
sca_magnitude() |
conventional bands for an effect size |
Effect size is the empty area as a share of the scope, from 0 (no empty
corner) to 1. effect_size_null beside it is the value random pairing alone
produces with the same data.
p value comes from a permutation test that breaks the pairing of X and Y.
effect_size_critical is the effect size random pairing exceeds only 5% of
the time (at the default test.p_threshold = 0.05): an observed effect size
beyond it is significant in a single test. sca_test_plot() draws it as a
dashed line. With several conditions, sca_table(fit, p.adjust = "holm")
adjusts the p-values for multiple testing; the critical value stays the
single-test reference line.
Thresholds read as rules such as X > 38.9 => Y > 30. no_threshold
marks an outcome level that no value of X reaches; always_satisfied marks
one that every observation in scope already meets.
Scales. A fitted model can be re-expressed without refitting:
sca_thresholds(fit, scale = "actual") # original units
sca_thresholds(fit, scale = "percentile") # percentiles
sca_thresholds(fit, scale = "sd") # standard deviations
Under the default absolute convention 0 is the low end of every axis and
the inequality carries the direction; under directional a low-level axis is
mirrored so that every rule reads as "more of the sufficient condition".
sca_scales() lists the options.
sca_scope() and the printed Settings block record it."ce_fdh") follows the data as a step function; CR-FDH ("cr_fdh") fits a
straight line through it. 1000 or more permutations are usual.relevance = if a minimum
effect size matters for the conclusion.An ordinary least-squares or median regression line can be added with
reference = "ols" or "qr". It is drawn for comparison and reported by
sca_reference(); it is not part of the sufficiency analysis.
?SCAtools describes the method and gives its references.citation("SCAtools") gives the references to cite.system.file("docs", "sufficiency-logic.md", package = "SCAtools") derives
the four directions step by step, and
system.file("examples", "four-directions.R", package = "SCAtools") runs
them.Source and issue tracker: https://github.com/youngchanresearcher/SCAtools
The Traditional Chinese version of this README is installed with the package:
file.show(system.file("docs", "README_zh-TW.md", package = "SCAtools"))