Claude Skill

alterlab-scikit-learn

Classical machine learning in Python with scikit-learn — algorithms, preprocessing, pipelines, and best-practice reference documentation. Use when working with supervised learning (classification, regression), unsupervised learning (clustering, dimensionality reduction), model ev

LLM Mart · 0 points · 0 views 0 listing impressions 0 install-command copies
Virus-scanned Reviewed automatically before listing.

Full trust report

Download alterlab-ieu-alterlab-academic-skills-skills_data-science_alterlab-scikit-learn-e4836c0.zip · 40 KB
Part of alterlab-ieu/alterlab-academic-skills — 94 skills

Install

skills CLI npx skills add https://github.com/AlterLab-IEU/AlterLab-Academic-Skills/tree/main/skills/data-science/alterlab-scikit-learn
Claude Code claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install alterlab-ieu-alterlab-academic-skills@llmmart
Git git clone https://github.com/AlterLab-IEU/AlterLab-Academic-Skills.git

The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole alterlab-ieu/alterlab-academic-skills collection as a plugin from our marketplace. Git is the plain clone.

Skill manifest

Scikit-learn

Overview

This skill provides comprehensive guidance for machine learning tasks using scikit-learn, the industry-standard Python library for classical machine learning. Use this skill for classification, regression, clustering, dimensionality reduction, preprocessing, model evaluation, and building production-ready ML pipelines.

Installation

# Install scikit-learn using uv
uv pip install scikit-learn

# Optional: Install visualization dependencies
uv pip install matplotlib seaborn

# Commonly used with
uv pip install pandas numpy

When to Use This Skill

Use the scikit-learn skill when:

  • Building classification or regression models
  • Performing clustering or dimensionality reduction
  • Preprocessing and transforming data for machine learning
  • Evaluating model performance with cross-validation
  • Tuning hyperparameters with grid or random search
  • Creating ML pipelines for production workflows
  • Comparing different algorithms for a task
  • Working with both structured (tabular) and text data
  • Need interpretable, classical machine learning approaches

Does NOT Trigger

Scenario Use Instead
Bayesian models with posteriors, credible intervals, or MCMC diagnostics alterlab-pymc
Censored time-to-event outcomes (Cox models, survival forests, C-index) alterlab-scikit-survival
UMAP embeddings with n_neighbors / min_dist tuning alterlab-umap
Explaining a fitted model's predictions with SHAP values and plots alterlab-shap
Coefficient tables, p-values, and residual diagnostics for inference alterlab-statsmodels

Quick Start

Minimal classification flow: stratified train_test_splitStandardScaler (fit on train only) → fit estimator → classification_report. For mixed numeric/categorical data, wrap preprocessing in a ColumnTransformer inside a Pipeline so it cross-validates without leakage.

See references/worked_examples.md for full copy-paste classification and mixed-data pipeline examples.

Core Capabilities

1. Supervised Learning

Comprehensive algorithms for classification and regression tasks.

Key algorithms:

  • Linear models: Logistic Regression, Linear Regression, Ridge, Lasso, ElasticNet
  • Tree-based: Decision Trees, Random Forest, Gradient Boosting
  • Support Vector Machines: SVC, SVR with various kernels
  • Ensemble methods: AdaBoost, Voting, Stacking
  • Neural Networks: MLPClassifier, MLPRegressor
  • Others: Naive Bayes, K-Nearest Neighbors

When to use:

  • Classification: Predicting discrete categories (spam detection, image classification, fraud detection)
  • Regression: Predicting continuous values (price prediction, demand forecasting)

See: references/supervised_learning.md for detailed algorithm documentation, parameters, and usage examples.

2. Unsupervised Learning

Discover patterns in unlabeled data through clustering and dimensionality reduction.

Clustering algorithms:

  • Partition-based: K-Means, MiniBatchKMeans
  • Density-based: DBSCAN, HDBSCAN, OPTICS
  • Hierarchical: AgglomerativeClustering
  • Probabilistic: Gaussian Mixture Models
  • Others: MeanShift, SpectralClustering, BIRCH

Dimensionality reduction:

  • Linear: PCA, TruncatedSVD, NMF
  • Manifold learning: t-SNE, UMAP, Isomap, LLE
  • Feature extraction: FastICA, LatentDirichletAllocation

When to use:

  • Customer segmentation, anomaly detection, data visualization
  • Reducing feature dimensions, exploratory data analysis
  • Topic modeling, image compression

See: references/unsupervised_learning.md for detailed documentation.

3. Model Evaluation and Selection

Tools for robust model evaluation, cross-validation, and hyperparameter tuning.

Cross-validation strategies:

  • KFold, StratifiedKFold (classification)
  • TimeSeriesSplit (temporal data)
  • GroupKFold (grouped samples)

Hyperparameter tuning:

  • GridSearchCV (exhaustive search)
  • RandomizedSearchCV (random sampling)
  • HalvingGridSearchCV (successive halving)

Metrics:

  • Classification: accuracy, precision, recall, F1-score, ROC AUC, confusion matrix
  • Regression: MSE, RMSE, MAE, R², MAPE
  • Clustering: silhouette score, Calinski-Harabasz, Davies-Bouldin

When to use:

  • Comparing model performance objectively
  • Finding optimal hyperparameters
  • Preventing overfitting through cross-validation
  • Understanding model behavior with learning curves

See: references/model_evaluation.md for comprehensive metrics and tuning strategies.

4. Data Preprocessing

Transform raw data into formats suitable for machine learning.

Scaling and normalization:

  • StandardScaler (zero mean, unit variance)
  • MinMaxScaler (bounded range)
  • RobustScaler (robust to outliers)
  • Normalizer (sample-wise normalization)

Encoding categorical variables:

  • OneHotEncoder (nominal categories)
  • OrdinalEncoder (ordered categories)
  • LabelEncoder (encodes the target labels y, not features)
  • TargetEncoder (encodes high-cardinality categorical features with cross-fitted target means)

Handling missing values:

  • SimpleImputer (mean, median, most frequent)
  • KNNImputer (k-nearest neighbors)
  • IterativeImputer (multivariate imputation)

Feature engineering:

  • PolynomialFeatures (interaction terms)
  • KBinsDiscretizer (binning)
  • Feature selection (RFE, SelectKBest, SelectFromModel)

When to use:

  • Before training any algorithm that requires scaled features (SVM, KNN, Neural Networks)
  • Converting categorical variables to numeric format
  • Handling missing data systematically
  • Creating non-linear features for linear models

See: references/preprocessing.md for detailed preprocessing techniques.

5. Pipelines and Composition

Build reproducible, production-ready ML workflows.

Key components:

  • Pipeline: Chain transformers and estimators sequentially
  • ColumnTransformer: Apply different preprocessing to different columns
  • FeatureUnion: Combine multiple transformers in parallel
  • TransformedTargetRegressor: Transform target variable

Benefits:

  • Prevents data leakage in cross-validation
  • Simplifies code and improves maintainability
  • Enables joint hyperparameter tuning
  • Ensures consistency between training and prediction

When to use:

  • Always use Pipelines for production workflows
  • When mixing numerical and categorical features (use ColumnTransformer)
  • When performing cross-validation with preprocessing steps
  • When hyperparameter tuning includes preprocessing parameters

See: references/pipelines_and_composition.md for comprehensive pipeline patterns.

Example Scripts

Two runnable end-to-end scripts ship with this skill:

python scripts/classification_pipeline.py   # mixed-data preprocessing, model comparison, GridSearchCV, evaluation, feature importance
python scripts/clustering_analysis.py        # optimal-k search, K-Means/DBSCAN/Agglomerative/GMM comparison, PCA visualization

See references/worked_examples.md for what each script demonstrates and standalone copy-paste versions.

Reference Documentation

This skill includes comprehensive reference files for deep dives into specific topics:

Quick Reference

File: references/quick_reference.md

  • Common import patterns and installation instructions
  • Quick workflow templates for common tasks
  • Algorithm selection cheat sheets
  • Common patterns and gotchas
  • Performance optimization tips

Supervised Learning

File: references/supervised_learning.md

  • Linear models (regression and classification)
  • Support Vector Machines
  • Decision Trees and ensemble methods
  • K-Nearest Neighbors, Naive Bayes, Neural Networks
  • Algorithm selection guide

Unsupervised Learning

File: references/unsupervised_learning.md

  • All clustering algorithms with parameters and use cases
  • Dimensionality reduction techniques
  • Outlier and novelty detection
  • Gaussian Mixture Models
  • Method selection guide

Model Evaluation

File: references/model_evaluation.md

  • Cross-validation strategies
  • Hyperparameter tuning methods
  • Classification, regression, and clustering metrics
  • Learning and validation curves
  • Best practices for model selection

Preprocessing

File: references/preprocessing.md

  • Feature scaling and normalization
  • Encoding categorical variables
  • Missing value imputation
  • Feature engineering techniques
  • Custom transformers

Pipelines and Composition

File: references/pipelines_and_composition.md

  • Pipeline construction and usage
  • ColumnTransformer for mixed data types
  • FeatureUnion for parallel transformations
  • Complete end-to-end examples
  • Best practices

Worked Examples

File: references/worked_examples.md

  • Quick-start classification and mixed-data pipeline snippets
  • Step-by-step classification model workflow
  • Step-by-step clustering analysis workflow
  • What each bundled example script demonstrates

Best Practices & Troubleshooting

File: references/best_practices_and_troubleshooting.md

  • Pipeline / leakage discipline, fit-on-train-only, stratified splitting
  • Random-state reproducibility, metric selection, when to scale features
  • Fixes for ConvergenceWarning, overfitting, and large-dataset memory errors

Common Workflows

  • Classification model: load data → stratified train_test_splitColumnTransformer preprocessing inside a PipelineGridSearchCV tuning → classification_report on the held-out test set.
  • Clustering analysis: StandardScaler → silhouette sweep over k to pick optimal_k → fit KMeansPCA(n_components=2) projection for visualization.

See references/worked_examples.md for the numbered, copy-paste version of each workflow.

Version notes (scikit-learn 1.8–1.9)

  • LogisticRegression(penalty=...) is deprecated (removed in 1.10): use l1_ratio (0 = L2, 1 = L1, in between = elastic net) and C=np.inf for no penalty.
  • SVC(probability=True) is deprecated (removed in 1.11): wrap the model as CalibratedClassifierCV(SVC(), ensemble=False) when probabilities are needed.
  • MDS(metric=True/False) became metric_mds=; HDBSCAN warns unless copy is set explicitly.
  • mean_squared_error(..., squared=False) is gone; use root_mean_squared_error.

Best Practices (essentials)

  • Always preprocess inside a Pipeline (prevents leakage); fit on train only, transform test.
  • Use stratify=y for classification splits; set random_state everywhere for reproducibility.
  • Scale features for SVM/KNN/NN/PCA/regularized-linear/K-Means; tree models and Naive Bayes do not need it.
  • Pick metrics for the problem: F1/accuracy on balanced data; precision/recall/ROC AUC/balanced accuracy on imbalanced data.

See references/best_practices_and_troubleshooting.md for code examples and fixes for ConvergenceWarning, overfitting, and large-dataset memory errors.

Additional Resources

Files (alterlab-academic-skills)
  • evals
    • evals.json 6.1 KB
      {
        "skill": "alterlab-scikit-learn",
        "evals": [
          {
            "id": "classification-pipeline-mixed-data",
            "prompt": "I have a tabular dataset with both numeric columns (age, income) and categorical columns (gender, occupation) plus some missing values, and a binary target. Build me a leakage-free classification workflow with proper preprocessing and evaluation.",
            "expected_output": "Invokes alterlab-scikit-learn to build a Pipeline with a ColumnTransformer: numeric branch (SimpleImputer median + StandardScaler), categorical branch (SimpleImputer most_frequent + OneHotEncoder handle_unknown='ignore'), then a classifier (e.g. RandomForest/GradientBoosting). Uses train_test_split with stratify=y and random_state, fits only on train, and reports classification_report. Emphasizes that preprocessing inside the Pipeline prevents data leakage.",
            "assertions": [
              { "type": "should_trigger", "value": true },
              { "type": "output_contains", "value": "ColumnTransformer" },
              { "type": "behavior", "value": "Wraps preprocessing and the estimator in a Pipeline (with ColumnTransformer for mixed types) to prevent leakage, and uses stratified splitting." }
            ]
          },
          {
            "id": "hyperparameter-tuning-cv",
            "prompt": "My RandomForest is overfitting and I want to find better settings for n_estimators and max_depth using cross-validation rather than eyeballing it. How do I tune this properly?",
            "expected_output": "Invokes alterlab-scikit-learn to tune hyperparameters with GridSearchCV (or RandomizedSearchCV / HalvingGridSearchCV) over a param_grid using the classifier__ prefix on a Pipeline, with cv folds (StratifiedKFold for classification), selects best_estimator_, and evaluates on the held-out test set. Mentions cross-validation and regularization/simpler models as overfitting remedies.",
            "assertions": [
              { "type": "should_trigger", "value": true },
              { "type": "output_contains", "value": "GridSearchCV" },
              { "type": "behavior", "value": "Recommends cross-validated hyperparameter search (GridSearchCV/RandomizedSearchCV) and evaluating the best model on a separate test set." }
            ]
          },
          {
            "id": "clustering-optimal-k",
            "prompt": "I have unlabeled customer data and want to segment it into clusters, but I don't know how many clusters to use. How do I pick the number and check the clustering is any good?",
            "expected_output": "Invokes alterlab-scikit-learn for unsupervised clustering: scales features with StandardScaler, sweeps k with KMeans evaluating silhouette_score (and/or elbow method, Calinski-Harabasz, Davies-Bouldin) to choose k, may compare DBSCAN/Agglomerative/GaussianMixture, and visualizes the result via a 2D PCA projection. Evaluates quality without ground-truth labels.",
            "assertions": [
              { "type": "should_trigger", "value": true },
              { "type": "output_contains", "value": "silhouette" },
              { "type": "behavior", "value": "Selects cluster count using silhouette/elbow analysis and evaluates clustering quality without labels." }
            ]
          },
          {
            "id": "regression-model-comparison",
            "prompt": "I'm predicting house prices and want to compare Ridge, Lasso, and Gradient Boosting regressors fairly, reporting RMSE and R-squared with cross-validation. Which preprocessing matters for the linear ones?",
            "expected_output": "Invokes alterlab-scikit-learn for supervised regression: compares Ridge, Lasso, and GradientBoostingRegressor via cross_val_score / cross-validation reporting RMSE, MAE, and R2, notes that the regularized linear models need StandardScaler (inside a Pipeline) while tree-based models do not, and sets random_state for reproducibility.",
            "assertions": [
              { "type": "should_trigger", "value": true },
              { "type": "behavior", "value": "Compares regressors with cross-validation on RMSE/R2 and notes feature scaling is required for the regularized linear models but not the tree-based one." }
            ]
          },
          {
            "id": "near-miss-pymc",
            "prompt": "Fit a Bayesian logistic regression and give me full posterior distributions and 94% credible intervals on the coefficients, with MCMC convergence diagnostics like R-hat and effective sample size.",
            "expected_output": "Does NOT invoke this skill; defers to alterlab-pymc. The user wants Bayesian inference with posterior distributions, credible intervals, and MCMC/NUTS diagnostics (R-hat, ESS), which is PyMC's territory, not scikit-learn's point-estimate classical ML.",
            "assertions": [
              { "type": "should_not_trigger", "value": true },
              { "type": "output_contains", "value": "alterlab-pymc" }
            ]
          },
          {
            "id": "near-miss-umap",
            "prompt": "I have high-dimensional single-cell embeddings and want a high-quality 2D UMAP projection for visualization, tuning n_neighbors and min_dist to preserve local and global structure.",
            "expected_output": "Does NOT invoke this skill; defers to alterlab-umap. While scikit-learn covers dimensionality reduction broadly, the user specifically wants UMAP with its dedicated n_neighbors/min_dist tuning and manifold structure preservation, which the alterlab-umap skill owns.",
            "assertions": [
              { "type": "should_not_trigger", "value": true },
              { "type": "output_contains", "value": "alterlab-umap" }
            ]
          },
          {
            "id": "near-miss-scikit-survival",
            "prompt": "I have patient follow-up data where many patients were still alive at the end of the study. I want to predict time to relapse, fit a random survival forest, and report the concordance index and integrated Brier score.",
            "expected_output": "Does NOT invoke this skill; defers to alterlab-scikit-survival. The outcome is a right-censored time-to-event variable that needs survival estimators (RandomSurvivalForest) and censoring-aware metrics (concordance index, integrated Brier score), not a standard scikit-learn regressor or classifier.",
            "assertions": [
              { "type": "should_not_trigger", "value": true },
              { "type": "output_contains", "value": "alterlab-scikit-survival" }
            ]
          }
        ]
      }
      
  • references
    • best_practices_and_troubleshooting.md 2.2 KB
      # Scikit-learn Best Practices & Troubleshooting
      
      ## Best Practices
      
      ### Always Use Pipelines
      Pipelines prevent data leakage and ensure consistency:
      ```python
      # Good: Preprocessing in pipeline
      pipeline = Pipeline([
          ('scaler', StandardScaler()),
          ('model', LogisticRegression())
      ])
      
      # Bad: Preprocessing outside (can leak information)
      X_scaled = StandardScaler().fit_transform(X)
      ```
      
      ### Fit on Training Data Only
      Never fit on test data:
      ```python
      # Good
      scaler = StandardScaler()
      X_train_scaled = scaler.fit_transform(X_train)
      X_test_scaled = scaler.transform(X_test)  # Only transform
      
      # Bad
      scaler = StandardScaler()
      X_all_scaled = scaler.fit_transform(np.vstack([X_train, X_test]))
      ```
      
      ### Use Stratified Splitting for Classification
      Preserve class distribution:
      ```python
      X_train, X_test, y_train, y_test = train_test_split(
          X, y, test_size=0.2, stratify=y, random_state=42
      )
      ```
      
      ### Set Random State for Reproducibility
      ```python
      model = RandomForestClassifier(n_estimators=100, random_state=42)
      ```
      
      ### Choose Appropriate Metrics
      - Balanced data: Accuracy, F1-score
      - Imbalanced data: Precision, Recall, ROC AUC, Balanced Accuracy
      - Cost-sensitive: Define custom scorer
      
      ### Scale Features When Required
      Algorithms requiring feature scaling:
      - SVM, KNN, Neural Networks
      - PCA, Linear/Logistic Regression with regularization
      - K-Means clustering
      
      Algorithms not requiring scaling:
      - Tree-based models (Decision Trees, Random Forest, Gradient Boosting)
      - Naive Bayes
      
      ## Troubleshooting Common Issues
      
      ### ConvergenceWarning
      **Issue:** Model didn't converge.
      **Solution:** Increase `max_iter` or scale features.
      ```python
      model = LogisticRegression(max_iter=1000)
      ```
      
      ### Poor Performance on Test Set
      **Issue:** Overfitting.
      **Solution:** Use regularization, cross-validation, or a simpler model.
      ```python
      # Add regularization
      model = Ridge(alpha=1.0)
      
      # Use cross-validation
      scores = cross_val_score(model, X, y, cv=5)
      ```
      
      ### Memory Error with Large Datasets
      **Solution:** Use algorithms designed for large data.
      ```python
      # Use SGD for large datasets
      from sklearn.linear_model import SGDClassifier
      model = SGDClassifier()
      
      # Or MiniBatchKMeans for clustering
      from sklearn.cluster import MiniBatchKMeans
      model = MiniBatchKMeans(n_clusters=8, batch_size=100)
      ```
      
    • model_evaluation.md 15.2 KB
      # Model Selection and Evaluation Reference
      
      ## Overview
      
      Comprehensive guide for evaluating models, tuning hyperparameters, and selecting the best model using scikit-learn's model selection tools.
      
      ## Train-Test Split
      
      ### Basic Splitting
      
      ```python
      from sklearn.model_selection import train_test_split
      
      # Basic split (default 75/25)
      X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25, random_state=42)
      
      # With stratification (preserves class distribution)
      X_train, X_test, y_train, y_test = train_test_split(
          X, y, test_size=0.25, stratify=y, random_state=42
      )
      
      # Three-way split (train/val/test)
      X_train, X_temp, y_train, y_temp = train_test_split(X, y, test_size=0.3, random_state=42)
      X_val, X_test, y_val, y_test = train_test_split(X_temp, y_temp, test_size=0.5, random_state=42)
      ```
      
      ## Cross-Validation
      
      ### Cross-Validation Strategies
      
      **KFold**
      - Standard k-fold cross-validation
      - Splits data into k consecutive folds
      ```python
      from sklearn.model_selection import KFold
      
      kf = KFold(n_splits=5, shuffle=True, random_state=42)
      for train_idx, val_idx in kf.split(X):
          X_train, X_val = X[train_idx], X[val_idx]
          y_train, y_val = y[train_idx], y[val_idx]
      ```
      
      **StratifiedKFold**
      - Preserves class distribution in each fold
      - Use for imbalanced classification
      ```python
      from sklearn.model_selection import StratifiedKFold
      
      skf = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)
      for train_idx, val_idx in skf.split(X, y):
          X_train, X_val = X[train_idx], X[val_idx]
          y_train, y_val = y[train_idx], y[val_idx]
      ```
      
      **TimeSeriesSplit**
      - For time series data
      - Respects temporal order
      ```python
      from sklearn.model_selection import TimeSeriesSplit
      
      tscv = TimeSeriesSplit(n_splits=5)
      for train_idx, val_idx in tscv.split(X):
          X_train, X_val = X[train_idx], X[val_idx]
          y_train, y_val = y[train_idx], y[val_idx]
      ```
      
      **GroupKFold**
      - Ensures samples from same group don't appear in both train and validation
      - Use when samples are not independent
      ```python
      from sklearn.model_selection import GroupKFold
      
      gkf = GroupKFold(n_splits=5)
      for train_idx, val_idx in gkf.split(X, y, groups=group_ids):
          X_train, X_val = X[train_idx], X[val_idx]
          y_train, y_val = y[train_idx], y[val_idx]
      ```
      
      **LeaveOneOut (LOO)**
      - Each sample used as validation set once
      - Use for very small datasets
      - Computationally expensive
      ```python
      from sklearn.model_selection import LeaveOneOut
      
      loo = LeaveOneOut()
      for train_idx, val_idx in loo.split(X):
          X_train, X_val = X[train_idx], X[val_idx]
          y_train, y_val = y[train_idx], y[val_idx]
      ```
      
      ### Cross-Validation Functions
      
      **cross_val_score**
      - Evaluate model using cross-validation
      - Returns array of scores
      ```python
      from sklearn.model_selection import cross_val_score
      from sklearn.ensemble import RandomForestClassifier
      
      model = RandomForestClassifier(n_estimators=100, random_state=42)
      scores = cross_val_score(model, X, y, cv=5, scoring='accuracy')
      
      print(f"Scores: {scores}")
      print(f"Mean: {scores.mean():.3f} (+/- {scores.std() * 2:.3f})")
      ```
      
      **cross_validate**
      - More comprehensive than cross_val_score
      - Can return multiple metrics and fit times
      ```python
      from sklearn.model_selection import cross_validate
      
      model = RandomForestClassifier(n_estimators=100, random_state=42)
      cv_results = cross_validate(
          model, X, y, cv=5,
          scoring=['accuracy', 'precision', 'recall', 'f1'],
          return_train_score=True,
          return_estimator=True  # Returns fitted estimators
      )
      
      print(f"Test accuracy: {cv_results['test_accuracy'].mean():.3f}")
      print(f"Test precision: {cv_results['test_precision'].mean():.3f}")
      print(f"Fit time: {cv_results['fit_time'].mean():.3f}s")
      ```
      
      **cross_val_predict**
      - Get predictions for each sample when it was in validation set
      - Useful for analyzing errors
      ```python
      from sklearn.model_selection import cross_val_predict
      
      model = RandomForestClassifier(n_estimators=100, random_state=42)
      y_pred = cross_val_predict(model, X, y, cv=5)
      
      # Now can analyze predictions vs actual
      from sklearn.metrics import confusion_matrix
      cm = confusion_matrix(y, y_pred)
      ```
      
      ## Hyperparameter Tuning
      
      ### Grid Search
      
      **GridSearchCV**
      - Exhaustive search over parameter grid
      - Tests all combinations
      ```python
      from sklearn.model_selection import GridSearchCV
      from sklearn.ensemble import RandomForestClassifier
      
      param_grid = {
          'n_estimators': [50, 100, 200],
          'max_depth': [5, 10, 15, None],
          'min_samples_split': [2, 5, 10],
          'min_samples_leaf': [1, 2, 4]
      }
      
      model = RandomForestClassifier(random_state=42)
      grid_search = GridSearchCV(
          model, param_grid,
          cv=5,
          scoring='accuracy',
          n_jobs=-1,  # Use all CPU cores
          verbose=1
      )
      
      grid_search.fit(X_train, y_train)
      
      print(f"Best parameters: {grid_search.best_params_}")
      print(f"Best cross-validation score: {grid_search.best_score_:.3f}")
      print(f"Test score: {grid_search.score(X_test, y_test):.3f}")
      
      # Access best model
      best_model = grid_search.best_estimator_
      
      # View all results
      import pandas as pd
      results_df = pd.DataFrame(grid_search.cv_results_)
      ```
      
      ### Randomized Search
      
      **RandomizedSearchCV**
      - Samples random combinations from parameter distributions
      - More efficient for large search spaces
      ```python
      from sklearn.model_selection import RandomizedSearchCV
      from scipy.stats import randint, uniform
      
      param_distributions = {
          'n_estimators': randint(50, 300),
          'max_depth': [5, 10, 15, 20, None],
          'min_samples_split': randint(2, 20),
          'min_samples_leaf': randint(1, 10),
          'max_features': uniform(0.1, 0.9)  # Continuous distribution
      }
      
      model = RandomForestClassifier(random_state=42)
      random_search = RandomizedSearchCV(
          model, param_distributions,
          n_iter=100,  # Number of parameter settings sampled
          cv=5,
          scoring='accuracy',
          n_jobs=-1,
          verbose=1,
          random_state=42
      )
      
      random_search.fit(X_train, y_train)
      
      print(f"Best parameters: {random_search.best_params_}")
      print(f"Best score: {random_search.best_score_:.3f}")
      ```
      
      ### Successive Halving
      
      **HalvingGridSearchCV / HalvingRandomSearchCV**
      - Iteratively selects best candidates using successive halving
      - More efficient than exhaustive search
      ```python
      from sklearn.experimental import enable_halving_search_cv
      from sklearn.model_selection import HalvingGridSearchCV
      
      param_grid = {
          'n_estimators': [50, 100, 200, 300],
          'max_depth': [5, 10, 15, 20, None],
          'min_samples_split': [2, 5, 10, 20]
      }
      
      model = RandomForestClassifier(random_state=42)
      halving_search = HalvingGridSearchCV(
          model, param_grid,
          cv=5,
          factor=3,  # Proportion of candidates eliminated in each iteration
          resource='n_samples',  # Can also use 'n_estimators' for ensembles
          max_resources='auto',
          random_state=42
      )
      
      halving_search.fit(X_train, y_train)
      print(f"Best parameters: {halving_search.best_params_}")
      ```
      
      ## Classification Metrics
      
      ### Basic Metrics
      
      ```python
      from sklearn.metrics import (
          accuracy_score, precision_score, recall_score, f1_score,
          balanced_accuracy_score, matthews_corrcoef
      )
      
      y_pred = model.predict(X_test)
      
      accuracy = accuracy_score(y_test, y_pred)
      precision = precision_score(y_test, y_pred, average='weighted')  # For multiclass
      recall = recall_score(y_test, y_pred, average='weighted')
      f1 = f1_score(y_test, y_pred, average='weighted')
      balanced_acc = balanced_accuracy_score(y_test, y_pred)  # Good for imbalanced data
      mcc = matthews_corrcoef(y_test, y_pred)  # Matthews correlation coefficient
      
      print(f"Accuracy: {accuracy:.3f}")
      print(f"Precision: {precision:.3f}")
      print(f"Recall: {recall:.3f}")
      print(f"F1-score: {f1:.3f}")
      print(f"Balanced Accuracy: {balanced_acc:.3f}")
      print(f"MCC: {mcc:.3f}")
      ```
      
      ### Classification Report
      
      ```python
      from sklearn.metrics import classification_report
      
      print(classification_report(y_test, y_pred, target_names=class_names))
      ```
      
      ### Confusion Matrix
      
      ```python
      from sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay
      import matplotlib.pyplot as plt
      
      cm = confusion_matrix(y_test, y_pred)
      disp = ConfusionMatrixDisplay(confusion_matrix=cm, display_labels=class_names)
      disp.plot(cmap='Blues')
      plt.show()
      ```
      
      ### ROC and AUC
      
      ```python
      from sklearn.metrics import roc_auc_score, roc_curve, RocCurveDisplay
      
      # Binary classification
      y_proba = model.predict_proba(X_test)[:, 1]
      auc = roc_auc_score(y_test, y_proba)
      print(f"ROC AUC: {auc:.3f}")
      
      # Plot ROC curve
      fpr, tpr, thresholds = roc_curve(y_test, y_proba)
      RocCurveDisplay(fpr=fpr, tpr=tpr, roc_auc=auc).plot()
      
      # Multiclass (one-vs-rest)
      auc_ovr = roc_auc_score(y_test, y_proba_multi, multi_class='ovr')
      ```
      
      ### Precision-Recall Curve
      
      ```python
      from sklearn.metrics import precision_recall_curve, PrecisionRecallDisplay
      from sklearn.metrics import average_precision_score
      
      precision, recall, thresholds = precision_recall_curve(y_test, y_proba)
      ap = average_precision_score(y_test, y_proba)
      
      disp = PrecisionRecallDisplay(precision=precision, recall=recall, average_precision=ap)
      disp.plot()
      ```
      
      ### Log Loss
      
      ```python
      from sklearn.metrics import log_loss
      
      y_proba = model.predict_proba(X_test)
      logloss = log_loss(y_test, y_proba)
      print(f"Log Loss: {logloss:.3f}")
      ```
      
      ## Regression Metrics
      
      ```python
      from sklearn.metrics import (
          mean_squared_error, root_mean_squared_error, mean_absolute_error, r2_score,
          mean_absolute_percentage_error, median_absolute_error
      )
      
      y_pred = model.predict(X_test)
      
      mse = mean_squared_error(y_test, y_pred)
      # Use root_mean_squared_error (sklearn >= 1.4); the squared=False arg was removed in 1.6
      rmse = root_mean_squared_error(y_test, y_pred)
      mae = mean_absolute_error(y_test, y_pred)
      r2 = r2_score(y_test, y_pred)
      mape = mean_absolute_percentage_error(y_test, y_pred)
      median_ae = median_absolute_error(y_test, y_pred)
      
      print(f"MSE: {mse:.3f}")
      print(f"RMSE: {rmse:.3f}")
      print(f"MAE: {mae:.3f}")
      print(f"R² Score: {r2:.3f}")
      print(f"MAPE: {mape:.3f}")
      print(f"Median AE: {median_ae:.3f}")
      ```
      
      ## Clustering Metrics
      
      ### With Ground Truth Labels
      
      ```python
      from sklearn.metrics import (
          adjusted_rand_score, normalized_mutual_info_score,
          adjusted_mutual_info_score, fowlkes_mallows_score,
          homogeneity_score, completeness_score, v_measure_score
      )
      
      ari = adjusted_rand_score(y_true, y_pred)
      nmi = normalized_mutual_info_score(y_true, y_pred)
      ami = adjusted_mutual_info_score(y_true, y_pred)
      fmi = fowlkes_mallows_score(y_true, y_pred)
      homogeneity = homogeneity_score(y_true, y_pred)
      completeness = completeness_score(y_true, y_pred)
      v_measure = v_measure_score(y_true, y_pred)
      ```
      
      ### Without Ground Truth
      
      ```python
      from sklearn.metrics import (
          silhouette_score, calinski_harabasz_score, davies_bouldin_score
      )
      
      silhouette = silhouette_score(X, labels)  # [-1, 1], higher better
      ch_score = calinski_harabasz_score(X, labels)  # Higher better
      db_score = davies_bouldin_score(X, labels)  # Lower better
      ```
      
      ## Custom Scoring
      
      ### Using make_scorer
      
      ```python
      from sklearn.metrics import make_scorer
      
      def custom_metric(y_true, y_pred):
          # Your custom logic
          return score
      
      custom_scorer = make_scorer(custom_metric, greater_is_better=True)
      
      # Use in cross-validation or grid search
      scores = cross_val_score(model, X, y, cv=5, scoring=custom_scorer)
      ```
      
      ### Multiple Metrics in Grid Search
      
      ```python
      from sklearn.model_selection import GridSearchCV
      
      scoring = {
          'accuracy': 'accuracy',
          'precision': 'precision_weighted',
          'recall': 'recall_weighted',
          'f1': 'f1_weighted'
      }
      
      grid_search = GridSearchCV(
          model, param_grid,
          cv=5,
          scoring=scoring,
          refit='f1',  # Refit on best f1 score
          return_train_score=True
      )
      
      grid_search.fit(X_train, y_train)
      ```
      
      ## Validation Curves
      
      ### Learning Curve
      
      ```python
      from sklearn.model_selection import learning_curve
      import matplotlib.pyplot as plt
      import numpy as np
      
      train_sizes, train_scores, val_scores = learning_curve(
          model, X, y,
          cv=5,
          train_sizes=np.linspace(0.1, 1.0, 10),
          scoring='accuracy',
          n_jobs=-1
      )
      
      train_mean = train_scores.mean(axis=1)
      train_std = train_scores.std(axis=1)
      val_mean = val_scores.mean(axis=1)
      val_std = val_scores.std(axis=1)
      
      plt.figure(figsize=(10, 6))
      plt.plot(train_sizes, train_mean, label='Training score')
      plt.plot(train_sizes, val_mean, label='Validation score')
      plt.fill_between(train_sizes, train_mean - train_std, train_mean + train_std, alpha=0.1)
      plt.fill_between(train_sizes, val_mean - val_std, val_mean + val_std, alpha=0.1)
      plt.xlabel('Training Set Size')
      plt.ylabel('Score')
      plt.title('Learning Curve')
      plt.legend()
      plt.grid(True)
      ```
      
      ### Validation Curve
      
      ```python
      from sklearn.model_selection import validation_curve
      
      param_range = [1, 10, 50, 100, 200, 500]
      train_scores, val_scores = validation_curve(
          model, X, y,
          param_name='n_estimators',
          param_range=param_range,
          cv=5,
          scoring='accuracy',
          n_jobs=-1
      )
      
      train_mean = train_scores.mean(axis=1)
      val_mean = val_scores.mean(axis=1)
      
      plt.figure(figsize=(10, 6))
      plt.plot(param_range, train_mean, label='Training score')
      plt.plot(param_range, val_mean, label='Validation score')
      plt.xlabel('n_estimators')
      plt.ylabel('Score')
      plt.title('Validation Curve')
      plt.legend()
      plt.grid(True)
      ```
      
      ## Model Persistence
      
      ### Save and Load Models
      
      ```python
      import joblib
      
      # Save model
      joblib.dump(model, 'model.pkl')
      
      # Load model
      loaded_model = joblib.load('model.pkl')
      
      # Also works with pipelines
      joblib.dump(pipeline, 'pipeline.pkl')
      ```
      
      ### Using pickle
      
      ```python
      import pickle
      
      # Save
      with open('model.pkl', 'wb') as f:
          pickle.dump(model, f)
      
      # Load
      with open('model.pkl', 'rb') as f:
          loaded_model = pickle.load(f)
      ```
      
      ## Imbalanced Data Strategies
      
      ### Class Weighting
      
      ```python
      from sklearn.ensemble import RandomForestClassifier
      
      # Automatically balance classes
      model = RandomForestClassifier(class_weight='balanced', random_state=42)
      model.fit(X_train, y_train)
      
      # Custom weights
      class_weights = {0: 1, 1: 10}  # Give class 1 more weight
      model = RandomForestClassifier(class_weight=class_weights, random_state=42)
      ```
      
      ### Resampling (using imbalanced-learn)
      
      ```python
      # Install: uv pip install imbalanced-learn
      from imblearn.over_sampling import SMOTE
      from imblearn.under_sampling import RandomUnderSampler
      from imblearn.pipeline import Pipeline as ImbPipeline
      
      # SMOTE oversampling
      smote = SMOTE(random_state=42)
      X_resampled, y_resampled = smote.fit_resample(X_train, y_train)
      
      # Combined approach
      pipeline = ImbPipeline([
          ('over', SMOTE(sampling_strategy=0.5)),
          ('under', RandomUnderSampler(sampling_strategy=0.8)),
          ('model', RandomForestClassifier())
      ])
      ```
      
      ## Best Practices
      
      ### Stratified Splitting
      Always use stratified splitting for classification:
      ```python
      X_train, X_test, y_train, y_test = train_test_split(
          X, y, test_size=0.2, stratify=y, random_state=42
      )
      ```
      
      ### Appropriate Metrics
      - **Balanced data**: Accuracy, F1-score
      - **Imbalanced data**: Precision, Recall, F1-score, ROC AUC, Balanced Accuracy
      - **Cost-sensitive**: Define custom scorer with costs
      - **Ranking**: ROC AUC, Average Precision
      
      ### Cross-Validation
      - Use 5 or 10-fold CV for most cases
      - Use StratifiedKFold for classification
      - Use TimeSeriesSplit for time series
      - Use GroupKFold when samples are grouped
      
      ### Nested Cross-Validation
      For unbiased performance estimates when tuning:
      ```python
      from sklearn.model_selection import cross_val_score, GridSearchCV
      
      # Inner loop: hyperparameter tuning
      grid_search = GridSearchCV(model, param_grid, cv=5)
      
      # Outer loop: performance estimation
      scores = cross_val_score(grid_search, X, y, cv=5)
      print(f"Nested CV score: {scores.mean():.3f} (+/- {scores.std() * 2:.3f})")
      ```
      
    • pipelines_and_composition.md 14.4 KB
      # Pipelines and Composite Estimators Reference
      
      ## Overview
      
      Pipelines chain multiple processing steps into a single estimator, preventing data leakage and simplifying code. They enable reproducible workflows and seamless integration with cross-validation and hyperparameter tuning.
      
      ## Pipeline Basics
      
      ### Creating a Pipeline
      
      **Pipeline (`sklearn.pipeline.Pipeline`)**
      - Chains transformers with a final estimator
      - All intermediate steps must have fit_transform()
      - Final step can be any estimator (transformer, classifier, regressor, clusterer)
      - Example:
      ```python
      from sklearn.pipeline import Pipeline
      from sklearn.preprocessing import StandardScaler
      from sklearn.decomposition import PCA
      from sklearn.linear_model import LogisticRegression
      
      pipeline = Pipeline([
          ('scaler', StandardScaler()),
          ('pca', PCA(n_components=10)),
          ('classifier', LogisticRegression())
      ])
      
      # Fit the entire pipeline
      pipeline.fit(X_train, y_train)
      
      # Predict using the pipeline
      y_pred = pipeline.predict(X_test)
      y_proba = pipeline.predict_proba(X_test)
      ```
      
      ### Using make_pipeline
      
      **make_pipeline**
      - Convenient constructor that auto-generates step names
      - Example:
      ```python
      from sklearn.pipeline import make_pipeline
      from sklearn.preprocessing import StandardScaler
      from sklearn.svm import SVC
      
      pipeline = make_pipeline(
          StandardScaler(),
          PCA(n_components=10),
          SVC(kernel='rbf')
      )
      
      pipeline.fit(X_train, y_train)
      ```
      
      ## Accessing Pipeline Components
      
      ### Accessing Steps
      
      ```python
      # By index
      scaler = pipeline.steps[0][1]
      
      # By name
      scaler = pipeline.named_steps['scaler']
      pca = pipeline.named_steps['pca']
      
      # Using indexing syntax
      scaler = pipeline['scaler']
      pca = pipeline['pca']
      
      # Get all step names
      print(pipeline.named_steps.keys())
      ```
      
      ### Setting Parameters
      
      ```python
      # Set parameters using double underscore notation
      pipeline.set_params(
          pca__n_components=15,
          classifier__C=0.1
      )
      
      # Or during creation
      pipeline = Pipeline([
          ('scaler', StandardScaler()),
          ('pca', PCA(n_components=10)),
          ('classifier', LogisticRegression(C=1.0))
      ])
      ```
      
      ### Accessing Attributes
      
      ```python
      # Access fitted attributes
      pca_components = pipeline.named_steps['pca'].components_
      explained_variance = pipeline.named_steps['pca'].explained_variance_ratio_
      
      # Access intermediate transformations
      X_scaled = pipeline.named_steps['scaler'].transform(X_test)
      X_pca = pipeline.named_steps['pca'].transform(X_scaled)
      ```
      
      ## Hyperparameter Tuning with Pipelines
      
      ### Grid Search with Pipeline
      
      ```python
      from sklearn.model_selection import GridSearchCV
      from sklearn.pipeline import Pipeline
      from sklearn.preprocessing import StandardScaler
      from sklearn.svm import SVC
      
      pipeline = Pipeline([
          ('scaler', StandardScaler()),
          ('classifier', SVC())
      ])
      
      param_grid = {
          'classifier__C': [0.1, 1, 10, 100],
          'classifier__gamma': ['scale', 'auto', 0.001, 0.01],
          'classifier__kernel': ['rbf', 'linear']
      }
      
      grid_search = GridSearchCV(pipeline, param_grid, cv=5, n_jobs=-1)
      grid_search.fit(X_train, y_train)
      
      print(f"Best parameters: {grid_search.best_params_}")
      print(f"Best score: {grid_search.best_score_:.3f}")
      ```
      
      ### Tuning Multiple Pipeline Steps
      
      ```python
      param_grid = {
          # PCA parameters
          'pca__n_components': [5, 10, 20, 50],
      
          # Classifier parameters
          'classifier__C': [0.1, 1, 10],
          'classifier__kernel': ['rbf', 'linear']
      }
      
      grid_search = GridSearchCV(pipeline, param_grid, cv=5)
      grid_search.fit(X_train, y_train)
      ```
      
      ## ColumnTransformer
      
      ### Basic Usage
      
      **ColumnTransformer (`sklearn.compose.ColumnTransformer`)**
      - Apply different preprocessing to different columns
      - Prevents data leakage in cross-validation
      - Example:
      ```python
      from sklearn.compose import ColumnTransformer
      from sklearn.preprocessing import StandardScaler, OneHotEncoder
      from sklearn.impute import SimpleImputer
      
      # Define column groups
      numeric_features = ['age', 'income', 'hours_per_week']
      categorical_features = ['gender', 'occupation', 'native_country']
      
      # Create preprocessor
      preprocessor = ColumnTransformer(
          transformers=[
              ('num', StandardScaler(), numeric_features),
              ('cat', OneHotEncoder(handle_unknown='ignore'), categorical_features)
          ],
          remainder='passthrough'  # Keep other columns unchanged
      )
      
      X_transformed = preprocessor.fit_transform(X)
      ```
      
      ### With Pipeline Steps
      
      ```python
      from sklearn.pipeline import Pipeline
      
      numeric_transformer = Pipeline(steps=[
          ('imputer', SimpleImputer(strategy='median')),
          ('scaler', StandardScaler())
      ])
      
      categorical_transformer = Pipeline(steps=[
          ('imputer', SimpleImputer(strategy='constant', fill_value='missing')),
          ('onehot', OneHotEncoder(handle_unknown='ignore'))
      ])
      
      preprocessor = ColumnTransformer(
          transformers=[
              ('num', numeric_transformer, numeric_features),
              ('cat', categorical_transformer, categorical_features)
          ]
      )
      
      # Full pipeline with model
      full_pipeline = Pipeline([
          ('preprocessor', preprocessor),
          ('classifier', LogisticRegression())
      ])
      
      full_pipeline.fit(X_train, y_train)
      ```
      
      ### Using make_column_transformer
      
      ```python
      from sklearn.compose import make_column_transformer
      
      preprocessor = make_column_transformer(
          (StandardScaler(), numeric_features),
          (OneHotEncoder(), categorical_features),
          remainder='passthrough'
      )
      ```
      
      ### Column Selection
      
      ```python
      # By column names (if X is DataFrame)
      preprocessor = ColumnTransformer([
          ('num', StandardScaler(), ['age', 'income']),
          ('cat', OneHotEncoder(), ['gender', 'occupation'])
      ])
      
      # By column indices
      preprocessor = ColumnTransformer([
          ('num', StandardScaler(), [0, 1, 2]),
          ('cat', OneHotEncoder(), [3, 4])
      ])
      
      # By boolean mask
      numeric_mask = [True, True, True, False, False]
      categorical_mask = [False, False, False, True, True]
      
      preprocessor = ColumnTransformer([
          ('num', StandardScaler(), numeric_mask),
          ('cat', OneHotEncoder(), categorical_mask)
      ])
      
      # By callable
      def is_numeric(X):
          return X.select_dtypes(include=['number']).columns.tolist()
      
      preprocessor = ColumnTransformer([
          ('num', StandardScaler(), is_numeric)
      ])
      ```
      
      ### Getting Feature Names
      
      ```python
      # Get output feature names
      feature_names = preprocessor.get_feature_names_out()
      
      # After fitting
      preprocessor.fit(X_train)
      output_features = preprocessor.get_feature_names_out()
      print(f"Input features: {X_train.columns.tolist()}")
      print(f"Output features: {output_features}")
      ```
      
      ### Remainder Handling
      
      ```python
      # Drop unspecified columns (default)
      preprocessor = ColumnTransformer([...], remainder='drop')
      
      # Pass through unchanged
      preprocessor = ColumnTransformer([...], remainder='passthrough')
      
      # Apply transformer to remaining columns
      preprocessor = ColumnTransformer([...], remainder=StandardScaler())
      ```
      
      ## FeatureUnion
      
      ### Basic Usage
      
      **FeatureUnion (`sklearn.pipeline.FeatureUnion`)**
      - Concatenates results of multiple transformers
      - Transformers are applied in parallel
      - Example:
      ```python
      from sklearn.pipeline import FeatureUnion
      from sklearn.decomposition import PCA
      from sklearn.feature_selection import SelectKBest
      
      # Combine PCA and feature selection
      feature_union = FeatureUnion([
          ('pca', PCA(n_components=10)),
          ('select_best', SelectKBest(k=20))
      ])
      
      X_combined = feature_union.fit_transform(X_train, y_train)
      print(f"Combined features: {X_combined.shape[1]}")  # 10 + 20 = 30
      ```
      
      ### With Pipeline
      
      ```python
      from sklearn.pipeline import Pipeline, FeatureUnion
      from sklearn.preprocessing import StandardScaler
      from sklearn.decomposition import PCA, TruncatedSVD
      
      # Create feature union
      feature_union = FeatureUnion([
          ('pca', PCA(n_components=10)),
          ('svd', TruncatedSVD(n_components=10))
      ])
      
      # Full pipeline
      pipeline = Pipeline([
          ('scaler', StandardScaler()),
          ('features', feature_union),
          ('classifier', LogisticRegression())
      ])
      
      pipeline.fit(X_train, y_train)
      ```
      
      ### Weighted Feature Union
      
      ```python
      # Apply weights to transformers
      feature_union = FeatureUnion(
          transformer_list=[
              ('pca', PCA(n_components=10)),
              ('select_best', SelectKBest(k=20))
          ],
          transformer_weights={
              'pca': 2.0,  # Give PCA features double weight
              'select_best': 1.0
          }
      )
      ```
      
      ## Advanced Pipeline Patterns
      
      ### Caching Pipeline Steps
      
      ```python
      from sklearn.pipeline import Pipeline
      from tempfile import mkdtemp
      from shutil import rmtree
      
      # Cache intermediate results
      cachedir = mkdtemp()
      pipeline = Pipeline([
          ('scaler', StandardScaler()),
          ('pca', PCA(n_components=50)),
          ('classifier', LogisticRegression())
      ], memory=cachedir)
      
      pipeline.fit(X_train, y_train)
      
      # Clean up cache
      rmtree(cachedir)
      ```
      
      ### Nested Pipelines
      
      ```python
      from sklearn.pipeline import Pipeline
      
      # Inner pipeline for text processing
      text_pipeline = Pipeline([
          ('vect', CountVectorizer()),
          ('tfidf', TfidfTransformer())
      ])
      
      # Outer pipeline combining text and numeric features
      full_pipeline = Pipeline([
          ('features', FeatureUnion([
              ('text', text_pipeline),
              ('numeric', StandardScaler())
          ])),
          ('classifier', LogisticRegression())
      ])
      ```
      
      ### Custom Transformers in Pipelines
      
      ```python
      from sklearn.base import BaseEstimator, TransformerMixin
      
      class TextLengthExtractor(BaseEstimator, TransformerMixin):
          def fit(self, X, y=None):
              return self
      
          def transform(self, X):
              return [[len(text)] for text in X]
      
      pipeline = Pipeline([
          ('length', TextLengthExtractor()),
          ('scaler', StandardScaler()),
          ('classifier', LogisticRegression())
      ])
      ```
      
      ### Slicing Pipelines
      
      ```python
      # Get sub-pipeline
      sub_pipeline = pipeline[:2]  # First two steps
      
      # Get specific range
      middle_steps = pipeline[1:3]
      ```
      
      ## TransformedTargetRegressor
      
      ### Basic Usage
      
      **TransformedTargetRegressor**
      - Transforms target variable before fitting
      - Automatically inverse-transforms predictions
      - Example:
      ```python
      from sklearn.compose import TransformedTargetRegressor
      from sklearn.preprocessing import QuantileTransformer
      from sklearn.linear_model import LinearRegression
      
      model = TransformedTargetRegressor(
          regressor=LinearRegression(),
          transformer=QuantileTransformer(output_distribution='normal')
      )
      
      model.fit(X_train, y_train)
      y_pred = model.predict(X_test)  # Automatically inverse-transformed
      ```
      
      ### With Functions
      
      ```python
      import numpy as np
      
      model = TransformedTargetRegressor(
          regressor=LinearRegression(),
          func=np.log1p,
          inverse_func=np.expm1
      )
      
      model.fit(X_train, y_train)
      ```
      
      ## Complete Example: End-to-End Pipeline
      
      ```python
      import pandas as pd
      from sklearn.compose import ColumnTransformer
      from sklearn.pipeline import Pipeline
      from sklearn.preprocessing import StandardScaler, OneHotEncoder
      from sklearn.impute import SimpleImputer
      from sklearn.decomposition import PCA
      from sklearn.ensemble import RandomForestClassifier
      from sklearn.model_selection import GridSearchCV
      
      # Define feature types
      numeric_features = ['age', 'income', 'hours_per_week']
      categorical_features = ['gender', 'occupation', 'education']
      
      # Numeric preprocessing pipeline
      numeric_transformer = Pipeline(steps=[
          ('imputer', SimpleImputer(strategy='median')),
          ('scaler', StandardScaler())
      ])
      
      # Categorical preprocessing pipeline
      categorical_transformer = Pipeline(steps=[
          ('imputer', SimpleImputer(strategy='constant', fill_value='missing')),
          ('onehot', OneHotEncoder(handle_unknown='ignore', sparse_output=False))
      ])
      
      # Combine preprocessing
      preprocessor = ColumnTransformer(
          transformers=[
              ('num', numeric_transformer, numeric_features),
              ('cat', categorical_transformer, categorical_features)
          ]
      )
      
      # Full pipeline
      pipeline = Pipeline([
          ('preprocessor', preprocessor),
          ('pca', PCA(n_components=0.95)),  # Keep 95% variance
          ('classifier', RandomForestClassifier(random_state=42))
      ])
      
      # Hyperparameter tuning
      param_grid = {
          'preprocessor__num__imputer__strategy': ['mean', 'median'],
          'pca__n_components': [0.90, 0.95, 0.99],
          'classifier__n_estimators': [100, 200],
          'classifier__max_depth': [10, 20, None]
      }
      
      grid_search = GridSearchCV(
          pipeline, param_grid,
          cv=5, scoring='accuracy',
          n_jobs=-1, verbose=1
      )
      
      grid_search.fit(X_train, y_train)
      
      print(f"Best parameters: {grid_search.best_params_}")
      print(f"Best CV score: {grid_search.best_score_:.3f}")
      print(f"Test score: {grid_search.score(X_test, y_test):.3f}")
      
      # Make predictions
      best_pipeline = grid_search.best_estimator_
      y_pred = best_pipeline.predict(X_test)
      y_proba = best_pipeline.predict_proba(X_test)
      ```
      
      ## Visualization
      
      ### Displaying Pipelines
      
      ```python
      # In Jupyter notebooks, pipelines display as diagrams
      from sklearn import set_config
      set_config(display='diagram')
      
      pipeline  # Displays visual diagram
      ```
      
      ### Text Representation
      
      ```python
      # Print pipeline structure
      print(pipeline)
      
      # Get detailed parameters
      print(pipeline.get_params())
      ```
      
      ## Best Practices
      
      ### Always Use Pipelines
      - Prevents data leakage
      - Ensures consistency between training and prediction
      - Makes code more maintainable
      - Enables easy hyperparameter tuning
      
      ### Proper Pipeline Construction
      ```python
      # Good: Preprocessing inside pipeline
      pipeline = Pipeline([
          ('scaler', StandardScaler()),
          ('model', LogisticRegression())
      ])
      pipeline.fit(X_train, y_train)
      
      # Bad: Preprocessing outside pipeline (can cause leakage)
      X_train_scaled = StandardScaler().fit_transform(X_train)
      model = LogisticRegression()
      model.fit(X_train_scaled, y_train)
      ```
      
      ### Use ColumnTransformer for Mixed Data
      Always use ColumnTransformer when you have both numerical and categorical features:
      ```python
      preprocessor = ColumnTransformer([
          ('num', StandardScaler(), numeric_features),
          ('cat', OneHotEncoder(), categorical_features)
      ])
      ```
      
      ### Name Your Steps Meaningfully
      ```python
      # Good
      pipeline = Pipeline([
          ('imputer', SimpleImputer()),
          ('scaler', StandardScaler()),
          ('pca', PCA(n_components=10)),
          ('rf_classifier', RandomForestClassifier())
      ])
      
      # Bad
      pipeline = Pipeline([
          ('step1', SimpleImputer()),
          ('step2', StandardScaler()),
          ('step3', PCA(n_components=10)),
          ('step4', RandomForestClassifier())
      ])
      ```
      
      ### Cache Expensive Transformations
      For repeated fitting (e.g., during grid search), cache expensive steps:
      ```python
      from tempfile import mkdtemp
      
      cachedir = mkdtemp()
      pipeline = Pipeline([
          ('expensive_preprocessing', ExpensiveTransformer()),
          ('classifier', LogisticRegression())
      ], memory=cachedir)
      ```
      
      ### Test Pipeline Compatibility
      Ensure all steps are compatible:
      - All intermediate steps must have fit() and transform()
      - Final step needs fit() and predict() (or transform())
      - Use set_output(transform='pandas') for DataFrame output
      ```python
      pipeline.set_output(transform='pandas')
      X_transformed = pipeline.transform(X)  # Returns DataFrame
      ```
      
    • preprocessing.md 15.6 KB
      # Data Preprocessing and Feature Engineering Reference
      
      ## Overview
      
      Data preprocessing transforms raw data into a format suitable for machine learning models. This includes scaling, encoding, handling missing values, and feature engineering.
      
      ## Feature Scaling and Normalization
      
      ### StandardScaler
      
      **StandardScaler (`sklearn.preprocessing.StandardScaler`)**
      - Standardizes features to zero mean and unit variance
      - Formula: z = (x - mean) / std
      - Use when: Features have different scales, algorithm assumes normally distributed data
      - Required for: SVM, KNN, Neural Networks, PCA, Linear Regression with regularization
      - Example:
      ```python
      from sklearn.preprocessing import StandardScaler
      
      scaler = StandardScaler()
      X_train_scaled = scaler.fit_transform(X_train)
      X_test_scaled = scaler.transform(X_test)  # Use same parameters as training
      
      # Access learned parameters
      print(f"Mean: {scaler.mean_}")
      print(f"Std: {scaler.scale_}")
      ```
      
      ### MinMaxScaler
      
      **MinMaxScaler (`sklearn.preprocessing.MinMaxScaler`)**
      - Scales features to a given range (default [0, 1])
      - Formula: X_scaled = (X - X.min) / (X.max - X.min)
      - Use when: Need bounded values, data not normally distributed
      - Sensitive to outliers
      - Example:
      ```python
      from sklearn.preprocessing import MinMaxScaler
      
      scaler = MinMaxScaler(feature_range=(0, 1))
      X_scaled = scaler.fit_transform(X_train)
      
      # Custom range
      scaler = MinMaxScaler(feature_range=(-1, 1))
      X_scaled = scaler.fit_transform(X_train)
      ```
      
      ### RobustScaler
      
      **RobustScaler (`sklearn.preprocessing.RobustScaler`)**
      - Scales using median and interquartile range (IQR)
      - Formula: X_scaled = (X - median) / IQR
      - Use when: Data contains outliers
      - Robust to outliers
      - Example:
      ```python
      from sklearn.preprocessing import RobustScaler
      
      scaler = RobustScaler()
      X_scaled = scaler.fit_transform(X_train)
      ```
      
      ### Normalizer
      
      **Normalizer (`sklearn.preprocessing.Normalizer`)**
      - Normalizes samples individually to unit norm
      - Common norms: 'l1', 'l2', 'max'
      - Use when: Need to normalize each sample independently (e.g., text features)
      - Example:
      ```python
      from sklearn.preprocessing import Normalizer
      
      normalizer = Normalizer(norm='l2')  # Euclidean norm
      X_normalized = normalizer.fit_transform(X)
      ```
      
      ### MaxAbsScaler
      
      **MaxAbsScaler (`sklearn.preprocessing.MaxAbsScaler`)**
      - Scales by maximum absolute value
      - Range: [-1, 1]
      - Doesn't shift/center data (preserves sparsity)
      - Use when: Data is already centered or sparse
      - Example:
      ```python
      from sklearn.preprocessing import MaxAbsScaler
      
      scaler = MaxAbsScaler()
      X_scaled = scaler.fit_transform(X_sparse)
      ```
      
      ## Encoding Categorical Variables
      
      ### OneHotEncoder
      
      **OneHotEncoder (`sklearn.preprocessing.OneHotEncoder`)**
      - Creates binary columns for each category
      - Use when: Nominal categories (no order), tree-based models or linear models
      - Example:
      ```python
      from sklearn.preprocessing import OneHotEncoder
      
      encoder = OneHotEncoder(sparse_output=False, handle_unknown='ignore')
      X_encoded = encoder.fit_transform(X_categorical)
      
      # Get feature names
      feature_names = encoder.get_feature_names_out(['color', 'size'])
      
      # Handle unknown categories during transform
      X_test_encoded = encoder.transform(X_test_categorical)
      ```
      
      ### OrdinalEncoder
      
      **OrdinalEncoder (`sklearn.preprocessing.OrdinalEncoder`)**
      - Encodes categories as integers
      - Use when: Ordinal categories (ordered), or tree-based models
      - Example:
      ```python
      from sklearn.preprocessing import OrdinalEncoder
      
      # Natural ordering
      encoder = OrdinalEncoder()
      X_encoded = encoder.fit_transform(X_categorical)
      
      # Custom ordering
      encoder = OrdinalEncoder(categories=[['small', 'medium', 'large']])
      X_encoded = encoder.fit_transform(X_categorical)
      ```
      
      ### LabelEncoder
      
      **LabelEncoder (`sklearn.preprocessing.LabelEncoder`)**
      - Encodes target labels (y) as integers
      - Use for: Target variable encoding
      - Example:
      ```python
      from sklearn.preprocessing import LabelEncoder
      
      le = LabelEncoder()
      y_encoded = le.fit_transform(y)
      
      # Decode back
      y_decoded = le.inverse_transform(y_encoded)
      print(f"Classes: {le.classes_}")
      ```
      
      ### Target Encoding
      
      scikit-learn ships `TargetEncoder` (≥ 1.3). Its `fit_transform` uses internal cross-fitting
      so training rows are not encoded with their own target, which limits leakage; call
      `fit_transform` on training data and `transform` on test data.
      
      ```python
      from sklearn.preprocessing import TargetEncoder
      
      encoder = TargetEncoder()  # pass cv=KFold(..., shuffle=True, random_state=42) to control the split
      X_train_encoded = encoder.fit_transform(X_train_categorical, y_train)
      X_test_encoded = encoder.transform(X_test_categorical)
      ```
      
      ## Non-linear Transformations
      
      ### Power Transforms
      
      **PowerTransformer**
      - Makes data more Gaussian-like
      - Methods: 'yeo-johnson' (works with negative values), 'box-cox' (positive only)
      - Use when: Data is skewed, algorithm assumes normality
      - Example:
      ```python
      from sklearn.preprocessing import PowerTransformer
      
      # Yeo-Johnson (handles negative values)
      pt = PowerTransformer(method='yeo-johnson', standardize=True)
      X_transformed = pt.fit_transform(X)
      
      # Box-Cox (positive values only)
      pt = PowerTransformer(method='box-cox', standardize=True)
      X_transformed = pt.fit_transform(X)
      ```
      
      ### Quantile Transformation
      
      **QuantileTransformer**
      - Transforms features to follow uniform or normal distribution
      - Robust to outliers
      - Use when: Want to reduce outlier impact
      - Example:
      ```python
      from sklearn.preprocessing import QuantileTransformer
      
      # Transform to uniform distribution
      qt = QuantileTransformer(output_distribution='uniform', random_state=42)
      X_transformed = qt.fit_transform(X)
      
      # Transform to normal distribution
      qt = QuantileTransformer(output_distribution='normal', random_state=42)
      X_transformed = qt.fit_transform(X)
      ```
      
      ### Log Transform
      
      ```python
      import numpy as np
      
      # Log1p (log(1 + x)) - handles zeros
      X_log = np.log1p(X)
      
      # Or use FunctionTransformer
      from sklearn.preprocessing import FunctionTransformer
      
      log_transformer = FunctionTransformer(np.log1p, inverse_func=np.expm1)
      X_log = log_transformer.fit_transform(X)
      ```
      
      ## Missing Value Imputation
      
      ### SimpleImputer
      
      **SimpleImputer (`sklearn.impute.SimpleImputer`)**
      - Basic imputation strategies
      - Strategies: 'mean', 'median', 'most_frequent', 'constant'
      - Example:
      ```python
      from sklearn.impute import SimpleImputer
      
      # For numerical features
      imputer = SimpleImputer(strategy='mean')
      X_imputed = imputer.fit_transform(X)
      
      # For categorical features
      imputer = SimpleImputer(strategy='most_frequent')
      X_imputed = imputer.fit_transform(X_categorical)
      
      # Fill with constant
      imputer = SimpleImputer(strategy='constant', fill_value=0)
      X_imputed = imputer.fit_transform(X)
      ```
      
      ### Iterative Imputer
      
      **IterativeImputer**
      - Models each feature with missing values as function of other features
      - More sophisticated than SimpleImputer
      - Example:
      ```python
      from sklearn.experimental import enable_iterative_imputer
      from sklearn.impute import IterativeImputer
      
      imputer = IterativeImputer(max_iter=10, random_state=42)
      X_imputed = imputer.fit_transform(X)
      ```
      
      ### KNN Imputer
      
      **KNNImputer**
      - Imputes using k-nearest neighbors
      - Use when: Features are correlated
      - Example:
      ```python
      from sklearn.impute import KNNImputer
      
      imputer = KNNImputer(n_neighbors=5)
      X_imputed = imputer.fit_transform(X)
      ```
      
      ## Feature Engineering
      
      ### Polynomial Features
      
      **PolynomialFeatures**
      - Creates polynomial and interaction features
      - Use when: Need non-linear features for linear models
      - Example:
      ```python
      from sklearn.preprocessing import PolynomialFeatures
      
      # Degree 2: includes x1, x2, x1^2, x2^2, x1*x2
      poly = PolynomialFeatures(degree=2, include_bias=False)
      X_poly = poly.fit_transform(X)
      
      # Get feature names
      feature_names = poly.get_feature_names_out(['x1', 'x2'])
      
      # Only interactions (no powers)
      poly = PolynomialFeatures(degree=2, interaction_only=True, include_bias=False)
      X_interactions = poly.fit_transform(X)
      ```
      
      ### Binning/Discretization
      
      **KBinsDiscretizer**
      - Bins continuous features into discrete intervals
      - Strategies: 'uniform', 'quantile', 'kmeans'
      - Encoding: 'onehot', 'ordinal', 'onehot-dense'
      - Example:
      ```python
      from sklearn.preprocessing import KBinsDiscretizer
      
      # Equal-width bins
      binner = KBinsDiscretizer(n_bins=5, encode='ordinal', strategy='uniform')
      X_binned = binner.fit_transform(X)
      
      # Equal-frequency bins (quantile-based)
      binner = KBinsDiscretizer(n_bins=5, encode='onehot', strategy='quantile')
      X_binned = binner.fit_transform(X)
      ```
      
      ### Binarization
      
      **Binarizer**
      - Converts features to binary (0 or 1) based on threshold
      - Example:
      ```python
      from sklearn.preprocessing import Binarizer
      
      binarizer = Binarizer(threshold=0.5)
      X_binary = binarizer.fit_transform(X)
      ```
      
      ### Spline Features
      
      **SplineTransformer**
      - Creates spline basis functions
      - Useful for capturing non-linear relationships
      - Example:
      ```python
      from sklearn.preprocessing import SplineTransformer
      
      spline = SplineTransformer(n_knots=5, degree=3)
      X_splines = spline.fit_transform(X)
      ```
      
      ## Text Feature Extraction
      
      ### CountVectorizer
      
      **CountVectorizer (`sklearn.feature_extraction.text.CountVectorizer`)**
      - Converts text to token count matrix
      - Use for: Bag-of-words representation
      - Example:
      ```python
      from sklearn.feature_extraction.text import CountVectorizer
      
      vectorizer = CountVectorizer(
          max_features=5000,  # Keep top 5000 features
          min_df=2,  # Ignore terms appearing in < 2 documents
          max_df=0.8,  # Ignore terms appearing in > 80% documents
          ngram_range=(1, 2)  # Unigrams and bigrams
      )
      
      X_counts = vectorizer.fit_transform(documents)
      feature_names = vectorizer.get_feature_names_out()
      ```
      
      ### TfidfVectorizer
      
      **TfidfVectorizer**
      - TF-IDF (Term Frequency-Inverse Document Frequency) transformation
      - Better than CountVectorizer for most tasks
      - Example:
      ```python
      from sklearn.feature_extraction.text import TfidfVectorizer
      
      vectorizer = TfidfVectorizer(
          max_features=5000,
          min_df=2,
          max_df=0.8,
          ngram_range=(1, 2),
          stop_words='english'  # Remove English stop words
      )
      
      X_tfidf = vectorizer.fit_transform(documents)
      ```
      
      ### HashingVectorizer
      
      **HashingVectorizer**
      - Uses hashing trick for memory efficiency
      - No fit needed, can't reverse transform
      - Use when: Very large vocabulary, streaming data
      - Example:
      ```python
      from sklearn.feature_extraction.text import HashingVectorizer
      
      vectorizer = HashingVectorizer(n_features=2**18)
      X_hashed = vectorizer.transform(documents)  # No fit needed
      ```
      
      ## Feature Selection
      
      ### Filter Methods
      
      **Variance Threshold**
      - Removes low-variance features
      - Example:
      ```python
      from sklearn.feature_selection import VarianceThreshold
      
      selector = VarianceThreshold(threshold=0.01)
      X_selected = selector.fit_transform(X)
      ```
      
      **SelectKBest / SelectPercentile**
      - Select features based on statistical tests
      - Tests: f_classif, chi2, mutual_info_classif
      - Example:
      ```python
      from sklearn.feature_selection import SelectKBest, f_classif
      
      # Select top 10 features
      selector = SelectKBest(score_func=f_classif, k=10)
      X_selected = selector.fit_transform(X_train, y_train)
      
      # Get selected feature indices
      selected_indices = selector.get_support(indices=True)
      ```
      
      ### Wrapper Methods
      
      **Recursive Feature Elimination (RFE)**
      - Recursively removes features
      - Uses model feature importances
      - Example:
      ```python
      from sklearn.feature_selection import RFE
      from sklearn.ensemble import RandomForestClassifier
      
      model = RandomForestClassifier(n_estimators=100, random_state=42)
      rfe = RFE(estimator=model, n_features_to_select=10, step=1)
      X_selected = rfe.fit_transform(X_train, y_train)
      
      # Get selected features
      selected_features = rfe.support_
      feature_ranking = rfe.ranking_
      ```
      
      **RFECV (with Cross-Validation)**
      - RFE with cross-validation to find optimal number of features
      - Example:
      ```python
      from sklearn.feature_selection import RFECV
      
      model = RandomForestClassifier(n_estimators=100, random_state=42)
      rfecv = RFECV(estimator=model, cv=5, scoring='accuracy')
      X_selected = rfecv.fit_transform(X_train, y_train)
      
      print(f"Optimal number of features: {rfecv.n_features_}")
      ```
      
      ### Embedded Methods
      
      **SelectFromModel**
      - Select features based on model coefficients/importances
      - Works with: Linear models (L1), Tree-based models
      - Example:
      ```python
      from sklearn.feature_selection import SelectFromModel
      from sklearn.ensemble import RandomForestClassifier
      
      model = RandomForestClassifier(n_estimators=100, random_state=42)
      selector = SelectFromModel(model, threshold='median')
      selector.fit(X_train, y_train)
      X_selected = selector.transform(X_train)
      
      # Get selected features
      selected_features = selector.get_support()
      ```
      
      **L1-based Feature Selection**
      ```python
      from sklearn.linear_model import LogisticRegression
      from sklearn.feature_selection import SelectFromModel
      
      # l1_ratio=1 is the L1 penalty (penalty='l1' is deprecated since scikit-learn 1.8)
      model = LogisticRegression(l1_ratio=1, solver='liblinear', C=0.1)
      selector = SelectFromModel(model)
      selector.fit(X_train, y_train)
      X_selected = selector.transform(X_train)
      ```
      
      ## Handling Outliers
      
      ### IQR Method
      
      ```python
      import numpy as np
      
      Q1 = np.percentile(X, 25, axis=0)
      Q3 = np.percentile(X, 75, axis=0)
      IQR = Q3 - Q1
      
      # Define outlier boundaries
      lower_bound = Q1 - 1.5 * IQR
      upper_bound = Q3 + 1.5 * IQR
      
      # Remove outliers
      mask = np.all((X >= lower_bound) & (X <= upper_bound), axis=1)
      X_no_outliers = X[mask]
      ```
      
      ### Winsorization
      
      ```python
      from scipy.stats import mstats
      
      # Clip outliers at 5th and 95th percentiles
      X_winsorized = mstats.winsorize(X, limits=[0.05, 0.05], axis=0)
      ```
      
      ## Custom Transformers
      
      ### Using FunctionTransformer
      
      ```python
      from sklearn.preprocessing import FunctionTransformer
      import numpy as np
      
      def log_transform(X):
          return np.log1p(X)
      
      transformer = FunctionTransformer(log_transform, inverse_func=np.expm1)
      X_transformed = transformer.fit_transform(X)
      ```
      
      ### Creating Custom Transformer
      
      ```python
      from sklearn.base import BaseEstimator, TransformerMixin
      
      class CustomTransformer(BaseEstimator, TransformerMixin):
          def __init__(self, parameter=1):
              self.parameter = parameter
      
          def fit(self, X, y=None):
              # Learn parameters from X if needed
              return self
      
          def transform(self, X):
              # Transform X
              return X * self.parameter
      
      transformer = CustomTransformer(parameter=2)
      X_transformed = transformer.fit_transform(X)
      ```
      
      ## Best Practices
      
      ### Fit on Training Data Only
      Always fit transformers on training data only:
      ```python
      # Correct
      scaler = StandardScaler()
      X_train_scaled = scaler.fit_transform(X_train)
      X_test_scaled = scaler.transform(X_test)
      
      # Wrong - causes data leakage
      scaler = StandardScaler()
      X_all_scaled = scaler.fit_transform(np.vstack([X_train, X_test]))
      ```
      
      ### Use Pipelines
      Combine preprocessing with models:
      ```python
      from sklearn.pipeline import Pipeline
      from sklearn.preprocessing import StandardScaler
      from sklearn.linear_model import LogisticRegression
      
      pipeline = Pipeline([
          ('scaler', StandardScaler()),
          ('classifier', LogisticRegression())
      ])
      
      pipeline.fit(X_train, y_train)
      ```
      
      ### Handle Categorical and Numerical Separately
      Use ColumnTransformer:
      ```python
      from sklearn.compose import ColumnTransformer
      from sklearn.preprocessing import StandardScaler, OneHotEncoder
      
      numeric_features = ['age', 'income']
      categorical_features = ['gender', 'occupation']
      
      preprocessor = ColumnTransformer(
          transformers=[
              ('num', StandardScaler(), numeric_features),
              ('cat', OneHotEncoder(), categorical_features)
          ]
      )
      
      X_transformed = preprocessor.fit_transform(X)
      ```
      
      ### Algorithm-Specific Requirements
      
      **Require Scaling:**
      - SVM, KNN, Neural Networks
      - PCA, Linear/Logistic Regression with regularization
      - K-Means clustering
      
      **Don't Require Scaling:**
      - Tree-based models (Decision Trees, Random Forest, Gradient Boosting)
      - Naive Bayes
      
      **Encoding Requirements:**
      - Linear models, SVM, KNN: One-hot encoding for nominal features
      - Tree-based models: Can handle ordinal encoding directly
      
    • quick_reference.md 11.3 KB
      # Scikit-learn Quick Reference
      
      ## Common Import Patterns
      
      ```python
      # Core scikit-learn
      import sklearn
      
      # Data splitting and cross-validation
      from sklearn.model_selection import train_test_split, cross_val_score, GridSearchCV
      
      # Preprocessing
      from sklearn.preprocessing import StandardScaler, MinMaxScaler, OneHotEncoder
      from sklearn.impute import SimpleImputer
      
      # Feature selection
      from sklearn.feature_selection import SelectKBest, RFE
      
      # Supervised learning
      from sklearn.linear_model import LogisticRegression, Ridge, Lasso
      from sklearn.ensemble import RandomForestClassifier, GradientBoostingRegressor
      from sklearn.svm import SVC, SVR
      from sklearn.tree import DecisionTreeClassifier
      
      # Unsupervised learning
      from sklearn.cluster import KMeans, DBSCAN, AgglomerativeClustering
      from sklearn.decomposition import PCA, NMF
      
      # Metrics
      from sklearn.metrics import (
          accuracy_score, precision_score, recall_score, f1_score,
          mean_squared_error, r2_score, confusion_matrix, classification_report
      )
      
      # Pipeline
      from sklearn.pipeline import Pipeline, make_pipeline
      from sklearn.compose import ColumnTransformer, make_column_transformer
      
      # Utilities
      import numpy as np
      import pandas as pd
      import matplotlib.pyplot as plt
      ```
      
      ## Installation
      
      ```bash
      # Using uv (recommended)
      uv pip install scikit-learn
      
      # Common companions (matplotlib is needed for the *Display plotting helpers)
      uv pip install pandas numpy matplotlib seaborn
      ```
      
      ## Quick Workflow Templates
      
      ### Classification Pipeline
      
      ```python
      from sklearn.model_selection import train_test_split
      from sklearn.preprocessing import StandardScaler
      from sklearn.ensemble import RandomForestClassifier
      from sklearn.metrics import classification_report, confusion_matrix
      
      # Split data
      X_train, X_test, y_train, y_test = train_test_split(
          X, y, test_size=0.2, stratify=y, random_state=42
      )
      
      # Preprocess
      scaler = StandardScaler()
      X_train_scaled = scaler.fit_transform(X_train)
      X_test_scaled = scaler.transform(X_test)
      
      # Train
      model = RandomForestClassifier(n_estimators=100, random_state=42)
      model.fit(X_train_scaled, y_train)
      
      # Evaluate
      y_pred = model.predict(X_test_scaled)
      print(classification_report(y_test, y_pred))
      print(confusion_matrix(y_test, y_pred))
      ```
      
      ### Regression Pipeline
      
      ```python
      from sklearn.model_selection import train_test_split
      from sklearn.preprocessing import StandardScaler
      from sklearn.ensemble import GradientBoostingRegressor
      from sklearn.metrics import root_mean_squared_error, r2_score
      
      # Split
      X_train, X_test, y_train, y_test = train_test_split(
          X, y, test_size=0.2, random_state=42
      )
      
      # Preprocess and train
      scaler = StandardScaler()
      X_train_scaled = scaler.fit_transform(X_train)
      X_test_scaled = scaler.transform(X_test)
      
      model = GradientBoostingRegressor(n_estimators=100, random_state=42)
      model.fit(X_train_scaled, y_train)
      
      # Evaluate
      y_pred = model.predict(X_test_scaled)
      # root_mean_squared_error added in sklearn 1.4; the squared= arg was removed in 1.6
      print(f"RMSE: {root_mean_squared_error(y_test, y_pred):.3f}")
      print(f"R² Score: {r2_score(y_test, y_pred):.3f}")
      ```
      
      ### Cross-Validation
      
      ```python
      from sklearn.model_selection import cross_val_score
      from sklearn.ensemble import RandomForestClassifier
      
      model = RandomForestClassifier(n_estimators=100, random_state=42)
      scores = cross_val_score(model, X, y, cv=5, scoring='accuracy')
      print(f"CV Accuracy: {scores.mean():.3f} (+/- {scores.std() * 2:.3f})")
      ```
      
      ### Complete Pipeline with Mixed Data Types
      
      ```python
      from sklearn.pipeline import Pipeline
      from sklearn.compose import ColumnTransformer
      from sklearn.preprocessing import StandardScaler, OneHotEncoder
      from sklearn.impute import SimpleImputer
      from sklearn.ensemble import RandomForestClassifier
      
      # Define feature types
      numeric_features = ['age', 'income']
      categorical_features = ['gender', 'occupation']
      
      # Create preprocessing pipelines
      numeric_transformer = Pipeline([
          ('imputer', SimpleImputer(strategy='median')),
          ('scaler', StandardScaler())
      ])
      
      categorical_transformer = Pipeline([
          ('imputer', SimpleImputer(strategy='most_frequent')),
          ('onehot', OneHotEncoder(handle_unknown='ignore'))
      ])
      
      # Combine transformers
      preprocessor = ColumnTransformer([
          ('num', numeric_transformer, numeric_features),
          ('cat', categorical_transformer, categorical_features)
      ])
      
      # Full pipeline
      model = Pipeline([
          ('preprocessor', preprocessor),
          ('classifier', RandomForestClassifier(n_estimators=100, random_state=42))
      ])
      
      # Fit and predict
      model.fit(X_train, y_train)
      y_pred = model.predict(X_test)
      ```
      
      ### Hyperparameter Tuning
      
      ```python
      from sklearn.model_selection import GridSearchCV
      from sklearn.ensemble import RandomForestClassifier
      
      param_grid = {
          'n_estimators': [100, 200, 300],
          'max_depth': [10, 20, None],
          'min_samples_split': [2, 5, 10]
      }
      
      model = RandomForestClassifier(random_state=42)
      grid_search = GridSearchCV(
          model, param_grid, cv=5, scoring='accuracy', n_jobs=-1
      )
      
      grid_search.fit(X_train, y_train)
      print(f"Best params: {grid_search.best_params_}")
      print(f"Best score: {grid_search.best_score_:.3f}")
      
      # Use best model
      best_model = grid_search.best_estimator_
      ```
      
      ## Common Patterns
      
      ### Loading Data
      
      ```python
      # From scikit-learn datasets
      from sklearn.datasets import load_iris, load_digits, make_classification
      
      # Built-in datasets
      iris = load_iris()
      X, y = iris.data, iris.target
      
      # Synthetic data
      X, y = make_classification(
          n_samples=1000, n_features=20, n_classes=2, random_state=42
      )
      
      # From pandas
      import pandas as pd
      df = pd.read_csv('data.csv')
      X = df.drop('target', axis=1)
      y = df['target']
      ```
      
      ### Handling Imbalanced Data
      
      ```python
      from sklearn.ensemble import RandomForestClassifier
      
      # Use class_weight parameter
      model = RandomForestClassifier(class_weight='balanced', random_state=42)
      model.fit(X_train, y_train)
      
      # Or use appropriate metrics
      from sklearn.metrics import balanced_accuracy_score, f1_score
      print(f"Balanced Accuracy: {balanced_accuracy_score(y_test, y_pred):.3f}")
      print(f"F1 Score: {f1_score(y_test, y_pred):.3f}")
      ```
      
      ### Feature Importance
      
      ```python
      from sklearn.ensemble import RandomForestClassifier
      import pandas as pd
      
      model = RandomForestClassifier(n_estimators=100, random_state=42)
      model.fit(X_train, y_train)
      
      # Get feature importances
      importances = pd.DataFrame({
          'feature': feature_names,
          'importance': model.feature_importances_
      }).sort_values('importance', ascending=False)
      
      print(importances.head(10))
      ```
      
      ### Clustering
      
      ```python
      from sklearn.cluster import KMeans
      from sklearn.preprocessing import StandardScaler
      
      # Scale data first
      scaler = StandardScaler()
      X_scaled = scaler.fit_transform(X)
      
      # Fit K-Means
      kmeans = KMeans(n_clusters=3, random_state=42)
      labels = kmeans.fit_predict(X_scaled)
      
      # Evaluate
      from sklearn.metrics import silhouette_score
      score = silhouette_score(X_scaled, labels)
      print(f"Silhouette Score: {score:.3f}")
      ```
      
      ### Dimensionality Reduction
      
      ```python
      from sklearn.decomposition import PCA
      import matplotlib.pyplot as plt
      
      # Fit PCA
      pca = PCA(n_components=2)
      X_reduced = pca.fit_transform(X)
      
      # Plot
      plt.scatter(X_reduced[:, 0], X_reduced[:, 1], c=y, cmap='viridis')
      plt.xlabel('PC1')
      plt.ylabel('PC2')
      plt.title(f'PCA (explained variance: {pca.explained_variance_ratio_.sum():.2%})')
      ```
      
      ### Model Persistence
      
      ```python
      import joblib
      
      # Save model
      joblib.dump(model, 'model.pkl')
      
      # Load model
      loaded_model = joblib.load('model.pkl')
      predictions = loaded_model.predict(X_new)
      ```
      
      ## Common Gotchas and Solutions
      
      ### Data Leakage
      ```python
      # WRONG: Fitting scaler on all data
      scaler = StandardScaler()
      X_scaled = scaler.fit_transform(X)
      X_train, X_test = train_test_split(X_scaled)
      
      # RIGHT: Fit on training data only
      X_train, X_test = train_test_split(X)
      scaler = StandardScaler()
      X_train_scaled = scaler.fit_transform(X_train)
      X_test_scaled = scaler.transform(X_test)
      
      # BEST: Use Pipeline
      from sklearn.pipeline import Pipeline
      pipeline = Pipeline([
          ('scaler', StandardScaler()),
          ('model', LogisticRegression())
      ])
      pipeline.fit(X_train, y_train)  # No leakage!
      ```
      
      ### Stratified Splitting for Classification
      ```python
      # Always use stratify for classification
      X_train, X_test, y_train, y_test = train_test_split(
          X, y, test_size=0.2, stratify=y, random_state=42
      )
      ```
      
      ### Random State for Reproducibility
      ```python
      # Set random_state for reproducibility
      model = RandomForestClassifier(n_estimators=100, random_state=42)
      ```
      
      ### Handling Unknown Categories
      ```python
      # Use handle_unknown='ignore' for OneHotEncoder
      encoder = OneHotEncoder(handle_unknown='ignore')
      ```
      
      ### Feature Names with Pipelines
      ```python
      # Get feature names after transformation
      preprocessor.fit(X_train)
      feature_names = preprocessor.get_feature_names_out()
      ```
      
      ## Cheat Sheet: Algorithm Selection
      
      ### Classification
      
      | Problem | Algorithm | When to Use |
      |---------|-----------|-------------|
      | Binary/Multiclass | Logistic Regression | Fast baseline, interpretability |
      | Binary/Multiclass | Random Forest | Good default, robust |
      | Binary/Multiclass | Gradient Boosting | Best accuracy, willing to tune |
      | Binary/Multiclass | SVM | Small data, complex boundaries |
      | Binary/Multiclass | Naive Bayes | Text classification, fast |
      | High dimensions | Linear SVM or Logistic | Text, many features |
      
      ### Regression
      
      | Problem | Algorithm | When to Use |
      |---------|-----------|-------------|
      | Continuous target | Linear Regression | Fast baseline, interpretability |
      | Continuous target | Ridge/Lasso | Regularization needed |
      | Continuous target | Random Forest | Good default, non-linear |
      | Continuous target | Gradient Boosting | Best accuracy |
      | Continuous target | SVR | Small data, non-linear |
      
      ### Clustering
      
      | Problem | Algorithm | When to Use |
      |---------|-----------|-------------|
      | Known K, spherical | K-Means | Fast, simple |
      | Unknown K, arbitrary shapes | DBSCAN | Noise/outliers present |
      | Hierarchical structure | Agglomerative | Need dendrogram |
      | Soft clustering | Gaussian Mixture | Probability estimates |
      
      ### Dimensionality Reduction
      
      | Problem | Algorithm | When to Use |
      |---------|-----------|-------------|
      | Linear reduction | PCA | Variance explanation |
      | Visualization | t-SNE | 2D/3D plots |
      | Non-negative data | NMF | Images, text |
      | Sparse data | TruncatedSVD | Text, recommender systems |
      
      ## Performance Tips
      
      ### Speed Up Training
      ```python
      # Use n_jobs=-1 for parallel processing
      model = RandomForestClassifier(n_estimators=100, n_jobs=-1)
      
      # Use warm_start for incremental learning
      model = RandomForestClassifier(n_estimators=100, warm_start=True)
      model.fit(X, y)
      model.n_estimators += 50
      model.fit(X, y)  # Adds 50 more trees
      
      # Use partial_fit for online learning
      from sklearn.linear_model import SGDClassifier
      model = SGDClassifier()
      for X_batch, y_batch in batches:
          model.partial_fit(X_batch, y_batch, classes=np.unique(y))
      ```
      
      ### Memory Efficiency
      ```python
      # Use sparse matrices
      from scipy.sparse import csr_matrix
      X_sparse = csr_matrix(X)
      
      # Use MiniBatchKMeans for large data
      from sklearn.cluster import MiniBatchKMeans
      model = MiniBatchKMeans(n_clusters=8, batch_size=100)
      ```
      
      ## Version Check
      
      ```python
      import sklearn
      print(f"scikit-learn version: {sklearn.__version__}")
      ```
      
      ## Useful Resources
      
      - Official Documentation: https://scikit-learn.org/stable/
      - User Guide: https://scikit-learn.org/stable/user_guide.html
      - API Reference: https://scikit-learn.org/stable/api/index.html
      - Examples: https://scikit-learn.org/stable/auto_examples/index.html
      - Tutorials: https://scikit-learn.org/stable/user_guide.html
      
    • supervised_learning.md 11 KB
      # Supervised Learning Reference
      
      ## Overview
      
      Supervised learning algorithms learn from labeled training data to make predictions on new data. Scikit-learn provides comprehensive implementations for both classification and regression tasks.
      
      ## Linear Models
      
      ### Regression
      
      **Linear Regression (`sklearn.linear_model.LinearRegression`)**
      - Ordinary least squares regression
      - Fast, interpretable, no hyperparameters
      - Use when: Linear relationships, interpretability matters
      - Example:
      ```python
      from sklearn.linear_model import LinearRegression
      
      model = LinearRegression()
      model.fit(X_train, y_train)
      predictions = model.predict(X_test)
      ```
      
      **Ridge Regression (`sklearn.linear_model.Ridge`)**
      - L2 regularization to prevent overfitting
      - Key parameter: `alpha` (regularization strength, default=1.0)
      - Use when: Multicollinearity present, need regularization
      - Example:
      ```python
      from sklearn.linear_model import Ridge
      
      model = Ridge(alpha=1.0)
      model.fit(X_train, y_train)
      ```
      
      **Lasso (`sklearn.linear_model.Lasso`)**
      - L1 regularization with feature selection
      - Key parameter: `alpha` (regularization strength)
      - Use when: Want sparse models, feature selection
      - Can reduce some coefficients to exactly zero
      - Example:
      ```python
      from sklearn.linear_model import Lasso
      
      model = Lasso(alpha=0.1)
      model.fit(X_train, y_train)
      # Check which features were selected
      print(f"Non-zero coefficients: {sum(model.coef_ != 0)}")
      ```
      
      **ElasticNet (`sklearn.linear_model.ElasticNet`)**
      - Combines L1 and L2 regularization
      - Key parameters: `alpha`, `l1_ratio` (0=Ridge, 1=Lasso)
      - Use when: Need both feature selection and regularization
      - Example:
      ```python
      from sklearn.linear_model import ElasticNet
      
      model = ElasticNet(alpha=0.1, l1_ratio=0.5)
      model.fit(X_train, y_train)
      ```
      
      ### Classification
      
      **Logistic Regression (`sklearn.linear_model.LogisticRegression`)**
      - Binary and multiclass classification
      - Key parameters: `C` (inverse regularization; `C=np.inf` for no penalty), `l1_ratio` (0 = L2, 1 = L1, in between = elastic net). `penalty=` is deprecated since 1.8 and is removed in 1.10
      - Returns probability estimates
      - Use when: Need probabilistic predictions, interpretability
      - Example:
      ```python
      from sklearn.linear_model import LogisticRegression
      
      model = LogisticRegression(C=1.0, max_iter=1000)
      model.fit(X_train, y_train)
      probas = model.predict_proba(X_test)
      ```
      
      **Stochastic Gradient Descent (SGD)**
      - `SGDClassifier`, `SGDRegressor`
      - Efficient for large-scale learning
      - Key parameters: `loss`, `penalty`, `alpha`, `learning_rate`
      - Use when: Very large datasets (>10^4 samples)
      - Example:
      ```python
      from sklearn.linear_model import SGDClassifier
      
      model = SGDClassifier(loss='log_loss', max_iter=1000, tol=1e-3)
      model.fit(X_train, y_train)
      ```
      
      ## Support Vector Machines
      
      **SVC (`sklearn.svm.SVC`)**
      - Classification with kernel methods
      - Key parameters: `C`, `kernel` ('linear', 'rbf', 'poly'), `gamma`
      - Use when: Small to medium datasets, complex decision boundaries
      - Note: Does not scale well to large datasets
      - Example:
      ```python
      from sklearn.svm import SVC
      
      # Linear kernel for linearly separable data
      model_linear = SVC(kernel='linear', C=1.0)
      
      # RBF kernel for non-linear data
      model_rbf = SVC(kernel='rbf', C=1.0, gamma='scale')
      model_rbf.fit(X_train, y_train)
      ```
      
      **SVR (`sklearn.svm.SVR`)**
      - Regression with kernel methods
      - Similar parameters to SVC
      - Additional parameter: `epsilon` (tube width)
      - Example:
      ```python
      from sklearn.svm import SVR
      
      model = SVR(kernel='rbf', C=1.0, epsilon=0.1)
      model.fit(X_train, y_train)
      ```
      
      ## Decision Trees
      
      **DecisionTreeClassifier / DecisionTreeRegressor**
      - Non-parametric model learning decision rules
      - Key parameters:
        - `max_depth`: Maximum tree depth (prevents overfitting)
        - `min_samples_split`: Minimum samples to split a node
        - `min_samples_leaf`: Minimum samples in leaf
        - `criterion`: 'gini', 'entropy' for classification; 'squared_error', 'absolute_error' for regression
      - Use when: Need interpretable model, non-linear relationships, mixed feature types
      - Prone to overfitting - use ensembles or pruning
      - Example:
      ```python
      from sklearn.tree import DecisionTreeClassifier
      
      model = DecisionTreeClassifier(
          max_depth=5,
          min_samples_split=20,
          min_samples_leaf=10,
          criterion='gini'
      )
      model.fit(X_train, y_train)
      
      # Visualize the tree
      from sklearn.tree import plot_tree
      plot_tree(model, feature_names=feature_names, class_names=class_names)
      ```
      
      ## Ensemble Methods
      
      ### Random Forests
      
      **RandomForestClassifier / RandomForestRegressor**
      - Ensemble of decision trees with bagging
      - Key parameters:
        - `n_estimators`: Number of trees (default=100)
        - `max_depth`: Maximum tree depth
        - `max_features`: Features to consider for splits ('sqrt', 'log2', or int)
        - `min_samples_split`, `min_samples_leaf`: Control tree growth
      - Use when: High accuracy needed, can afford computation
      - Provides feature importance
      - Example:
      ```python
      from sklearn.ensemble import RandomForestClassifier
      
      model = RandomForestClassifier(
          n_estimators=100,
          max_depth=10,
          max_features='sqrt',
          n_jobs=-1  # Use all CPU cores
      )
      model.fit(X_train, y_train)
      
      # Feature importance
      importances = model.feature_importances_
      ```
      
      ### Gradient Boosting
      
      **GradientBoostingClassifier / GradientBoostingRegressor**
      - Sequential ensemble building trees on residuals
      - Key parameters:
        - `n_estimators`: Number of boosting stages
        - `learning_rate`: Shrinks contribution of each tree
        - `max_depth`: Depth of individual trees (typically 3-5)
        - `subsample`: Fraction of samples for training each tree
      - Use when: Need high accuracy, can afford training time
      - Often achieves best performance
      - Example:
      ```python
      from sklearn.ensemble import GradientBoostingClassifier
      
      model = GradientBoostingClassifier(
          n_estimators=100,
          learning_rate=0.1,
          max_depth=3,
          subsample=0.8
      )
      model.fit(X_train, y_train)
      ```
      
      **HistGradientBoostingClassifier / HistGradientBoostingRegressor**
      - Faster gradient boosting with histogram-based algorithm
      - Native support for missing values and categorical features
      - Key parameters: Similar to GradientBoosting
      - Use when: Large datasets, need faster training
      - Example:
      ```python
      from sklearn.ensemble import HistGradientBoostingClassifier
      
      model = HistGradientBoostingClassifier(
          max_iter=100,
          learning_rate=0.1,
          max_depth=None,  # No limit by default
          categorical_features='from_dtype'  # Auto-detect categorical
      )
      model.fit(X_train, y_train)
      ```
      
      ### Other Ensemble Methods
      
      **AdaBoost**
      - Adaptive boosting focusing on misclassified samples
      - Key parameters: `n_estimators`, `learning_rate`, `estimator` (base estimator)
      - Use when: Simple boosting approach needed
      - Example:
      ```python
      from sklearn.ensemble import AdaBoostClassifier
      
      model = AdaBoostClassifier(n_estimators=50, learning_rate=1.0)
      model.fit(X_train, y_train)
      ```
      
      **Voting Classifier / Regressor**
      - Combines predictions from multiple models
      - Types: 'hard' (majority vote) or 'soft' (average probabilities)
      - Use when: Want to ensemble different model types
      - Example:
      ```python
      from sklearn.calibration import CalibratedClassifierCV
      from sklearn.ensemble import VotingClassifier
      from sklearn.linear_model import LogisticRegression
      from sklearn.tree import DecisionTreeClassifier
      from sklearn.svm import SVC
      
      model = VotingClassifier(
          estimators=[
              ('lr', LogisticRegression()),
              ('dt', DecisionTreeClassifier()),
              # SVC(probability=True) is deprecated in 1.9; calibrate explicitly instead
              ('svc', CalibratedClassifierCV(SVC(), ensemble=False))
          ],
          voting='soft'
      )
      model.fit(X_train, y_train)
      ```
      
      **Stacking Classifier / Regressor**
      - Trains a meta-model on predictions from base models
      - More sophisticated than voting
      - Key parameter: `final_estimator` (meta-learner)
      - Example:
      ```python
      from sklearn.ensemble import StackingClassifier
      from sklearn.linear_model import LogisticRegression
      from sklearn.tree import DecisionTreeClassifier
      from sklearn.svm import SVC
      
      model = StackingClassifier(
          estimators=[
              ('dt', DecisionTreeClassifier()),
              ('svc', SVC())
          ],
          final_estimator=LogisticRegression()
      )
      model.fit(X_train, y_train)
      ```
      
      ## K-Nearest Neighbors
      
      **KNeighborsClassifier / KNeighborsRegressor**
      - Non-parametric method based on distance
      - Key parameters:
        - `n_neighbors`: Number of neighbors (default=5)
        - `weights`: 'uniform' or 'distance'
        - `metric`: Distance metric ('euclidean', 'manhattan', etc.)
      - Use when: Small dataset, simple baseline needed
      - Slow prediction on large datasets
      - Example:
      ```python
      from sklearn.neighbors import KNeighborsClassifier
      
      model = KNeighborsClassifier(n_neighbors=5, weights='distance')
      model.fit(X_train, y_train)
      ```
      
      ## Naive Bayes
      
      **GaussianNB, MultinomialNB, BernoulliNB**
      - Probabilistic classifiers based on Bayes' theorem
      - Fast training and prediction
      - GaussianNB: Continuous features (assumes Gaussian distribution)
      - MultinomialNB: Count features (text classification)
      - BernoulliNB: Binary features
      - Use when: Text classification, fast baseline, probabilistic predictions
      - Example:
      ```python
      from sklearn.naive_bayes import GaussianNB, MultinomialNB
      
      # For continuous features
      model_gaussian = GaussianNB()
      
      # For text/count data
      model_multinomial = MultinomialNB(alpha=1.0)  # alpha is smoothing parameter
      model_multinomial.fit(X_train, y_train)
      ```
      
      ## Neural Networks
      
      **MLPClassifier / MLPRegressor**
      - Multi-layer perceptron (feedforward neural network)
      - Key parameters:
        - `hidden_layer_sizes`: Tuple of hidden layer sizes, e.g., (100, 50)
        - `activation`: 'relu', 'tanh', 'logistic'
        - `solver`: 'adam', 'sgd', 'lbfgs'
        - `alpha`: L2 regularization parameter
        - `learning_rate`: 'constant', 'adaptive'
      - Use when: Complex non-linear patterns, large datasets
      - Requires feature scaling
      - Example:
      ```python
      from sklearn.neural_network import MLPClassifier
      from sklearn.preprocessing import StandardScaler
      
      # Scale features first
      scaler = StandardScaler()
      X_train_scaled = scaler.fit_transform(X_train)
      
      model = MLPClassifier(
          hidden_layer_sizes=(100, 50),
          activation='relu',
          solver='adam',
          alpha=0.0001,
          max_iter=1000
      )
      model.fit(X_train_scaled, y_train)
      ```
      
      ## Algorithm Selection Guide
      
      ### Choose based on:
      
      **Dataset size:**
      - Small (<1k samples): KNN, SVM, Decision Trees
      - Medium (1k-100k): Random Forest, Gradient Boosting, Linear Models
      - Large (>100k): SGD, Linear Models, HistGradientBoosting
      
      **Interpretability:**
      - High: Linear Models, Decision Trees
      - Medium: Random Forest (feature importance)
      - Low: SVM with RBF kernel, Neural Networks
      
      **Accuracy vs Speed:**
      - Fast training: Naive Bayes, Linear Models, KNN
      - High accuracy: Gradient Boosting, Random Forest, Stacking
      - Fast prediction: Linear Models, Naive Bayes
      - Slow prediction: KNN (on large datasets), SVM
      
      **Feature types:**
      - Continuous: Most algorithms work well
      - Categorical: Trees, HistGradientBoosting (native support)
      - Mixed: Trees, Gradient Boosting
      - Text: Naive Bayes, Linear Models with TF-IDF
      
      **Common starting points:**
      1. Logistic Regression (classification) / Linear Regression (regression) - fast baseline
      2. Random Forest - good default choice
      3. Gradient Boosting - optimize for best accuracy
      
    • unsupervised_learning.md 14.5 KB
      # Unsupervised Learning Reference
      
      ## Overview
      
      Unsupervised learning discovers patterns in unlabeled data through clustering, dimensionality reduction, and density estimation.
      
      ## Clustering
      
      ### K-Means
      
      **KMeans (`sklearn.cluster.KMeans`)**
      - Partition-based clustering into K clusters
      - Key parameters:
        - `n_clusters`: Number of clusters to form
        - `init`: Initialization method ('k-means++', 'random')
        - `n_init`: Number of initializations (default=10)
        - `max_iter`: Maximum iterations
      - Use when: Know number of clusters, spherical cluster shapes
      - Fast and scalable
      - Example:
      ```python
      from sklearn.cluster import KMeans
      
      model = KMeans(n_clusters=3, init='k-means++', n_init=10, random_state=42)
      labels = model.fit_predict(X)
      centers = model.cluster_centers_
      
      # Inertia (sum of squared distances to nearest center)
      print(f"Inertia: {model.inertia_}")
      ```
      
      **MiniBatchKMeans**
      - Faster K-Means using mini-batches
      - Use when: Large datasets, need faster training
      - Slightly less accurate than K-Means
      - Example:
      ```python
      from sklearn.cluster import MiniBatchKMeans
      
      model = MiniBatchKMeans(n_clusters=3, batch_size=100, random_state=42)
      labels = model.fit_predict(X)
      ```
      
      ### Density-Based Clustering
      
      **DBSCAN (`sklearn.cluster.DBSCAN`)**
      - Density-Based Spatial Clustering
      - Key parameters:
        - `eps`: Maximum distance between two samples to be neighbors
        - `min_samples`: Minimum samples in neighborhood to form core point
        - `metric`: Distance metric
      - Use when: Arbitrary cluster shapes, presence of noise/outliers
      - Automatically determines number of clusters
      - Labels noise points as -1
      - Example:
      ```python
      from sklearn.cluster import DBSCAN
      
      model = DBSCAN(eps=0.5, min_samples=5, metric='euclidean')
      labels = model.fit_predict(X)
      
      # Number of clusters (excluding noise)
      n_clusters = len(set(labels)) - (1 if -1 in labels else 0)
      n_noise = list(labels).count(-1)
      print(f"Clusters: {n_clusters}, Noise points: {n_noise}")
      ```
      
      **HDBSCAN (`sklearn.cluster.HDBSCAN`)**
      - Hierarchical DBSCAN with adaptive epsilon
      - More robust than DBSCAN
      - Key parameter: `min_cluster_size`
      - Use when: Varying density clusters
      - Example:
      ```python
      from sklearn.cluster import HDBSCAN
      
      # copy=True avoids modifying X in place (the default changes to True in 1.10)
      model = HDBSCAN(min_cluster_size=10, min_samples=5, copy=True)
      labels = model.fit_predict(X)
      ```
      
      **OPTICS (`sklearn.cluster.OPTICS`)**
      - Ordering points to identify clustering structure
      - Similar to DBSCAN but doesn't require eps parameter
      - Key parameters: `min_samples`, `max_eps`
      - Use when: Varying density, exploratory analysis
      - Example:
      ```python
      from sklearn.cluster import OPTICS
      
      model = OPTICS(min_samples=5, max_eps=0.5)
      labels = model.fit_predict(X)
      ```
      
      ### Hierarchical Clustering
      
      **AgglomerativeClustering**
      - Bottom-up hierarchical clustering
      - Key parameters:
        - `n_clusters`: Number of clusters (or use `distance_threshold`)
        - `linkage`: 'ward', 'complete', 'average', 'single'
        - `metric`: Distance metric
      - Use when: Need dendrogram, hierarchical structure important
      - Example:
      ```python
      from sklearn.cluster import AgglomerativeClustering
      
      model = AgglomerativeClustering(n_clusters=3, linkage='ward')
      labels = model.fit_predict(X)
      
      # Create dendrogram using scipy
      from scipy.cluster.hierarchy import dendrogram, linkage
      Z = linkage(X, method='ward')
      dendrogram(Z)
      ```
      
      ### Other Clustering Methods
      
      **MeanShift**
      - Finds clusters by shifting points toward mode of density
      - Automatically determines number of clusters
      - Key parameter: `bandwidth`
      - Use when: Don't know number of clusters, arbitrary shapes
      - Example:
      ```python
      from sklearn.cluster import MeanShift, estimate_bandwidth
      
      # Estimate bandwidth
      bandwidth = estimate_bandwidth(X, quantile=0.2, n_samples=500)
      model = MeanShift(bandwidth=bandwidth)
      labels = model.fit_predict(X)
      ```
      
      **SpectralClustering**
      - Uses graph-based approach with eigenvalues
      - Key parameters: `n_clusters`, `affinity` ('rbf', 'nearest_neighbors')
      - Use when: Non-convex clusters, graph structure
      - Example:
      ```python
      from sklearn.cluster import SpectralClustering
      
      model = SpectralClustering(n_clusters=3, affinity='rbf', random_state=42)
      labels = model.fit_predict(X)
      ```
      
      **AffinityPropagation**
      - Finds exemplars by message passing
      - Automatically determines number of clusters
      - Key parameters: `damping`, `preference`
      - Use when: Don't know number of clusters
      - Example:
      ```python
      from sklearn.cluster import AffinityPropagation
      
      model = AffinityPropagation(damping=0.9, random_state=42)
      labels = model.fit_predict(X)
      n_clusters = len(model.cluster_centers_indices_)
      ```
      
      **BIRCH**
      - Balanced Iterative Reducing and Clustering using Hierarchies
      - Memory efficient for large datasets
      - Key parameters: `n_clusters`, `threshold`, `branching_factor`
      - Use when: Very large datasets
      - Example:
      ```python
      from sklearn.cluster import Birch
      
      model = Birch(n_clusters=3, threshold=0.5)
      labels = model.fit_predict(X)
      ```
      
      ### Clustering Evaluation
      
      **Metrics when ground truth is known:**
      ```python
      from sklearn.metrics import adjusted_rand_score, normalized_mutual_info_score
      from sklearn.metrics import adjusted_mutual_info_score, fowlkes_mallows_score
      
      # Compare predicted labels with true labels
      ari = adjusted_rand_score(y_true, y_pred)
      nmi = normalized_mutual_info_score(y_true, y_pred)
      ami = adjusted_mutual_info_score(y_true, y_pred)
      fmi = fowlkes_mallows_score(y_true, y_pred)
      ```
      
      **Metrics without ground truth:**
      ```python
      from sklearn.metrics import silhouette_score, calinski_harabasz_score
      from sklearn.metrics import davies_bouldin_score
      
      # Silhouette: [-1, 1], higher is better
      silhouette = silhouette_score(X, labels)
      
      # Calinski-Harabasz: higher is better
      ch_score = calinski_harabasz_score(X, labels)
      
      # Davies-Bouldin: lower is better
      db_score = davies_bouldin_score(X, labels)
      ```
      
      **Elbow method for K-Means:**
      ```python
      from sklearn.cluster import KMeans
      import matplotlib.pyplot as plt
      
      inertias = []
      K_range = range(2, 11)
      for k in K_range:
          model = KMeans(n_clusters=k, random_state=42)
          model.fit(X)
          inertias.append(model.inertia_)
      
      plt.plot(K_range, inertias, 'bo-')
      plt.xlabel('Number of clusters')
      plt.ylabel('Inertia')
      plt.title('Elbow Method')
      ```
      
      ## Dimensionality Reduction
      
      ### Principal Component Analysis (PCA)
      
      **PCA (`sklearn.decomposition.PCA`)**
      - Linear dimensionality reduction using SVD
      - Key parameters:
        - `n_components`: Number of components (int or float for explained variance)
        - `whiten`: Whiten components to unit variance
      - Use when: Linear relationships, want to explain variance
      - Example:
      ```python
      from sklearn.decomposition import PCA
      
      # Keep components explaining 95% variance
      pca = PCA(n_components=0.95)
      X_reduced = pca.fit_transform(X)
      
      print(f"Original dimensions: {X.shape[1]}")
      print(f"Reduced dimensions: {X_reduced.shape[1]}")
      print(f"Explained variance ratio: {pca.explained_variance_ratio_}")
      print(f"Total variance explained: {pca.explained_variance_ratio_.sum()}")
      
      # Or specify exact number of components
      pca = PCA(n_components=2)
      X_2d = pca.fit_transform(X)
      ```
      
      **IncrementalPCA**
      - PCA for large datasets that don't fit in memory
      - Processes data in batches
      - Key parameter: `n_components`, `batch_size`
      - Example:
      ```python
      from sklearn.decomposition import IncrementalPCA
      
      pca = IncrementalPCA(n_components=50, batch_size=100)
      X_reduced = pca.fit_transform(X)
      ```
      
      **KernelPCA**
      - Non-linear dimensionality reduction using kernels
      - Key parameters: `n_components`, `kernel` ('linear', 'poly', 'rbf', 'sigmoid')
      - Use when: Non-linear relationships
      - Example:
      ```python
      from sklearn.decomposition import KernelPCA
      
      pca = KernelPCA(n_components=2, kernel='rbf', gamma=0.1)
      X_reduced = pca.fit_transform(X)
      ```
      
      ### Manifold Learning
      
      **t-SNE (`sklearn.manifold.TSNE`)**
      - t-distributed Stochastic Neighbor Embedding
      - Excellent for 2D/3D visualization
      - Key parameters:
        - `n_components`: Usually 2 or 3
        - `perplexity`: Balance between local and global structure (5-50)
        - `learning_rate`: Usually 10-1000 (or 'auto')
        - `max_iter`: Number of iterations (min 250). Renamed from `n_iter`, which was removed in sklearn 1.7
      - Use when: Visualizing high-dimensional data
      - Note: Slow on large datasets, no transform() method
      - Example:
      ```python
      from sklearn.manifold import TSNE
      
      tsne = TSNE(n_components=2, perplexity=30, learning_rate='auto', max_iter=1000, random_state=42)
      X_embedded = tsne.fit_transform(X)
      
      # Visualize
      import matplotlib.pyplot as plt
      plt.scatter(X_embedded[:, 0], X_embedded[:, 1], c=labels, cmap='viridis')
      plt.title('t-SNE visualization')
      ```
      
      **UMAP (not in scikit-learn, but compatible)**
      - Uniform Manifold Approximation and Projection
      - Faster than t-SNE, preserves global structure better
      - Install: `uv pip install umap-learn`
      - Example:
      ```python
      from umap import UMAP
      
      reducer = UMAP(n_components=2, n_neighbors=15, min_dist=0.1, random_state=42)
      X_embedded = reducer.fit_transform(X)
      ```
      
      **Isomap**
      - Isometric Mapping
      - Preserves geodesic distances
      - Key parameters: `n_components`, `n_neighbors`
      - Use when: Non-linear manifolds
      - Example:
      ```python
      from sklearn.manifold import Isomap
      
      isomap = Isomap(n_components=2, n_neighbors=5)
      X_embedded = isomap.fit_transform(X)
      ```
      
      **Locally Linear Embedding (LLE)**
      - Preserves local neighborhood structure
      - Key parameters: `n_components`, `n_neighbors`
      - Example:
      ```python
      from sklearn.manifold import LocallyLinearEmbedding
      
      lle = LocallyLinearEmbedding(n_components=2, n_neighbors=10)
      X_embedded = lle.fit_transform(X)
      ```
      
      **MDS (Multidimensional Scaling)**
      - Preserves pairwise distances
      - Key parameters: `n_components`, `metric_mds` (True = metric MDS, False = non-metric), `init`
      - scikit-learn ≥ 1.8 renamed the boolean `metric` to `metric_mds` (`metric` now names the distance, and `dissimilarity='precomputed'` became `metric='precomputed'`); passing `metric=True` warns and stops working in 1.10
      - Example:
      ```python
      from sklearn.manifold import MDS
      
      mds = MDS(n_components=2, metric_mds=True, init='classical_mds', random_state=42)
      X_embedded = mds.fit_transform(X)
      ```
      
      ### Matrix Factorization
      
      **NMF (Non-negative Matrix Factorization)**
      - Factorizes into non-negative matrices
      - Key parameters: `n_components`, `init` ('nndsvd', 'random')
      - Use when: Data is non-negative (images, text)
      - Interpretable components
      - Example:
      ```python
      from sklearn.decomposition import NMF
      
      nmf = NMF(n_components=10, init='nndsvd', random_state=42)
      W = nmf.fit_transform(X)  # Document-topic matrix
      H = nmf.components_  # Topic-word matrix
      ```
      
      **TruncatedSVD**
      - SVD for sparse matrices
      - Similar to PCA but works with sparse data
      - Use when: Text data, sparse matrices
      - Example:
      ```python
      from sklearn.decomposition import TruncatedSVD
      
      svd = TruncatedSVD(n_components=100, random_state=42)
      X_reduced = svd.fit_transform(X_sparse)
      print(f"Explained variance: {svd.explained_variance_ratio_.sum()}")
      ```
      
      **FastICA**
      - Independent Component Analysis
      - Separates multivariate signal into independent components
      - Key parameter: `n_components`
      - Use when: Signal separation (e.g., audio, EEG)
      - Example:
      ```python
      from sklearn.decomposition import FastICA
      
      ica = FastICA(n_components=10, random_state=42)
      S = ica.fit_transform(X)  # Independent sources
      A = ica.mixing_  # Mixing matrix
      ```
      
      **LatentDirichletAllocation (LDA)**
      - Topic modeling for text data
      - Key parameters: `n_components` (number of topics), `learning_method` ('batch', 'online')
      - Use when: Topic modeling, document clustering
      - Example:
      ```python
      from sklearn.decomposition import LatentDirichletAllocation
      
      lda = LatentDirichletAllocation(n_components=10, random_state=42)
      doc_topics = lda.fit_transform(X_counts)  # Document-topic distribution
      
      # Get top words for each topic
      feature_names = vectorizer.get_feature_names_out()
      for topic_idx, topic in enumerate(lda.components_):
          top_words = [feature_names[i] for i in topic.argsort()[-10:]]
          print(f"Topic {topic_idx}: {', '.join(top_words)}")
      ```
      
      ## Outlier and Novelty Detection
      
      ### Outlier Detection
      
      **IsolationForest**
      - Isolates anomalies using random trees
      - Key parameters:
        - `contamination`: Expected proportion of outliers
        - `n_estimators`: Number of trees
      - Use when: High-dimensional data, efficiency important
      - Example:
      ```python
      from sklearn.ensemble import IsolationForest
      
      model = IsolationForest(contamination=0.1, random_state=42)
      predictions = model.fit_predict(X)  # -1 for outliers, 1 for inliers
      ```
      
      **LocalOutlierFactor**
      - Measures local density deviation
      - Key parameters: `n_neighbors`, `contamination`
      - Use when: Varying density regions
      - Example:
      ```python
      from sklearn.neighbors import LocalOutlierFactor
      
      lof = LocalOutlierFactor(n_neighbors=20, contamination=0.1)
      predictions = lof.fit_predict(X)  # -1 for outliers, 1 for inliers
      outlier_scores = lof.negative_outlier_factor_
      ```
      
      **One-Class SVM**
      - Learns decision boundary around normal data
      - Key parameters: `nu` (upper bound on outliers), `kernel`, `gamma`
      - Use when: Small training set of normal data
      - Example:
      ```python
      from sklearn.svm import OneClassSVM
      
      model = OneClassSVM(nu=0.1, kernel='rbf', gamma='auto')
      model.fit(X_train)
      predictions = model.predict(X_test)  # -1 for outliers, 1 for inliers
      ```
      
      **EllipticEnvelope**
      - Assumes Gaussian distribution
      - Key parameter: `contamination`
      - Use when: Data is Gaussian-distributed
      - Example:
      ```python
      from sklearn.covariance import EllipticEnvelope
      
      model = EllipticEnvelope(contamination=0.1, random_state=42)
      predictions = model.fit_predict(X)
      ```
      
      ## Gaussian Mixture Models
      
      **GaussianMixture**
      - Probabilistic clustering with mixture of Gaussians
      - Key parameters:
        - `n_components`: Number of mixture components
        - `covariance_type`: 'full', 'tied', 'diag', 'spherical'
      - Use when: Soft clustering, need probability estimates
      - Example:
      ```python
      from sklearn.mixture import GaussianMixture
      
      gmm = GaussianMixture(n_components=3, covariance_type='full', random_state=42)
      gmm.fit(X)
      
      # Predict cluster labels
      labels = gmm.predict(X)
      
      # Get probability of each cluster
      probabilities = gmm.predict_proba(X)
      
      # Information criteria for model selection
      print(f"BIC: {gmm.bic(X)}")  # Lower is better
      print(f"AIC: {gmm.aic(X)}")  # Lower is better
      ```
      
      ## Choosing the Right Method
      
      ### Clustering:
      - **Know K, spherical clusters**: K-Means
      - **Arbitrary shapes, noise**: DBSCAN, HDBSCAN
      - **Hierarchical structure**: AgglomerativeClustering
      - **Very large data**: MiniBatchKMeans, BIRCH
      - **Probabilistic**: GaussianMixture
      
      ### Dimensionality Reduction:
      - **Linear, variance explanation**: PCA
      - **Non-linear, visualization**: t-SNE, UMAP
      - **Non-negative data**: NMF
      - **Sparse data**: TruncatedSVD
      - **Topic modeling**: LatentDirichletAllocation
      
      ### Outlier Detection:
      - **High-dimensional**: IsolationForest
      - **Varying density**: LocalOutlierFactor
      - **Gaussian data**: EllipticEnvelope
      
    • worked_examples.md 5.3 KB
      # Scikit-learn Worked Examples
      
      Copy-paste workflows for the most common scikit-learn tasks. All examples set `random_state=42` for reproducibility and use pipelines to prevent data leakage.
      
      ## Quick Start: Classification
      
      ```python
      from sklearn.model_selection import train_test_split
      from sklearn.preprocessing import StandardScaler
      from sklearn.ensemble import RandomForestClassifier
      from sklearn.metrics import classification_report
      
      # Split data
      X_train, X_test, y_train, y_test = train_test_split(
          X, y, test_size=0.2, stratify=y, random_state=42
      )
      
      # Preprocess
      scaler = StandardScaler()
      X_train_scaled = scaler.fit_transform(X_train)
      X_test_scaled = scaler.transform(X_test)
      
      # Train model
      model = RandomForestClassifier(n_estimators=100, random_state=42)
      model.fit(X_train_scaled, y_train)
      
      # Evaluate
      y_pred = model.predict(X_test_scaled)
      print(classification_report(y_test, y_pred))
      ```
      
      ## Quick Start: Complete Pipeline with Mixed Data
      
      ```python
      from sklearn.pipeline import Pipeline
      from sklearn.compose import ColumnTransformer
      from sklearn.preprocessing import StandardScaler, OneHotEncoder
      from sklearn.impute import SimpleImputer
      from sklearn.ensemble import GradientBoostingClassifier
      
      # Define feature types
      numeric_features = ['age', 'income']
      categorical_features = ['gender', 'occupation']
      
      # Create preprocessing pipelines
      numeric_transformer = Pipeline([
          ('imputer', SimpleImputer(strategy='median')),
          ('scaler', StandardScaler())
      ])
      
      categorical_transformer = Pipeline([
          ('imputer', SimpleImputer(strategy='most_frequent')),
          ('onehot', OneHotEncoder(handle_unknown='ignore'))
      ])
      
      # Combine transformers
      preprocessor = ColumnTransformer([
          ('num', numeric_transformer, numeric_features),
          ('cat', categorical_transformer, categorical_features)
      ])
      
      # Full pipeline
      model = Pipeline([
          ('preprocessor', preprocessor),
          ('classifier', GradientBoostingClassifier(random_state=42))
      ])
      
      # Fit and predict
      model.fit(X_train, y_train)
      y_pred = model.predict(X_test)
      ```
      
      ## Workflow: Building a Classification Model
      
      1. **Load and explore data**
         ```python
         import pandas as pd
         df = pd.read_csv('data.csv')
         X = df.drop('target', axis=1)
         y = df['target']
         ```
      
      2. **Split data with stratification**
         ```python
         from sklearn.model_selection import train_test_split
         X_train, X_test, y_train, y_test = train_test_split(
             X, y, test_size=0.2, stratify=y, random_state=42
         )
         ```
      
      3. **Create preprocessing pipeline**
         ```python
         from sklearn.pipeline import Pipeline
         from sklearn.preprocessing import StandardScaler
         from sklearn.compose import ColumnTransformer
      
         # Handle numeric and categorical features separately
         preprocessor = ColumnTransformer([
             ('num', StandardScaler(), numeric_features),
             ('cat', OneHotEncoder(), categorical_features)
         ])
         ```
      
      4. **Build complete pipeline**
         ```python
         model = Pipeline([
             ('preprocessor', preprocessor),
             ('classifier', RandomForestClassifier(random_state=42))
         ])
         ```
      
      5. **Tune hyperparameters**
         ```python
         from sklearn.model_selection import GridSearchCV
      
         param_grid = {
             'classifier__n_estimators': [100, 200],
             'classifier__max_depth': [10, 20, None]
         }
      
         grid_search = GridSearchCV(model, param_grid, cv=5)
         grid_search.fit(X_train, y_train)
         ```
      
      6. **Evaluate on test set**
         ```python
         from sklearn.metrics import classification_report
      
         best_model = grid_search.best_estimator_
         y_pred = best_model.predict(X_test)
         print(classification_report(y_test, y_pred))
         ```
      
      ## Workflow: Performing Clustering Analysis
      
      1. **Preprocess data**
         ```python
         from sklearn.preprocessing import StandardScaler
      
         scaler = StandardScaler()
         X_scaled = scaler.fit_transform(X)
         ```
      
      2. **Find optimal number of clusters**
         ```python
         from sklearn.cluster import KMeans
         from sklearn.metrics import silhouette_score
      
         scores = []
         for k in range(2, 11):
             kmeans = KMeans(n_clusters=k, random_state=42)
             labels = kmeans.fit_predict(X_scaled)
             scores.append(silhouette_score(X_scaled, labels))
      
         optimal_k = range(2, 11)[np.argmax(scores)]
         ```
      
      3. **Apply clustering**
         ```python
         model = KMeans(n_clusters=optimal_k, random_state=42)
         labels = model.fit_predict(X_scaled)
         ```
      
      4. **Visualize with dimensionality reduction**
         ```python
         from sklearn.decomposition import PCA
      
         pca = PCA(n_components=2)
         X_2d = pca.fit_transform(X_scaled)
      
         plt.scatter(X_2d[:, 0], X_2d[:, 1], c=labels, cmap='viridis')
         ```
      
      ## Example Scripts
      
      ### Classification Pipeline
      
      Run a complete classification workflow with preprocessing, model comparison, hyperparameter tuning, and evaluation:
      
      ```bash
      python scripts/classification_pipeline.py
      ```
      
      Demonstrates: handling mixed data types (numeric and categorical), model comparison using cross-validation, hyperparameter tuning with `GridSearchCV`, comprehensive evaluation with multiple metrics, and feature importance analysis.
      
      ### Clustering Analysis
      
      Perform clustering analysis with algorithm comparison and visualization:
      
      ```bash
      python scripts/clustering_analysis.py
      ```
      
      Demonstrates: finding the optimal number of clusters (elbow method, silhouette analysis), comparing multiple clustering algorithms (K-Means, DBSCAN, Agglomerative, Gaussian Mixture), evaluating clustering quality without ground truth, and visualizing results with PCA projection.
      
  • scripts
    • classification_pipeline.py 7.9 KB
      """
      Complete classification pipeline example with preprocessing, model training,
      hyperparameter tuning, and evaluation.
      """
      
      import numpy as np
      import pandas as pd
      from sklearn.model_selection import train_test_split, GridSearchCV, cross_val_score
      from sklearn.preprocessing import StandardScaler, OneHotEncoder
      from sklearn.impute import SimpleImputer
      from sklearn.compose import ColumnTransformer
      from sklearn.pipeline import Pipeline
      from sklearn.ensemble import RandomForestClassifier, GradientBoostingClassifier
      from sklearn.linear_model import LogisticRegression
      from sklearn.metrics import (
          classification_report, confusion_matrix, roc_auc_score,
          accuracy_score, precision_score, recall_score, f1_score
      )
      import warnings
      warnings.filterwarnings('ignore')
      
      
      def create_preprocessing_pipeline(numeric_features, categorical_features):
          """
          Create a preprocessing pipeline for mixed data types.
      
          Parameters:
          -----------
          numeric_features : list
              List of numeric feature column names
          categorical_features : list
              List of categorical feature column names
      
          Returns:
          --------
          ColumnTransformer
              Preprocessing pipeline
          """
          # Numeric preprocessing
          numeric_transformer = Pipeline(steps=[
              ('imputer', SimpleImputer(strategy='median')),
              ('scaler', StandardScaler())
          ])
      
          # Categorical preprocessing
          categorical_transformer = Pipeline(steps=[
              ('imputer', SimpleImputer(strategy='constant', fill_value='missing')),
              ('onehot', OneHotEncoder(handle_unknown='ignore', sparse_output=False))
          ])
      
          # Combine transformers
          preprocessor = ColumnTransformer(
              transformers=[
                  ('num', numeric_transformer, numeric_features),
                  ('cat', categorical_transformer, categorical_features)
              ]
          )
      
          return preprocessor
      
      
      def train_and_evaluate_model(X, y, numeric_features, categorical_features,
                                   test_size=0.2, random_state=42):
          """
          Complete pipeline: preprocess, train, tune, and evaluate a classifier.
      
          Parameters:
          -----------
          X : DataFrame or array
              Feature matrix
          y : Series or array
              Target variable
          numeric_features : list
              List of numeric feature names
          categorical_features : list
              List of categorical feature names
          test_size : float
              Proportion of data for testing
          random_state : int
              Random seed
      
          Returns:
          --------
          dict
              Dictionary containing trained model, predictions, and metrics
          """
          # Split data with stratification
          X_train, X_test, y_train, y_test = train_test_split(
              X, y, test_size=test_size, stratify=y, random_state=random_state
          )
      
          print(f"Training set size: {len(X_train)}")
          print(f"Test set size: {len(X_test)}")
          print(f"Class distribution in training: {pd.Series(y_train).value_counts().to_dict()}")
      
          # Create preprocessor
          preprocessor = create_preprocessing_pipeline(numeric_features, categorical_features)
      
          # Define models to compare
          models = {
              'Logistic Regression': Pipeline([
                  ('preprocessor', preprocessor),
                  ('classifier', LogisticRegression(max_iter=1000, random_state=random_state))
              ]),
              'Random Forest': Pipeline([
                  ('preprocessor', preprocessor),
                  ('classifier', RandomForestClassifier(n_estimators=100, random_state=random_state))
              ]),
              'Gradient Boosting': Pipeline([
                  ('preprocessor', preprocessor),
                  ('classifier', GradientBoostingClassifier(n_estimators=100, random_state=random_state))
              ])
          }
      
          # Compare models using cross-validation
          print("\n" + "="*60)
          print("Model Comparison (5-Fold Cross-Validation)")
          print("="*60)
      
          cv_results = {}
          for name, model in models.items():
              scores = cross_val_score(model, X_train, y_train, cv=5, scoring='accuracy')
              cv_results[name] = scores.mean()
              print(f"{name:20s}: {scores.mean():.4f} (+/- {scores.std() * 2:.4f})")
      
          # Select best model based on CV
          best_model_name = max(cv_results, key=cv_results.get)
          best_model = models[best_model_name]
      
          print(f"\nBest model: {best_model_name}")
      
          # Hyperparameter tuning for best model
          if best_model_name == 'Random Forest':
              param_grid = {
                  'classifier__n_estimators': [100, 200],
                  'classifier__max_depth': [10, 20, None],
                  'classifier__min_samples_split': [2, 5]
              }
          elif best_model_name == 'Gradient Boosting':
              param_grid = {
                  'classifier__n_estimators': [100, 200],
                  'classifier__learning_rate': [0.01, 0.1],
                  'classifier__max_depth': [3, 5]
              }
          else:  # Logistic Regression
              param_grid = {
                  'classifier__C': [0.1, 1.0, 10.0],
                  'classifier__penalty': ['l2']
              }
      
          print("\n" + "="*60)
          print("Hyperparameter Tuning")
          print("="*60)
      
          grid_search = GridSearchCV(
              best_model, param_grid, cv=5, scoring='accuracy',
              n_jobs=-1, verbose=0
          )
      
          grid_search.fit(X_train, y_train)
      
          print(f"Best parameters: {grid_search.best_params_}")
          print(f"Best CV score: {grid_search.best_score_:.4f}")
      
          # Evaluate on test set
          tuned_model = grid_search.best_estimator_
          y_pred = tuned_model.predict(X_test)
          y_pred_proba = tuned_model.predict_proba(X_test)
      
          print("\n" + "="*60)
          print("Test Set Evaluation")
          print("="*60)
      
          # Calculate metrics
          accuracy = accuracy_score(y_test, y_pred)
          precision = precision_score(y_test, y_pred, average='weighted')
          recall = recall_score(y_test, y_pred, average='weighted')
          f1 = f1_score(y_test, y_pred, average='weighted')
      
          print(f"Accuracy:  {accuracy:.4f}")
          print(f"Precision: {precision:.4f}")
          print(f"Recall:    {recall:.4f}")
          print(f"F1-Score:  {f1:.4f}")
      
          # ROC AUC (if binary classification)
          if len(np.unique(y)) == 2:
              roc_auc = roc_auc_score(y_test, y_pred_proba[:, 1])
              print(f"ROC AUC:   {roc_auc:.4f}")
      
          print("\n" + "="*60)
          print("Classification Report")
          print("="*60)
          print(classification_report(y_test, y_pred))
      
          print("\n" + "="*60)
          print("Confusion Matrix")
          print("="*60)
          print(confusion_matrix(y_test, y_pred))
      
          # Feature importance (if available)
          if hasattr(tuned_model.named_steps['classifier'], 'feature_importances_'):
              print("\n" + "="*60)
              print("Top 10 Most Important Features")
              print("="*60)
      
              feature_names = tuned_model.named_steps['preprocessor'].get_feature_names_out()
              importances = tuned_model.named_steps['classifier'].feature_importances_
      
              feature_importance_df = pd.DataFrame({
                  'feature': feature_names,
                  'importance': importances
              }).sort_values('importance', ascending=False).head(10)
      
              print(feature_importance_df.to_string(index=False))
      
          return {
              'model': tuned_model,
              'y_test': y_test,
              'y_pred': y_pred,
              'y_pred_proba': y_pred_proba,
              'metrics': {
                  'accuracy': accuracy,
                  'precision': precision,
                  'recall': recall,
                  'f1': f1
              }
          }
      
      
      # Example usage
      if __name__ == "__main__":
          # Load example dataset
          from sklearn.datasets import load_breast_cancer
      
          # Load data
          data = load_breast_cancer()
          X = pd.DataFrame(data.data, columns=data.feature_names)
          y = data.target
      
          # For demonstration, treat all features as numeric
          numeric_features = X.columns.tolist()
          categorical_features = []
      
          print("="*60)
          print("Classification Pipeline Example")
          print("Dataset: Breast Cancer Wisconsin")
          print("="*60)
      
          # Run complete pipeline
          results = train_and_evaluate_model(
              X, y, numeric_features, categorical_features,
              test_size=0.2, random_state=42
          )
      
          print("\n" + "="*60)
          print("Pipeline Complete!")
          print("="*60)
      
    • clustering_analysis.py 11.1 KB
      """
      Clustering analysis example with multiple algorithms, evaluation, and visualization.
      """
      
      import numpy as np
      import matplotlib.pyplot as plt
      from sklearn.preprocessing import StandardScaler
      from sklearn.decomposition import PCA
      from sklearn.cluster import KMeans, DBSCAN, AgglomerativeClustering
      from sklearn.mixture import GaussianMixture
      from sklearn.metrics import (
          silhouette_score, calinski_harabasz_score, davies_bouldin_score
      )
      import warnings
      warnings.filterwarnings('ignore')
      
      
      def preprocess_for_clustering(X, scale=True, pca_components=None):
          """
          Preprocess data for clustering.
      
          Parameters:
          -----------
          X : array-like
              Feature matrix
          scale : bool
              Whether to standardize features
          pca_components : int or None
              Number of PCA components (None to skip PCA)
      
          Returns:
          --------
          array
              Preprocessed data
          """
          X_processed = X.copy()
      
          if scale:
              scaler = StandardScaler()
              X_processed = scaler.fit_transform(X_processed)
      
          if pca_components is not None:
              pca = PCA(n_components=pca_components)
              X_processed = pca.fit_transform(X_processed)
              print(f"PCA: Explained variance ratio = {pca.explained_variance_ratio_.sum():.3f}")
      
          return X_processed
      
      
      def find_optimal_k_kmeans(X, k_range=range(2, 11)):
          """
          Find optimal K for K-Means using elbow method and silhouette score.
      
          Parameters:
          -----------
          X : array-like
              Feature matrix (should be scaled)
          k_range : range
              Range of K values to test
      
          Returns:
          --------
          dict
              Dictionary with inertia and silhouette scores for each K
          """
          inertias = []
          silhouette_scores = []
      
          for k in k_range:
              kmeans = KMeans(n_clusters=k, random_state=42, n_init=10)
              labels = kmeans.fit_predict(X)
      
              inertias.append(kmeans.inertia_)
              silhouette_scores.append(silhouette_score(X, labels))
      
          # Plot results
          fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 4))
      
          # Elbow plot
          ax1.plot(k_range, inertias, 'bo-')
          ax1.set_xlabel('Number of clusters (K)')
          ax1.set_ylabel('Inertia')
          ax1.set_title('Elbow Method')
          ax1.grid(True)
      
          # Silhouette plot
          ax2.plot(k_range, silhouette_scores, 'ro-')
          ax2.set_xlabel('Number of clusters (K)')
          ax2.set_ylabel('Silhouette Score')
          ax2.set_title('Silhouette Analysis')
          ax2.grid(True)
      
          plt.tight_layout()
          plt.savefig('clustering_optimization.png', dpi=300, bbox_inches='tight')
          print("Saved: clustering_optimization.png")
          plt.close()
      
          # Find best K based on silhouette score
          best_k = k_range[np.argmax(silhouette_scores)]
          print(f"\nRecommended K based on silhouette score: {best_k}")
      
          return {
              'k_values': list(k_range),
              'inertias': inertias,
              'silhouette_scores': silhouette_scores,
              'best_k': best_k
          }
      
      
      def compare_clustering_algorithms(X, n_clusters=3):
          """
          Compare different clustering algorithms.
      
          Parameters:
          -----------
          X : array-like
              Feature matrix (should be scaled)
          n_clusters : int
              Number of clusters
      
          Returns:
          --------
          dict
              Dictionary with results for each algorithm
          """
          print("="*60)
          print(f"Comparing Clustering Algorithms (n_clusters={n_clusters})")
          print("="*60)
      
          algorithms = {
              'K-Means': KMeans(n_clusters=n_clusters, random_state=42, n_init=10),
              'Agglomerative': AgglomerativeClustering(n_clusters=n_clusters, linkage='ward'),
              'Gaussian Mixture': GaussianMixture(n_components=n_clusters, random_state=42)
          }
      
          # DBSCAN doesn't require n_clusters
          # We'll add it separately
          dbscan = DBSCAN(eps=0.5, min_samples=5)
          dbscan_labels = dbscan.fit_predict(X)
      
          results = {}
      
          for name, algorithm in algorithms.items():
              labels = algorithm.fit_predict(X)
      
              # Calculate metrics
              silhouette = silhouette_score(X, labels)
              calinski = calinski_harabasz_score(X, labels)
              davies = davies_bouldin_score(X, labels)
      
              results[name] = {
                  'labels': labels,
                  'n_clusters': n_clusters,
                  'silhouette': silhouette,
                  'calinski_harabasz': calinski,
                  'davies_bouldin': davies
              }
      
              print(f"\n{name}:")
              print(f"  Silhouette Score:       {silhouette:.4f} (higher is better)")
              print(f"  Calinski-Harabasz:      {calinski:.4f} (higher is better)")
              print(f"  Davies-Bouldin:         {davies:.4f} (lower is better)")
      
          # DBSCAN results
          n_clusters_dbscan = len(set(dbscan_labels)) - (1 if -1 in dbscan_labels else 0)
          n_noise = list(dbscan_labels).count(-1)
      
          if n_clusters_dbscan > 1:
              # Only calculate metrics if we have multiple clusters
              mask = dbscan_labels != -1  # Exclude noise
              if mask.sum() > 0:
                  silhouette = silhouette_score(X[mask], dbscan_labels[mask])
                  calinski = calinski_harabasz_score(X[mask], dbscan_labels[mask])
                  davies = davies_bouldin_score(X[mask], dbscan_labels[mask])
      
                  results['DBSCAN'] = {
                      'labels': dbscan_labels,
                      'n_clusters': n_clusters_dbscan,
                      'n_noise': n_noise,
                      'silhouette': silhouette,
                      'calinski_harabasz': calinski,
                      'davies_bouldin': davies
                  }
      
                  print(f"\nDBSCAN:")
                  print(f"  Clusters found:         {n_clusters_dbscan}")
                  print(f"  Noise points:           {n_noise}")
                  print(f"  Silhouette Score:       {silhouette:.4f} (higher is better)")
                  print(f"  Calinski-Harabasz:      {calinski:.4f} (higher is better)")
                  print(f"  Davies-Bouldin:         {davies:.4f} (lower is better)")
          else:
              print(f"\nDBSCAN:")
              print(f"  Clusters found:         {n_clusters_dbscan}")
              print(f"  Noise points:           {n_noise}")
              print("  Note: Insufficient clusters for metric calculation")
      
          return results
      
      
      def visualize_clusters(X, results, true_labels=None):
          """
          Visualize clustering results using PCA for 2D projection.
      
          Parameters:
          -----------
          X : array-like
              Feature matrix
          results : dict
              Dictionary with clustering results
          true_labels : array-like or None
              True labels (if available) for comparison
          """
          # Reduce to 2D using PCA
          pca = PCA(n_components=2)
          X_2d = pca.fit_transform(X)
      
          # Determine number of subplots
          n_plots = len(results)
          if true_labels is not None:
              n_plots += 1
      
          n_cols = min(3, n_plots)
          n_rows = (n_plots + n_cols - 1) // n_cols
      
          fig, axes = plt.subplots(n_rows, n_cols, figsize=(5*n_cols, 4*n_rows))
          if n_plots == 1:
              axes = np.array([axes])
          axes = axes.flatten()
      
          plot_idx = 0
      
          # Plot true labels if available
          if true_labels is not None:
              ax = axes[plot_idx]
              scatter = ax.scatter(X_2d[:, 0], X_2d[:, 1], c=true_labels, cmap='viridis', alpha=0.6)
              ax.set_title('True Labels')
              ax.set_xlabel(f'PC1 ({pca.explained_variance_ratio_[0]:.2%})')
              ax.set_ylabel(f'PC2 ({pca.explained_variance_ratio_[1]:.2%})')
              plt.colorbar(scatter, ax=ax)
              plot_idx += 1
      
          # Plot clustering results
          for name, result in results.items():
              ax = axes[plot_idx]
              labels = result['labels']
      
              scatter = ax.scatter(X_2d[:, 0], X_2d[:, 1], c=labels, cmap='viridis', alpha=0.6)
      
              # Highlight noise points for DBSCAN
              if name == 'DBSCAN' and -1 in labels:
                  noise_mask = labels == -1
                  ax.scatter(X_2d[noise_mask, 0], X_2d[noise_mask, 1],
                            c='red', marker='x', s=100, label='Noise', alpha=0.8)
                  ax.legend()
      
              title = f"{name} (K={result['n_clusters']})"
              if 'silhouette' in result:
                  title += f"\nSilhouette: {result['silhouette']:.3f}"
              ax.set_title(title)
              ax.set_xlabel(f'PC1 ({pca.explained_variance_ratio_[0]:.2%})')
              ax.set_ylabel(f'PC2 ({pca.explained_variance_ratio_[1]:.2%})')
              plt.colorbar(scatter, ax=ax)
      
              plot_idx += 1
      
          # Hide unused subplots
          for idx in range(plot_idx, len(axes)):
              axes[idx].axis('off')
      
          plt.tight_layout()
          plt.savefig('clustering_results.png', dpi=300, bbox_inches='tight')
          print("\nSaved: clustering_results.png")
          plt.close()
      
      
      def complete_clustering_analysis(X, true_labels=None, scale=True,
                                       find_k=True, k_range=range(2, 11), n_clusters=3):
          """
          Complete clustering analysis workflow.
      
          Parameters:
          -----------
          X : array-like
              Feature matrix
          true_labels : array-like or None
              True labels (for comparison only, not used in clustering)
          scale : bool
              Whether to scale features
          find_k : bool
              Whether to search for optimal K
          k_range : range
              Range of K values to test
          n_clusters : int
              Number of clusters to use in comparison
      
          Returns:
          --------
          dict
              Dictionary with all analysis results
          """
          print("="*60)
          print("Clustering Analysis")
          print("="*60)
          print(f"Data shape: {X.shape}")
      
          # Preprocess data
          X_processed = preprocess_for_clustering(X, scale=scale)
      
          # Find optimal K if requested
          optimization_results = None
          if find_k:
              print("\n" + "="*60)
              print("Finding Optimal Number of Clusters")
              print("="*60)
              optimization_results = find_optimal_k_kmeans(X_processed, k_range=k_range)
      
              # Use recommended K
              if optimization_results:
                  n_clusters = optimization_results['best_k']
      
          # Compare clustering algorithms
          comparison_results = compare_clustering_algorithms(X_processed, n_clusters=n_clusters)
      
          # Visualize results
          print("\n" + "="*60)
          print("Visualizing Results")
          print("="*60)
          visualize_clusters(X_processed, comparison_results, true_labels=true_labels)
      
          return {
              'X_processed': X_processed,
              'optimization': optimization_results,
              'comparison': comparison_results
          }
      
      
      # Example usage
      if __name__ == "__main__":
          from sklearn.datasets import load_iris, make_blobs
      
          print("="*60)
          print("Example 1: Iris Dataset")
          print("="*60)
      
          # Load Iris dataset
          iris = load_iris()
          X_iris = iris.data
          y_iris = iris.target
      
          results_iris = complete_clustering_analysis(
              X_iris,
              true_labels=y_iris,
              scale=True,
              find_k=True,
              k_range=range(2, 8),
              n_clusters=3
          )
      
          print("\n" + "="*60)
          print("Example 2: Synthetic Dataset with Noise")
          print("="*60)
      
          # Create synthetic dataset
          X_synth, y_synth = make_blobs(
              n_samples=500, n_features=2, centers=4,
              cluster_std=0.5, random_state=42
          )
      
          # Add noise points
          noise = np.random.randn(50, 2) * 3
          X_synth = np.vstack([X_synth, noise])
          y_synth_with_noise = np.concatenate([y_synth, np.full(50, -1)])
      
          results_synth = complete_clustering_analysis(
              X_synth,
              true_labels=y_synth_with_noise,
              scale=True,
              find_k=True,
              k_range=range(2, 8),
              n_clusters=4
          )
      
          print("\n" + "="*60)
          print("Analysis Complete!")
          print("="*60)
      
  • SKILL.md 11.7 KB
    ---
    name: alterlab-scikit-learn
    description: Classical machine learning in Python with scikit-learn — algorithms, preprocessing, pipelines, and best-practice reference documentation. Use when working with supervised learning (classification, regression), unsupervised learning (clustering, dimensionality reduction), model evaluation, hyperparameter tuning, feature preprocessing, or building ML pipelines. Part of the AlterLab Academic Skills suite.
    license: MIT
    allowed-tools: Read Write Edit Bash(python:*) Bash(uv:*)
    compatibility: No API key required. Runs locally via `uv run python`; requires scikit-learn >= 1.8 (current 1.9 as of 2026-09).
    metadata:
        skill-author: AlterLab
        version: "1.0.1"
        last_updated: "2026-09-23"
    ---
    
    # Scikit-learn
    
    ## Overview
    
    This skill provides comprehensive guidance for machine learning tasks using scikit-learn, the industry-standard Python library for classical machine learning. Use this skill for classification, regression, clustering, dimensionality reduction, preprocessing, model evaluation, and building production-ready ML pipelines.
    
    ## Installation
    
    ```bash
    # Install scikit-learn using uv
    uv pip install scikit-learn
    
    # Optional: Install visualization dependencies
    uv pip install matplotlib seaborn
    
    # Commonly used with
    uv pip install pandas numpy
    ```
    
    ## When to Use This Skill
    
    Use the scikit-learn skill when:
    
    - Building classification or regression models
    - Performing clustering or dimensionality reduction
    - Preprocessing and transforming data for machine learning
    - Evaluating model performance with cross-validation
    - Tuning hyperparameters with grid or random search
    - Creating ML pipelines for production workflows
    - Comparing different algorithms for a task
    - Working with both structured (tabular) and text data
    - Need interpretable, classical machine learning approaches
    
    ### Does NOT Trigger
    
    | Scenario | Use Instead |
    |----------|-------------|
    | Bayesian models with posteriors, credible intervals, or MCMC diagnostics | `alterlab-pymc` |
    | Censored time-to-event outcomes (Cox models, survival forests, C-index) | `alterlab-scikit-survival` |
    | UMAP embeddings with `n_neighbors` / `min_dist` tuning | `alterlab-umap` |
    | Explaining a fitted model's predictions with SHAP values and plots | `alterlab-shap` |
    | Coefficient tables, p-values, and residual diagnostics for inference | `alterlab-statsmodels` |
    
    ## Quick Start
    
    Minimal classification flow: stratified `train_test_split` → `StandardScaler` (fit on train only) → fit estimator → `classification_report`. For mixed numeric/categorical data, wrap preprocessing in a `ColumnTransformer` inside a `Pipeline` so it cross-validates without leakage.
    
    **See `references/worked_examples.md`** for full copy-paste classification and mixed-data pipeline examples.
    
    ## Core Capabilities
    
    ### 1. Supervised Learning
    
    Comprehensive algorithms for classification and regression tasks.
    
    **Key algorithms:**
    - **Linear models**: Logistic Regression, Linear Regression, Ridge, Lasso, ElasticNet
    - **Tree-based**: Decision Trees, Random Forest, Gradient Boosting
    - **Support Vector Machines**: SVC, SVR with various kernels
    - **Ensemble methods**: AdaBoost, Voting, Stacking
    - **Neural Networks**: MLPClassifier, MLPRegressor
    - **Others**: Naive Bayes, K-Nearest Neighbors
    
    **When to use:**
    - Classification: Predicting discrete categories (spam detection, image classification, fraud detection)
    - Regression: Predicting continuous values (price prediction, demand forecasting)
    
    **See:** `references/supervised_learning.md` for detailed algorithm documentation, parameters, and usage examples.
    
    ### 2. Unsupervised Learning
    
    Discover patterns in unlabeled data through clustering and dimensionality reduction.
    
    **Clustering algorithms:**
    - **Partition-based**: K-Means, MiniBatchKMeans
    - **Density-based**: DBSCAN, HDBSCAN, OPTICS
    - **Hierarchical**: AgglomerativeClustering
    - **Probabilistic**: Gaussian Mixture Models
    - **Others**: MeanShift, SpectralClustering, BIRCH
    
    **Dimensionality reduction:**
    - **Linear**: PCA, TruncatedSVD, NMF
    - **Manifold learning**: t-SNE, UMAP, Isomap, LLE
    - **Feature extraction**: FastICA, LatentDirichletAllocation
    
    **When to use:**
    - Customer segmentation, anomaly detection, data visualization
    - Reducing feature dimensions, exploratory data analysis
    - Topic modeling, image compression
    
    **See:** `references/unsupervised_learning.md` for detailed documentation.
    
    ### 3. Model Evaluation and Selection
    
    Tools for robust model evaluation, cross-validation, and hyperparameter tuning.
    
    **Cross-validation strategies:**
    - KFold, StratifiedKFold (classification)
    - TimeSeriesSplit (temporal data)
    - GroupKFold (grouped samples)
    
    **Hyperparameter tuning:**
    - GridSearchCV (exhaustive search)
    - RandomizedSearchCV (random sampling)
    - HalvingGridSearchCV (successive halving)
    
    **Metrics:**
    - **Classification**: accuracy, precision, recall, F1-score, ROC AUC, confusion matrix
    - **Regression**: MSE, RMSE, MAE, R², MAPE
    - **Clustering**: silhouette score, Calinski-Harabasz, Davies-Bouldin
    
    **When to use:**
    - Comparing model performance objectively
    - Finding optimal hyperparameters
    - Preventing overfitting through cross-validation
    - Understanding model behavior with learning curves
    
    **See:** `references/model_evaluation.md` for comprehensive metrics and tuning strategies.
    
    ### 4. Data Preprocessing
    
    Transform raw data into formats suitable for machine learning.
    
    **Scaling and normalization:**
    - StandardScaler (zero mean, unit variance)
    - MinMaxScaler (bounded range)
    - RobustScaler (robust to outliers)
    - Normalizer (sample-wise normalization)
    
    **Encoding categorical variables:**
    - OneHotEncoder (nominal categories)
    - OrdinalEncoder (ordered categories)
    - LabelEncoder (encodes the target labels `y`, not features)
    - TargetEncoder (encodes high-cardinality categorical features with cross-fitted target means)
    
    **Handling missing values:**
    - SimpleImputer (mean, median, most frequent)
    - KNNImputer (k-nearest neighbors)
    - IterativeImputer (multivariate imputation)
    
    **Feature engineering:**
    - PolynomialFeatures (interaction terms)
    - KBinsDiscretizer (binning)
    - Feature selection (RFE, SelectKBest, SelectFromModel)
    
    **When to use:**
    - Before training any algorithm that requires scaled features (SVM, KNN, Neural Networks)
    - Converting categorical variables to numeric format
    - Handling missing data systematically
    - Creating non-linear features for linear models
    
    **See:** `references/preprocessing.md` for detailed preprocessing techniques.
    
    ### 5. Pipelines and Composition
    
    Build reproducible, production-ready ML workflows.
    
    **Key components:**
    - **Pipeline**: Chain transformers and estimators sequentially
    - **ColumnTransformer**: Apply different preprocessing to different columns
    - **FeatureUnion**: Combine multiple transformers in parallel
    - **TransformedTargetRegressor**: Transform target variable
    
    **Benefits:**
    - Prevents data leakage in cross-validation
    - Simplifies code and improves maintainability
    - Enables joint hyperparameter tuning
    - Ensures consistency between training and prediction
    
    **When to use:**
    - Always use Pipelines for production workflows
    - When mixing numerical and categorical features (use ColumnTransformer)
    - When performing cross-validation with preprocessing steps
    - When hyperparameter tuning includes preprocessing parameters
    
    **See:** `references/pipelines_and_composition.md` for comprehensive pipeline patterns.
    
    ## Example Scripts
    
    Two runnable end-to-end scripts ship with this skill:
    
    ```bash
    python scripts/classification_pipeline.py   # mixed-data preprocessing, model comparison, GridSearchCV, evaluation, feature importance
    python scripts/clustering_analysis.py        # optimal-k search, K-Means/DBSCAN/Agglomerative/GMM comparison, PCA visualization
    ```
    
    **See `references/worked_examples.md`** for what each script demonstrates and standalone copy-paste versions.
    
    ## Reference Documentation
    
    This skill includes comprehensive reference files for deep dives into specific topics:
    
    ### Quick Reference
    **File:** `references/quick_reference.md`
    - Common import patterns and installation instructions
    - Quick workflow templates for common tasks
    - Algorithm selection cheat sheets
    - Common patterns and gotchas
    - Performance optimization tips
    
    ### Supervised Learning
    **File:** `references/supervised_learning.md`
    - Linear models (regression and classification)
    - Support Vector Machines
    - Decision Trees and ensemble methods
    - K-Nearest Neighbors, Naive Bayes, Neural Networks
    - Algorithm selection guide
    
    ### Unsupervised Learning
    **File:** `references/unsupervised_learning.md`
    - All clustering algorithms with parameters and use cases
    - Dimensionality reduction techniques
    - Outlier and novelty detection
    - Gaussian Mixture Models
    - Method selection guide
    
    ### Model Evaluation
    **File:** `references/model_evaluation.md`
    - Cross-validation strategies
    - Hyperparameter tuning methods
    - Classification, regression, and clustering metrics
    - Learning and validation curves
    - Best practices for model selection
    
    ### Preprocessing
    **File:** `references/preprocessing.md`
    - Feature scaling and normalization
    - Encoding categorical variables
    - Missing value imputation
    - Feature engineering techniques
    - Custom transformers
    
    ### Pipelines and Composition
    **File:** `references/pipelines_and_composition.md`
    - Pipeline construction and usage
    - ColumnTransformer for mixed data types
    - FeatureUnion for parallel transformations
    - Complete end-to-end examples
    - Best practices
    
    ### Worked Examples
    **File:** `references/worked_examples.md`
    - Quick-start classification and mixed-data pipeline snippets
    - Step-by-step classification model workflow
    - Step-by-step clustering analysis workflow
    - What each bundled example script demonstrates
    
    ### Best Practices & Troubleshooting
    **File:** `references/best_practices_and_troubleshooting.md`
    - Pipeline / leakage discipline, fit-on-train-only, stratified splitting
    - Random-state reproducibility, metric selection, when to scale features
    - Fixes for ConvergenceWarning, overfitting, and large-dataset memory errors
    
    ## Common Workflows
    
    - **Classification model:** load data → stratified `train_test_split` → `ColumnTransformer` preprocessing inside a `Pipeline` → `GridSearchCV` tuning → `classification_report` on the held-out test set.
    - **Clustering analysis:** `StandardScaler` → silhouette sweep over `k` to pick `optimal_k` → fit `KMeans` → `PCA(n_components=2)` projection for visualization.
    
    **See `references/worked_examples.md`** for the numbered, copy-paste version of each workflow.
    
    ## Version notes (scikit-learn 1.8–1.9)
    
    - `LogisticRegression(penalty=...)` is deprecated (removed in 1.10): use `l1_ratio` (0 = L2, 1 = L1, in between = elastic net) and `C=np.inf` for no penalty.
    - `SVC(probability=True)` is deprecated (removed in 1.11): wrap the model as `CalibratedClassifierCV(SVC(), ensemble=False)` when probabilities are needed.
    - `MDS(metric=True/False)` became `metric_mds=`; `HDBSCAN` warns unless `copy` is set explicitly.
    - `mean_squared_error(..., squared=False)` is gone; use `root_mean_squared_error`.
    
    ## Best Practices (essentials)
    
    - Always preprocess inside a `Pipeline` (prevents leakage); fit on train only, `transform` test.
    - Use `stratify=y` for classification splits; set `random_state` everywhere for reproducibility.
    - Scale features for SVM/KNN/NN/PCA/regularized-linear/K-Means; tree models and Naive Bayes do not need it.
    - Pick metrics for the problem: F1/accuracy on balanced data; precision/recall/ROC AUC/balanced accuracy on imbalanced data.
    
    **See `references/best_practices_and_troubleshooting.md`** for code examples and fixes for `ConvergenceWarning`, overfitting, and large-dataset memory errors.
    
    ## Additional Resources
    
    - Official Documentation: https://scikit-learn.org/stable/
    - User Guide: https://scikit-learn.org/stable/user_guide.html
    - API Reference: https://scikit-learn.org/stable/api/index.html
    - Examples Gallery: https://scikit-learn.org/stable/auto_examples/index.html
    
    

Comments (0)

Sign in to join the conversation.

No comments yet.

Reviews (0)

No reviews yet.

Related