Skip to main content

tidymodels-review-patterns

Review patterns for tidymodels workflows, including leakage, resampling, tuning, metrics, and reproducibility.

Zur Installation springen

Quellinformationen

Repository
choxos/BiostatAgent
Letzte Quellaktivität
27. Mai 2026 um 20:44
Erkannte Sprache von SKILL.md
Englisch
Sterne
11
Forks
1

Installationsoptionen

Standardmäßig ist der Prompt ausgewählt, der zuerst die Quelle prüft. Sie können zu einem direkten Befehl wechseln oder eine lokale Kopie herunterladen.

Quelldateien prüfen

Lesen Sie SKILL.md und alle von SkillsMP angezeigten Begleitdateien, bevor Sie sich für eine Installation entscheiden.

SKILL.md wird angezeigt

SKILL.md
Quellanweisungen · Schreibgeschützte Vorschau
name
tidymodels-review-patterns
description
Review patterns for tidymodels workflows, including leakage, resampling, tuning, metrics, and reproducibility.
# Tidymodels Code Review Patterns ## Overview Anti-pattern detection and best practices for tidymodels workflows based on "Tidy Modeling with R" (TMwR) principles. This skill enables systematic code review for data leakage, resampling violations, workflow issues, evaluation problems, and reproducibility concerns. ## Data Leakage Patterns (CRITICAL) ### DL-001: Recipe Fitted on Test Data **Severity**: CRITICAL **Anti-Pattern**: ```r # WRONG: Fitting recipe on test data rec <- recipe(outcome ~ ., data = test_data) |> prep() # WRONG: prep() using test data rec <- recipe(outcome ~ ., data = train_data) |> prep(training = test_data) ``` **Correct Pattern**: ```r # CORRECT: Recipe always prepped on training data only rec <- recipe(outcome ~ ., data = train_data) |> prep(training = train_data) # BEST: Use workflow (handles automatically) wf <- workflow() |> add_recipe(rec) |> add_model(model_spec) fit <- fit(wf, data = train_data) ``` **Detection**: Look for `prep()` calls with test data or recipes defined on test sets. --- ### DL-002: Preprocessing Before Split **Severity**: CRITICAL **Anti-Pattern**: ```r # WRONG: Normalizing before splitting df_normalized <- df |> mutate(across(where(is.numeric), scale)) split <- initial_split(df_normalized) # WRONG: Feature selection before split important_vars <- df |> select(where(~cor(.x, df$outcome) > 0.3)) split <- initial_split(important_vars) ``` **Correct Pattern**: ```r # CORRECT: Split first, then preprocess in recipe split <- initial_split(df, strata = outcome) train_data <- training(split) rec <- recipe(outcome ~ ., data = train_data) |> step_normalize(all_numeric_predictors()) |> step_corr(all_numeric_predictors(), threshold = 0.9) ``` **Detection**: Any transformations (scale, normalize, mutate) applied before `initial_split()`. --- ### DL-003: Target Encoding Without Cross-Validation **Severity**: CRITICAL **Anti-Pattern**: ```r # WRONG: Target encoding using full dataset statistics rec <- recipe(outcome ~ ., data = train_data) |> step_lencode_mixed(all_nominal_predictors(), outcome = vars(outcome)) # Then prep without proper CV prepped <- prep(rec) ``` **Correct Pattern**: ```r # CORRECT: Target encoding within workflow with resampling rec <- recipe(outcome ~ ., data = train_data) |> step_lencode_mixed(all_nominal_predictors(), outcome = vars(outcome)) wf <- workflow() |> add_recipe(rec) |> add_model(model_spec) # Encoding computed fresh for each fold cv_results <- fit_resamples(wf, resamples = vfold_cv(train_data)) ``` **Detection**: `step_lencode_*` or `step_embed` used outside workflow with resampling. --- ### DL-004: Feature Selection Using Test Data **Severity**: CRITICAL **Anti-Pattern**: ```r # WRONG: Selecting features based on test correlations test_cors <- cor(test_data[, -1], test_data$outcome) selected_vars <- names(test_cors[abs(test_cors) > 0.3]) # WRONG: Using test data for variable importance importance <- varImp(model, data = test_data) ``` **Correct Pattern**: ```r # CORRECT: Feature selection in recipe (computed on training only) rec <- recipe(outcome ~ ., data = train_data) |> step_select_vip(all_predictors(), outcome = "outcome", threshold = 0.8) # CORRECT: Or use recursive feature elimination with CV rfe_results <- rfe_fit( wf, resamples = vfold_cv(train_data), sizes = c(5, 10, 15, 20) ) ``` **Detection**: Variable selection operations referencing test data. --- ### DL-005: prep() Called Before initial_split() **Severity**: CRITICAL **Anti-Pattern**: ```r # WRONG: Prepping recipe on full data before split full_rec <- recipe(outcome ~ ., data = full_data) |> step_normalize(all_numeric_predictors()) |> prep() # Then splitting split <- initial_split(full_data) ``` **Correct Pattern**: ```r # CORRECT: Always split first split <- initial_split(full_data, strata = outcome) train_data <- training(split) rec <- recipe(outcome ~ ., data = train_data) |> step_normalize(all_numeric_predictors()) # Don't prep manually - let workflow handle it ``` **Detection**: Sequence analysis - `prep()` appearing before `initial_split()`. --- ## Resampling Violations (MAJOR/CRITICAL) ### RS-001: Missing Stratified Sampling **Severity**: MAJOR (CRITICAL for imbalanced data) **Anti-Pattern**: ```r # WRONG: No stratification for imbalanced outcome split <- initial_split(df) # outcome is 95%/5% imbalanced # WRONG: Unstratified CV folds <- vfold_cv(train_data, v = 10) ``` **Correct Pattern**: ```r # CORRECT: Stratify by outcome split <- initial_split(df, strata = outcome) # CORRECT: Stratified CV folds <- vfold_cv(train_data, v = 10, strata = outcome) # CORRECT: For continuous outcomes, stratify by bins split <- initial_split(df, strata = outcome, breaks = 4) ``` **Detection**: Missing `strata =` argument with classification outcomes or highly skewed continuous outcomes. --- ### RS-002: Evaluating Model on Training Data **Severity**: CRITICAL **Anti-Pattern**: ```r # WRONG: Predictions on training data for evaluation fit <- fit(wf, data = train_data) preds <- predict(fit, train_data) metrics <- yardstick::metrics(preds, truth = outcome, estimate = .pred) ``` **Correct Pattern**: ```r # CORRECT: Evaluate on held-out test data fit <- fit(wf, data = train_data) preds <- predict(fit, test_data) metrics <- yardstick::metrics( bind_cols(test_data, preds), truth = outcome, estimate = .pred ) # BEST: Use resampling for robust estimates cv_results <- fit_resamples(wf, resamples = folds) collect_metrics(cv_results) ``` **Detection**: `predict()` and metrics computed on same data used for `fit()`. --- ### RS-003: Tuning Without Nested Cross-Validation **Severity**: MAJOR **Anti-Pattern**: ```r # WRONG: Tune on same folds used for final evaluation folds <- vfold_cv(train_data) tune_results <- tune_grid(wf, resamples = folds) best_params <- select_best(tune_results) # Using same folds for "final" evaluation final_wf <- finalize_workflow(wf, best_params) fit_resamples(final_wf, resamples = folds) # Overly optimistic! ``` **Correct Pattern**: ```r # CORRECT: Nested CV or separate test set # Option 1: Hold out test set for final evaluation split <- initial_split(df, strata = outcome) train_data <- training(split) test_data <- testing(split) inner_folds <- vfold_cv(train_data, strata = outcome) tune_results <- tune_grid(wf, resamples = inner_folds) # Final evaluation on untouched test set final_fit <- fit(finalize_workflow(wf, select_best(tune_results)), train_data) predict(final_fit, test_data) # Option 2: Nested CV outer_folds <- nested_cv(train_data, outside = vfold_cv(v = 5), inside = vfold_cv(v = 5)) ``` **Detection**: Same resampling object used for both tuning and final evaluation. --- ### RS-004: Missing Random Seeds **Severity**: MAJOR **Anti-Pattern**: ```r # WRONG: No seed before random operations split <- initial_split(df) # Non-reproducible folds <- vfold_cv(train_data) # Different each run boot <- bootstraps(train_data) # Non-reproducible ``` **Correct Pattern**: ```r # CORRECT: Set seed before each random operation set.seed(123) split <- initial_split(df, strata = outcome) set.seed(456) folds <- vfold_cv(training(split), strata = outcome) # Or use tidymodels control options ctrl <- control_resamples(save_pred = TRUE) ``` **Detection**: Random operations (`initial_split`, `vfold_cv`, `bootstraps`, `mc_cv`) without preceding `set.seed()`. --- ### RS-005: Validation Set Reuse **Severity**: CRITICAL **Anti-Pattern**: ```r # WRONG: Using validation set multiple times for decisions val_split <- validation_split(train_data) # First use: model selection results1 <- fit_resamples(wf1, val_split) results2 <- fit_resamples(wf2, val_split) # Choose wf1 based on validation # Second use: hyperparameter tuning tune_results <- tune_grid(wf1, val_split) # Choose best params based on same validation set # Third use: final "evaluation" on same validation final_results <- fit_resamples(final_wf, val_split) # Overfit to validation! ``` **Correct Pattern**: ```r # CORRECT: Use CV for development, hold out final test split <- initial_split(df, strata = outcome) train_data <- training(split) test_data <- testing(split) # Touch only ONCE at the end # Use CV for all development decisions folds <- vfold_cv(train_data, strata = outcome) # Model selection via CV results1 <- fit_resamples(wf1, folds) results2 <- fit_resamples(wf2, folds) # Tuning via CV tune_results <- tune_grid(wf1, folds) # Final evaluation on test_data (only once!) final_fit <- last_fit(final_wf, split) ``` **Detection**: Same validation/test split used in multiple `fit_resamples()` or `tune_grid()` calls. --- ## Workflow Issues (MINOR/MAJOR) ### WF-001: Not Using Workflows **Severity**: MINOR to MAJOR **Anti-Pattern**: ```r # WRONG: Manual prep/bake/fit rec <- recipe(outcome ~ ., data = train_data) |> step_normalize(all_numeric_predictors()) |> prep() train_baked <- bake(rec, new_data = NULL) test_baked <- bake(rec, new_data = test_data) model <- linear_reg() |> set_engine("lm") fit <- fit(model, outcome ~ ., data = train_baked) preds <- predict(fit, test_baked) ``` **Correct Pattern**: ```r # CORRECT: Use workflow wf <- workflow() |> add_recipe(recipe(outcome ~ ., data = train_data) |> step_normalize(all_numeric_predictors())) |> add_model(linear_reg() |> set_engine("lm")) fit <- fit(wf, data = train_data) preds <- predict(fit, new_data = test_data) ``` **Benefits of workflows**: - Automatic handling of preprocessing on new data - Proper integration with tuning and resampling - Cleaner code organization - Reduced risk of data leakage --- ### WF-002: Inconsistent Preprocessing Train/Test **Severity**: MAJOR **Anti-Pattern**: ```r # WRONG: Different preprocessing for train vs test train_processed <- train_data |> mutate(across(where(is.numeric), ~(.x - mean(.x)) / sd(.x))) test_processed <- test_data |>
Auf GitHub ansehen
Diese SKILL.md ist sehr gross, daher zeigt SkillsMP hier nur den ersten Abschnitt. Auf GitHub ansehen