Cheat sheets

Feature Engineering and Pipelines

Impute, scale, encode, select and ensemble inside one leak-free pipeline. Python from the lessons.

  • Concepts and terms
  • Tasks and commands
  • Annotated code
  • Diagrams
  • Defaults and numbers
  • Troubleshooting
  • Questions and tips

Source

One pipeline for mixed columns#

numeric colscategorical colsfitTraining dataX_train onlynumeric_pipemedian impute,scalecategorical_pipemost_frequent,one-hotColumnTransformerpreprocess stepModelGradientBoostingClassifierPredictiontransform, thenpredictnumeric colscategorical colsfitTraining dataX_train onlynumeric_pipemedian impute, scalecategorical_pipemost_frequent, one-hotColumnTransformerpreprocess stepModelGradientBoostingClassifierPredictiontransform, then predict

Build it in sklearn#

numeric_pipe = Pipeline([
("impute", SimpleImputer(strategy="median")),
("scale", StandardScaler()),
])
categorical_pipe = Pipeline([
("impute", SimpleImputer(strategy="most_frequent")),
("encode", OneHotEncoder(handle_unknown="ignore")),unseen city gives zeros
])
preprocessor = ColumnTransformer([
("num", numeric_pipe, ["age", "income", "score"]),
("cat", categorical_pipe, ["city", "gender", "plan"]),
])
full_pipeline = Pipeline([("preprocess", preprocessor),
("model", GradientBoostingClassifier())])

What fit and predict do#

1Split firstX_train, X_test = X[:800], X[800:] before anyfit.2pipe.fiteach transformer calls fit_transform on X_train.3pipe.fitthe last step calls fit on the transformedX_train.4pipe.predicteach transformer calls transform, notfit_transform.5pipe.predictthe model calls predict on the transformedX_test.6Cross-validationeach fold fits the preprocessor on its owntraining split.

Transform and encode tasks#

TaskCode
Scale to [0, 1]min_max_scale(values)
Mean 0, std 1standardize(values)
Compress right skewlog_transform(values) uses log(v + 1)
Equal-width binsbin_values(values, n_bins=5)
Squares and pairspolynomial_features(row, degree=2)
Smoothed target meantarget_encode(feature_values, target_values, smoothing=10)
Flag holes firstadd_missing_indicator(values)
Text weightstfidf(documents) returns vectors, vocab

Feature selection tasks#

TaskCode
Drop near-constant columnsvariance_threshold(X, threshold=0.01)
Rank by MImutual_information(X, y, n_bins=10)
Prune by weightrfe(X, y, n_features_to_select=5)
Zero weights with L1l1_feature_selection(X, y, alpha=0.1)
Split-gain importancetree_importance(X, y, n_trees=50)
sklearn RFERFE(LogisticRegression(), n_features_to_select=10)
sklearn L1SelectFromModel(Lasso(alpha=0.01))
sklearn treesrf.feature_importances_

Ensembles: use X when#

CommandWhat it does
Bagging / Random ForestCuts variance. Noisy data, many features
AdaBoostCuts bias. Clean data. Hurt by outliers
Gradient BoostingCuts bias. Tabular data. Easy to overfit
XGBoost / LightGBMBoth. Start here for production tabular ML
StackingBoth. Last 1-2% accuracy. Use CV meta-features
Soft votingAverage probabilities of diverse models

Boosting loops#

weights = np.full(n, 1 / n)AdaBoost starts uniform
err = np.clip(err, 1e-10, 1 - 1e-10)weighted stump error
alpha = 0.5 * np.log((1 - err) / err)low error, high vote
weights *= np.exp(-alpha * y * pred)misses gain weight
weights /= weights.sum()
self.initial_pred = np.mean(y)gradient boosting start
residuals = y - current_predsquared error gradient
current_pred += self.lr * updateshrink each tree

Defaults and numbers#

SettingDefaultNote
Target encoding smoothing10Pulls rare categories to the global mean
remove_correlated threshold0.9Drops the second column of a pair
AdaBoostScratch n_estimators50Decision stumps
GradientBoostingScratch100learning_rate=0.1, max_depth=3
BaggingClassifier20n_estimators=20, max_depth=5
Learning rate range0.01 to 0.3Smaller needs more trees
Bootstrap unique rows63.2%36.8% out-of-bag for validation
Forest split featuressqrt(n_features)n_features / 3 for regression

Pipeline failures#

SymptomCauseFix
Test score too highScaler fit before the splitUse Pipeline with cross_val_score
Train and serve outputs differTransforms outside the pipelineOne Pipeline object for both
Crash on a new cityEncoder never saw the valueOneHotEncoder(handle_unknown="ignore")
Breaks on schema changeHardcoded column namesColumn name lists from config
Random ID ranks highTree importance cardinality biasCheck with permutation importance
Target encoding overfitsEncoded on test rowsFit on train data only, smooth
Stacking leaksMeta-features from fitted dataGenerate them with cross-validation

Formulas#

TF-IDF
\frac{\text{count in doc}}{\text{words in doc}} \cdot \log \frac{\text{docs}}{\text{docs with word}}
Mutual information
I(X; Y) = \sum_x \sum_y p(x, y) \log \frac{p(x, y)}{p(x) p(y)}, zero when independent.
L1 loss
prediction error plus \alpha \sum \lvert w_i \rvert. Higher alpha zeros more weights.
Majority vote
21 classifiers at 60% give about 74%. 101 give 84%.
RFE cost
N - \text{target} trainings. 500 features to 10 is 490 runs.
MI bins
\sqrt{n} bins or Sturges' rule 1 + \log_2 n.

Questions#

Why scale features?
K-Means, KNN and SVM use distance. Scaling makes all features count equally.
Why add a missing indicator?
The fact that data is missing can itself be informative.
Why MI and not correlation?
MI catches quadratic or periodic links. Correlation can read zero.
Why soft voting?
It uses confidence information. It is usually better than hard voting.
What makes a run reproducible?
Fixed seeds, pinned dependencies, versioned data and config files.
Which model first on tabular data?
LightGBM or XGBoost with default parameters.