smartcor detects variable types and selects a suitable
correlation method for each pair. It supports continuous, count, binary,
ordinal, and categorical variables and returns the estimate, inference,
selected method, and rationale.
Before choosing a method, it checks the pair for outliers, normality, latent normality, and linearity. It chooses among 18 methods, following the decision framework of Harshvardhan and Ranjan (2026).
Once the package is on CRAN, a single call installs it together with
all of its dependencies (including polycor):
install.packages("smartcor")To install the supplied archive instead, use remotes
package.
remotes::install_local("smartcor.zip")The package includes gss_2024_casestudy.csv. This CSV is
frozen for reproducibility. The examples below read the bundled copy and
do not download data.
library(smartcor)
csv = system.file("extdata", "gss_2024_casestudy.csv", package = "smartcor")
gss = read.csv(csv)result = smart_cor(gss$coninc, gss$sex, verbose = FALSE)
result
#>
#> ── Smart Correlation ───────────────────────────────────────────────────────────
#> Estimate: -0.1336
#> Method: Rank-Biserial Correlation
#> Variables: gss$coninc ("continuous") x gss$sex ("binary")
#> N: 3000
#> p-value: < 0.001
#> Test: Wald test on Fisher-z scale
#> H0: delta = 0
#> Small p-values (e.g., p < 0.05) indicate evidence against H0.
#> 95% CI: [-0.1743, -0.0925]
#> Source: Cliff (1996)
#>
#> Diagnostics
#> Outliers (outer fence): none
#> Normality (Jarque-Bera): p < 2e-16 (rejected)
#>
#> The Jarque-Bera test rejects normality of the within-group residuals (p <
#> 2e-16); Rank-Biserial Correlation selected.
#>
#> ℹ Alternatives: "point_biserial" and "biserial" (pass `method = "..."` to use)The fields are available directly:
result$estimate
result$method
result$p.value
c(result$ci_lower, result$ci_upper)
result$diagnosticsSet assume_latent_normal to control pairs that can use a
latent-variable method:
smart_cor(gss$degree, gss$happy, assume_latent_normal = "auto")
smart_cor(gss$degree, gss$happy, assume_latent_normal = TRUE)
smart_cor(gss$degree, gss$happy, assume_latent_normal = FALSE)The default, "auto", runs the likelihood-ratio test of
latent normality for each affected pair. TRUE and
FALSE fix the answer; the outlier and Jarque-Bera checks
still run. A binary-by-binary table is saturated, so automatic selection
uses phi; TRUE gives tetrachoric and FALSE
gives Yule’s Q.
Each diagnostic is also available on its own. All tests use
alpha = 0.05 unless you pass another value to
smart_cor(), smart_cormat(),
smart_cor_df(), or compare_methods().
detect_outliers(gss$coninc) # outer fences, Q1 - 3 IQR and Q3 + 3 IQR
test_bivariate_normality(gss$age, gss$coninc) # Mardia's test
test_bivariate_normality(gss$coninc, gss$degree) # Jarque-Bera and the LR test
test_bivariate_normality(gss$degree, gss$happy) # LR test of the threshold model
test_linearity(gss$coninc, gss$age)For two continuous/count variables without outliers,
smart_cor() runs test_linearity(). The test
regresses each variable on the other, orders the residuals by the
regressor (averaging residuals at tied values), and applies the
Box-Pierce, Ljung-Box, BDS, Breusch-Pagan, and RESET rule in each
direction. A direction rejects linearity when a residual structure test
and RESET both reject. Spearman is selected only when both directions
reject; otherwise Pearson is retained. Each direction’s p-value is
max(min(p_bp, p_lb, p_bds), p_reset), and the combined
p-value is the larger of the two. An explicit method skips
all diagnostics.
Because both directions are tested and tied values are averaged, the
decision does not depend on argument order or row order. An inconclusive
result retains Pearson and reports the reason. When the rule recommends
robust/bootstrap Pearson inference, bootstrap = "auto" uses
a paired-bootstrap interval; the p-value remains the standard Pearson
t-test. bootstrap = FALSE disables that bootstrap.
columns = c("age", "coninc", "degree", "happy", "sex", "region")
matrix = smart_cormat(gss[, columns], seed = 1, verbose = FALSE)
matrix$methods
#> age coninc degree happy
#> age "pearson" "spearman" "kendall" "kendall"
#> coninc "spearman" "pearson" "kendall" "kendall"
#> degree "kendall" "kendall" "polychoric" "kendall"
#> happy "kendall" "kendall" "kendall" "polychoric"
#> sex "rank_biserial" "rank_biserial" "rank_biserial" "polychoric"
#> region "kw_eta_squared" "kw_eta_squared" "freemans_theta" "freemans_theta"
#> sex region
#> age "rank_biserial" "kw_eta_squared"
#> coninc "rank_biserial" "kw_eta_squared"
#> degree "rank_biserial" "freemans_theta"
#> happy "polychoric" "freemans_theta"
#> sex "phi" "cramers_v"
#> region "cramers_v" "cramers_v"matrix$correlations
matrix$types
tidy(matrix)Use smart_cor_df() when a script needs plain data
frames:
plain = smart_cor_df(gss[, columns])
plain$correlations
plain$methodsSet nearPD = TRUE when downstream analysis requires a
positive-definite matrix:
adjusted = smart_cormat(gss[, columns], nearPD = TRUE, verbose = FALSE)
adjusted$correlations
adjusted$original_correlations
adjusted$nearPD
plain = smart_cor_df(gss[, columns], nearPD = TRUE)The default is nearPD = FALSE. The adjustment calls
Matrix::nearPD(..., corr = TRUE) and preserves the diagonal
of ones. Methods, pairwise details, and tidy() retain the
original estimates and inference. Missing or infinite matrix entries
must be resolved before adjustment.
comparison = compare_methods(
gss$degree,
gss$happy,
bootstrap = FALSE,
verbose = FALSE
)
comparison$resultsplot(matrix)
ggcor_heatmap(matrix)
ggcor_method_heatmap(matrix)| Variable types | Default method | Alternative |
|---|---|---|
| Correlation methods (signed, from -1 to +1) | ||
| Continuous + continuous | Pearson (linear, no outliers) | Spearman (outliers or nonlinear), Kendall’s tau |
| Continuous + binary | Biserial (if latent normality holds) | Point-biserial; rank-biserial (outliers or non-normal) |
| Binary + binary | Pearson = phi | Tetrachoric (latent normal), Yule’s Q (no latent continuum) |
| Continuous + ordinal | Polyserial (if latent normality holds) | Kendall’s tau (m <= 5) or Spearman |
| Ordinal + ordinal | Polychoric (if latent normality holds) | Kendall’s tau (m <= 5) or Spearman; Goodman-Kruskal gamma |
| Binary + ordinal | Polychoric (if latent normality holds) | Rank-biserial; Kendall’s tau, Spearman |
| Association measures (unsigned, from 0 to 1) | ||
| Continuous + categorical | Correlation ratio eta-squared | Kruskal-Wallis eta-squared (outliers or non-normal); Cramer’s V (binned) |
| Binary + categorical | Cramer’s V | – |
| Ordinal + categorical | Freeman’s theta | Cramer’s V |
| Categorical + categorical | Cramer’s V | Theil’s U, Tschuprow’s T |
m is the number of categories of the ordinal variable (the smaller of the two for an ordinal pair). Count variables follow the continuous rows.
The package implements 18 methods: Pearson, Spearman, Kendall’s tau, point-biserial, biserial, rank-biserial, phi, tetrachoric, Yule’s Q, polychoric, polyserial, Goodman-Kruskal’s gamma, the correlation ratio (eta-squared), Kruskal-Wallis eta-squared, Freeman’s theta, Cramer’s V, Tschuprow’s T, and Theil’s U. Each comes with a confidence interval and a p-value.
The accompanying paper, smartcor: Intelligent Correlation Method Selection for Mixed Variable Types by M. Harshvardhan and Pritam Ranjan (2026), is available as an arXiv preprint: arXiv:2607.22285 (doi:10.48550/arXiv.2607.22285). The package vignettes cover the same material: method selection, the underlying theory, and inference.
M. Harshvardhan (maintainer) and Pritam Ranjan.
GPL (>= 3)