partial_cor() computes partial correlations between variables
while controlling for one or more other variables — the SPSS
PARTIAL CORR procedure (Stata: pcorr). It answers the
question "how strongly are x and y related once the influence of the
control variables is removed?"
Arguments
- data
Your survey data (a data frame or tibble). If grouped (via
dplyr::group_by()), separate partial correlations are computed per group (SPSS SPLIT FILE).- ...
Variables to correlate (unquoted, supports tidyselect). At least two.
- controls
Control variable(s) to partial out (unquoted, supports tidyselect; SPSS
BYlist). At least one, must not overlap with the analysis variables.- weights
Optional survey weights (unquoted variable name), treated as frequency weights matching SPSS
WEIGHT BY.
Value
An object of class "partial_cor" whose
$correlations tibble holds one row per variable pair (and
group combination) with:
- partial_r
Partial correlation controlling for the
controls- zero_order_r
The ordinary (zero-order) Pearson correlation of the pair, for comparison — SPSS
/STATISTICS=CORR- df
Degrees of freedom, n - 2 - k with k control variables (non-integer for weighted data, Charter §5.1)
- t_stat, p_value
t-test of the partial correlation (two-tailed, the SPSS default)
- n
Listwise-complete sample size (rounded weighted N when weighted)
For three or more analysis variables, $matrices additionally
holds the full partial-correlation matrix per group.
Details
Understanding the Output
Comparing partial_r against zero_order_r tells you what
the controls contribute:
Partial clearly smaller than zero-order: much of the original association runs through the control variables (confounding or mediation).
Partial similar to zero-order: the association is largely independent of the controls.
Partial larger than zero-order: a suppressor situation — the controls masked part of the association.
When to Use This
Check whether a bivariate correlation survives controlling for demographics (age, education, ...)
Separate the direct association of two attitudes from what a shared cause explains
For full multivariate control with several predictors, use
linear_regression instead.
Technical Details
Cases are deleted listwise across the analysis and control
variables (SPSS /MISSING=LISTWISE, the PARTIAL CORR default).
The partial correlation is computed from the Pearson correlation
matrix of all variables via the inverse of the control-variable block;
the same Pearson formula as pearson_cor is used
throughout, so weighted results follow the SPSS frequency-weight
convention with unrounded sum(w) in df and test statistics.
Significance is two-tailed (the SPSS default).
An SPSS v29 PARTIAL CORR reference run is pending; until it lands the statistics are verified against the independent residual-of-regressions characterization (see the SPSS compatibility vignette).
See also
pearson_cor for zero-order correlations.
linear_regression for multivariate control.
summary.partial_cor for detailed output.
Other correlation:
kendall_tau(),
pearson_cor(),
spearman_rho()
Examples
library(dplyr)
data(survey_data)
# Does the satisfaction-income correlation survive controlling for age?
partial_cor(survey_data, life_satisfaction, income, controls = age)
#> Partial Correlation: life_satisfaction, income | controlling for age
#> life_satisfaction x income: partial r = 0.448, p < 0.001 *** (zero-order r = 0.448), N = 2115
#> Use summary() for detailed output.
# Several variables, several controls
partial_cor(survey_data, trust_government, trust_media, trust_science,
controls = c(age, political_orientation))
#> Partial Correlation: trust_government, trust_media, trust_science | controlling for age, political_orientation
#> trust_government x trust_media: partial r = 0.019, p = 0.390 (zero-order r = 0.019), N = 1964
#> trust_government x trust_science: partial r = 0.033, p = 0.148 (zero-order r = 0.030), N = 1964
#> trust_media x trust_science: partial r = 0.009, p = 0.684 (zero-order r = 0.010), N = 1964
#> Use summary() for detailed output.
# Weighted (SPSS WEIGHT BY)
partial_cor(survey_data, life_satisfaction, income,
controls = age, weights = sampling_weight)
#> Partial Correlation: life_satisfaction, income | controlling for age [Weighted]
#> life_satisfaction x income: partial r = 0.450, p < 0.001 *** (zero-order r = 0.450), N = 2130
#> Use summary() for detailed output.
# Grouped (SPSS SPLIT FILE)
survey_data %>%
group_by(gender) %>%
partial_cor(life_satisfaction, income, controls = age)
#> Partial Correlation: life_satisfaction, income | controlling for age
#> [gender = Male]
#> life_satisfaction x income: partial r = 0.455, p < 0.001 *** (zero-order r = 0.455), N = 1005
#> [gender = Female]
#> life_satisfaction x income: partial r = 0.441, p < 0.001 *** (zero-order r = 0.442), N = 1110
#> Use summary() for detailed output.
# --- Three-layer output ---
result <- partial_cor(survey_data, life_satisfaction, income, controls = age)
result # compact overview
#> Partial Correlation: life_satisfaction, income | controlling for age
#> life_satisfaction x income: partial r = 0.448, p < 0.001 *** (zero-order r = 0.448), N = 2115
#> Use summary() for detailed output.
summary(result) # full detailed output
#>
#> Partial Correlation Results
#> ---------------------------
#> - Variables: life_satisfaction, income
#> - Controlling for: age
#> - Missing: Listwise deletion
#>
#> Pairwise Results:
#> --------------------------------------------------------------------------------------
#> Variable 1 Variable 2 Partial r Zero-order r df t p n sig
#> --------------------------------------------------------------------------------------
#> life_satisfaction income 0.448 0.448 2112 23.037 <.001 2115 ***
#> --------------------------------------------------------------------------------------
#>
#> Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05
