Detects variable types (continuous, count, binary, ordinal,
categorical), checks outliers, normality, latent normality, and
linearity, and selects the appropriate correlation method for each
pair. Supports 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 with a confidence interval and
p-value. Explains the selection
rationale in the output, follows tidy data principles, and works in
both interactive and scripted workflows. The methodology is described
in Harshvardhan and Ranjan (2026)
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$diagnostics
Set 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$methods
Set 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$results
plot(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)