Unsupervised filter that scores each feature without a target
Source:R/fs_unsupervised.R
fs_unsupervised.RdScores each column of data with a summary that ignores any outcome
(variance, spread, missingness, or number of distinct values) and keeps or
drops each column by comparing its score with threshold.
Usage
fs_unsupervised(
data,
method = c("variance", "mad", "iqr", "range", "missing_prop", "n_unique"),
threshold = 0,
direction = c("above", "below"),
action = c("keep", "remove"),
include_equal = FALSE,
na_rm = TRUE,
output = c("result", "matrix", "dt", "data.frame", "mask", "indices", "names", "list"),
verbose = FALSE
)Arguments
- data
A data.frame, data.table, or matrix whose columns are all numeric. Every column is a candidate feature. The input is copied, never modified in place.
- method
One of
"variance"(default),"mad","iqr","range","missing_prop", or"n_unique". See Details.- threshold
Non-negative, finite number compared with each feature's score. Default 0. Each method has its own scale (a variance is in squared units,
"missing_prop"lies in[0, 1],"n_unique"is a count), so a threshold chosen for one method does not carry over to another.- direction
"above"(default) or"below": which side ofthresholda score must fall on to meet the condition.- action
"keep"(default) retains the features that meet the condition;"remove"drops them.- include_equal
Logical. If
TRUE, a score equal tothresholdmeets the condition. DefaultFALSE.- na_rm
Logical. If
TRUE(the default),NAs are removed before computing"variance","mad","iqr", and"range"; ifFALSE, anNAin a column makes its scoreNAunder those methods."missing_prop"and"n_unique"ignorena_rm.- output
Shape of the return value.
"result"(default): anfs_resultobject (see Value)."matrix","dt","data.frame": the selected features as a numeric matrix, a data.table, or a data.frame."mask": logical vector of lengthncol(data), named after the columns ofdata;TRUEmarks a selected column."indices": integer positions of the selected columns, named after them."names": character vector of the selected column names."list": a list withfiltered(matrix),mask,indices,names,scores, andmeta.metarecordsmethod,threshold,direction,action,include_equal,na_rm,n_input_cols, andn_kept_cols.
- verbose
Logical; print progress messages. Default
FALSE.
Value
With output = "result" (the default), an fs_result object:
selected: character vector of selected feature names.scores: named numeric vector with one score per column, in column order,NAwhere the score is undefined.method:"unsupervised_"followed by the method, for example"unsupervised_variance".task:NA_character_, since there is no target.model:NULL.details: a list holding, in this order,mask(the logical keep-mask over the columns),indices(selected positions, named),filtered(the selected columns as a data.table),threshold,direction,action, andn_features(ncol(data)).call: the matched call.
Any other output returns the shape described under output.
When no feature meets the criteria, a warning is issued and the tabular
shapes come back empty. "matrix" and "data.frame" then have zero
columns and keep the input row count. The "dt" shape and
details$filtered have zero columns and also zero rows, because
data.table represents a zero-column table that way.
Details
Use it for the first cleaning pass: dropping constant or near-constant
columns, columns that are mostly missing, or columns with too few distinct
values. No outcome informs the scores, so it is safe to run before a
train/test split. For the same reason it says nothing about whether a
feature is useful. A high-variance column can be pure noise and a
low-variance one can be your best predictor; fs_supervised() or a
model-based method answers that question.
The six values of method:
"variance"(default): sample variance (denominator n - 1), in squared units. For values below about1e-162in magnitude the variance underflows to 0, so to find constant columns in extreme units use"range"with threshold 0 or"n_unique"with threshold 1."mad": median absolute deviation fromstats::mad(), which multiplies by the consistency constant 1.4826. Scores are on the scale of a standard-deviation estimate, not the raw median absolute deviation; choose thresholds on that scale."iqr": interquartile range."range": maximum minus minimum."missing_prop": proportion of missing values, in[0, 1]. With the defaultthreshold = 0,direction = "above", andaction = "keep", this keeps the columns that have any missing values and drops the complete ones, which is almost never what you want. A warning then suggestsaction = "remove"ordirection = "below". The warning fires only when all three ofthreshold,direction, andactionare left at their defaults; passing any one of them explicitly silences it."n_unique": number of distinct non-NAvalues.
A feature whose score is NA is never selected, whether action is
"keep" or "remove", and a warning reports how many features were
excluded this way.
Columns are subset by position, never by name, so duplicated column names
cannot pull in the wrong column. Every column needs a non-empty,
non-NA name. A matrix keeps its own column names; V1, V2, ... are
used only when it has none.
See also
The Filter methods guide, which runs this function on a worked example.
Examples
df <- data.frame(
spread = c(1, 2, 3, 4, 100),
flat = c(2, 2, 2, 2, 2),
gappy = c(1, NA, 3, NA, 5)
)
# Default: an fs_result
res <- fs_unsupervised(df, method = "variance", threshold = 0.5)
res$selected
#> [1] "spread" "gappy"
res$scores
#> spread flat gappy
#> 1902.5 0.0 4.0
res$details$filtered
#> spread gappy
#> <num> <num>
#> 1: 1 1
#> 2: 2 NA
#> 3: 3 3
#> 4: 4 NA
#> 5: 100 5
# The classic shapes are still available
fs_unsupervised(df, method = "variance", threshold = 0.5,
output = "matrix")
#> spread gappy
#> [1,] 1 1
#> [2,] 2 NA
#> [3,] 3 3
#> [4,] 4 NA
#> [5,] 100 5
# Remove features with missing proportion >= 0.2
fs_unsupervised(df, method = "missing_prop", threshold = 0.2,
direction = "above", action = "remove",
include_equal = TRUE, output = "names")
#> [1] "spread" "flat"