Finds pairs of variables whose absolute correlation exceeds threshold
and, by default, drops variables until no such pair remains, keeping one
representative of each correlated group.
Usage
fs_correlation(
data,
threshold,
method = "pearson",
prune = TRUE,
na.rm = FALSE,
sample_frac = 1,
output_format = "matrix",
diag_value = 0,
seed = NULL,
verbose = FALSE,
parallel = FALSE,
n_cores = 2L
)Arguments
- data
A data frame or matrix with at least 2 columns. Column names must be unique, non-empty, and not
NA; duplicated names are an error because a correlation matrix with duplicated names is ambiguous. The allowed column types depend onmethod:"pearson","spearman","kendall": all numeric."polychoric": all ordered factors."pointbiserial": numeric, or any type with exactly 2 distinct non-missing values. A numeric column with more than 2 distinct values counts as continuous, and a column with exactly 2 counts as dichotomous. At least one of each is needed, or every correlation isNA(with a warning).
- threshold
Absolute-correlation cutoff between 0 and 1. Pairs with an absolute correlation strictly greater than
thresholdare flagged. Required; there is no default.- method
One of
"pearson"(default),"spearman","kendall","polychoric"(needs the suggested polycor package), or"pointbiserial". The point-biserial correlation is the Pearson correlation between a continuous variable and a 0/1 indicator of a dichotomous one, where 1 marks the second sorted value (for a factor, the second level). Only continuous-dichotomous pairs have one, so under this method every continuous-continuous and dichotomous-dichotomous cell staysNAand those pairs are never flagged.- prune
If
TRUE(default),selectedis the reduced set left after pruning (see "How pruning works"). IfFALSE, nothing is dropped andselectedis every variable in at least one flagged pair: the redundant set, not the set to keep.- na.rm
How to handle missing values. If
TRUE, they are removed pairwise for"pearson","spearman", and"kendall"; within each pair for"pointbiserial"; and casewise (rows complete across all columns) for"polychoric". IfFALSE(default), a missing value makes the affected correlationsNA, except under"polychoric", which stops with an error instead of silently dropping rows.- sample_frac
Fraction of rows, in (0, 1], to sample without replacement before computing correlations. The sample size is rounded up and is never below one row. Default 1 (no sampling).
- output_format
Shape of
details$corr_matrix:"matrix"(default) or"data.frame"(long form).- diag_value
Single number, or
NA, written on the diagonal ofdetails$corr_matrix. The diagonal never takes part in flagging, scoring, or pruning. Default 0.- seed
Optional integer seed for the row sampling. It is applied for this call only and the previous RNG state is restored afterward. It has no effect when
sample_frac = 1, and parallel point-biserial computation uses no random numbers. DefaultNULL(featR does not touch the RNG).- verbose
If
TRUE, report row sampling, the correlation method, and any variables dropped by pruning. DefaultFALSE.- parallel
If
TRUE, compute point-biserial correlations in parallel with the suggested foreach and doParallel packages. Every other method computes the matrix in one call and ignores this. DefaultFALSE.- n_cores
Number of workers when
parallel = TRUEandmethod = "pointbiserial", a whole number of at least 1, capped at the detected core count. Default 2.
Value
An fs_result object with:
selectedWith
prune = TRUE, every variable not indetails$dropped; no two of them have a computable absolute correlation abovethreshold. Withprune = FALSE, both members of every flagged pair.scoresNamed numeric vector giving each variable's largest absolute correlation with any other variable. Larger means more redundant.
NAwhen no correlation with that variable could be computed.methodpaste0("correlation_", method), for example"correlation_pearson".taskNA; the filter uses no outcome.modelNULL; no model is fitted.detailsA list with:
corr_matrix: the correlation matrix withdiag_valueon the diagonal, or, whenoutput_format = "data.frame", the same values in long form with columnsVar1,Var2,Correlation.pairs: a data frame of the flagged pairs (Var1,Var2,Correlation), strongest absolute correlation first, whateveroutput_formatis.dropped: variables removed by pruning, in the order they were dropped; empty whenprune = FALSE.redundant: every variable in at least one flagged pair, which isselectedas it would be underprune = FALSE.n_features: the number of variables considered.
callThe matched call.
Details
This is an unsupervised redundancy filter. It looks only at how the
variables relate to one another, never at an outcome, so when two
variables are nearly interchangeable it cannot keep the one that predicts
better. It keeps whichever is less correlated with the rest of the data.
Use fs_boruta() when the choice within a correlated group should depend
on importance for a target.
How pruning works
Pruning is greedy. While any pair of retained variables still has an
absolute correlation above threshold, the strongest such pair is taken,
and the member with the larger mean absolute correlation to the other
retained variables is dropped (on an exact tie, the later column). Afterward
no two retained variables have a computable correlation above
threshold. The surviving set is not guaranteed to be the smallest one
with that property, and it can depend on the order in which pairs are
resolved.
This borrows the tie-break of caret::findCorrelation() but not its scan
order: caret visits columns in order of mean correlation rather than
pairs in order of strength, so the two can drop different variables.
Variables that were never flagged are always kept.
Correlations that cannot be computed
A correlation that cannot be computed is NA. Such pairs are never
flagged and never pruned, because an unknown correlation is no evidence of
redundancy, and a warning reports how many there are. When no pair
exceeds threshold, a message (not a warning) says so, whatever
verbose is set to.
See also
The Filter methods guide, which runs this function on a worked example.
Examples
d <- data.frame(
a = c(1, 2, 3, 4, 5, 6),
b = c(2, 4, 6, 8, 10, 12),
c = c(1.5, 0.9, 2.1, 0.4, 1.1, 0.8)
)
res <- fs_correlation(d, threshold = 0.9)
res$selected
#> [1] "a" "c"
res$details$pairs
#> Var1 Var2 Correlation
#> 1 a b 1
# Both members of every flagged pair, with nothing dropped
fs_correlation(d, threshold = 0.9, prune = FALSE)$selected
#> [1] "a" "b"