Repository navigation
Conversation
Test CoverageTotal: 70.48% (19280 / 27357 lines)
|
This was referenced Oct 20, 2026
solarsys
force-pushed
the
feat/autoimprove-features
branch
2 times, most recently
from
October 23, 2026 09:18
1ac30a6 to
abcf367
Compare
…ion, report) A run now ends with a report that explains the selected model and how the search got there, built from the decision log alone. - Decision log: every trial records the proposer's rationale and expectation (written before it runs), the trial it was changed from and what changed. LLM proposers are asked for both. - Selection: among the trials that beat the baseline consistently across folds, the most interpretable one within one paired SE of the best (the one-SE rule, select_simplest). Models sit on an interpretability ladder (SearchSpace.rung): logistic regression, depth-1 XGBoost (additive, now in the space), shallow trees and MLPs, then deeper trees and sequence models. one_se=False keeps the highest-lower-bound rule. - Plain words: every model has a description and every setting a meaning (Param.meaning, SearchSpace.explain). - AutoImprover.attribute(): reverts each changed setting of the selected trial one at a time and scores it on the same folds. - evaluate_on_test() also scores the highest-scoring candidate when a simpler one was selected, and saves test.json. - AutoImprover.report() / load_run(): HTML, Markdown and JSON with the summary, task, model and why (candidates, ladder, price of interpretability, attribution), test comparison and reasoning trace (timeline, every trial with hypothesis, change, result and verdict, single-setting comparisons, lessons). Statements are labelled measured, tested or hypothesis; numbers in lessons that match nothing in the log are flagged (unverified_numbers). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015ntMLEmFsQEQJKTmPGGw4T
A run's report now explains how the selected model decides and how it would perform in clinical use, and lists what a clinician must decide. - pyhealth.tasks.TaskCard and the optional BaseTask.task_card() hook: the task's design choices with their rationale, and a feature dictionary (meaning, clinical group, expected direction of effect). - pyhealth.metrics.clinical: alert_rate_metrics (sensitivity, PPV and number needed to evaluate when the top 5/10/20% of risk is flagged), net_benefit (decision curve), calibration_bins, subgroup_metrics and clinical_summary; counts below 11 patients are suppressed. - AutoImprover(task_card=...); explain(): exact TreeSHAP for trees, integrated gradients for torch models (exact for logistic regression); importance by clinical group, top features with effect shapes in bins of at least 11 patients, learned vs expected direction, and the top-feature overlap of the fold models. - evaluate_on_test(subgroups=...) adds the clinical summary per config. - flags() and approve(): a missing card, undescribed top features, effects opposite to the expected direction, poor calibration and subgroup gaps; decisions are kept in review.json. - The report gains How it decides, Performance in clinical terms, Clinician review and a TRIPOD+AI reporting checklist; load_run reads the new files. The eICU example has a task card and age/sex subgroups. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015ntMLEmFsQEQJKTmPGGw4T
…d test) New inputs are written as JSON specs over PyHealth's event log, never as code. FeatureSpace validates a spec against a fixed set of operators (count, exists, days_since, stat, n_distinct, trend, blocks_with, ratio, diff, band, ge, any, cross, column), compiles it at each sample's prediction time t with windows that end strictly before t, and writes its column name and plain-language definition from the spec itself. Every spec carries its clinical rationale and expected direction; invalid specs are refused with a reason. - The future-blind test computes each spec on the full record and on the record as known at t (later rows removed, values known only later blanked via known_at, derived events rebuilt); any difference rejects it. - FeatureSpace.check reports definition, coverage and the test result; augment adds an "engineered" tensor field (EngineeredDataset) whose imputation and scaling run_config_cv refits on each fold's training part (fold_parts). - Optional BaseTask hooks: time_key, feature_vocabulary() and derived_events(patient, t) with derived_event_types. Class-level defaults, so set_task cache keys are unchanged. - examples/autoimprove_features_mimic3.py checks one hand-written feature on synthetic MIMIC-III and measures its paired CV gain. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015ntMLEmFsQEQJKTmPGGw4T
solarsys
force-pushed
the
feat/autoimprove-features
branch
from
October 25, 2026 15:20
abcf367 to
e025a02
Compare
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #1318, then #1317 and #1316. Review the last commit,
autoimprove: features as data.Why
Model and setting search reaches a ceiling quickly; better inputs are where the remaining gains are. Changing inputs must not mean running code that an LLM (or anyone) wrote, on a machine that holds patient data. A feature also has to be reviewable: a clinician must be able to read exactly what was computed, and know that it cannot see the future.
What changes
FeatureSpec/FeatureSpace. A feature is JSON built from a fixed set of operators over PyHealth's event log (Patient.get_events), evaluated at each sample's prediction time t:count,exists,days_since,stat(min, max, mean, last or slope of a value),n_distinct,trendandblocks_with;ratio,diff,band,ge,anyandcross;column, for an existing task feature.Selectors name an event type, an optional vocabulary group (e.g. SABA) and optional
wherefilters. Filter values must occur for at least 11 patients.Definitions are generated from the spec, deterministically. For example,
ge(3, count(365 d, SABA orders))becomes "1 if there were 3 or more SABA orders in the 365 days before the landmark, else 0". So the sentence a clinician reviews is exactly what was computed. Every spec must also carry its clinicalrationaleand expecteddirection.Refusals carry a reason, the same way invalid configs already do:
The future-blind test. Each spec is computed twice: on the full record, and on the record as known at t. Rows dated at or after t are removed, and values known only later (
known_at, e.g. a stay's length known at discharge) are blanked. Derived events are rebuilt from the truncated record. Any difference rejects the spec.check()reports each spec's definition, coverage and future-blind result.augment()adds anengineeredtensor field (EngineeredDataset).run_config_cvnow imputes and scales that field on each fold's training part (fold_parts), so a held-out fold never informs its own medians and scales. The other fields keep the processorsset_taskfitted, as before.Optional
BaseTaskhooks:time_key,feature_vocabulary(), andderived_events(patient, t)withderived_event_types. They are class-level defaults, soset_taskcache keys (built fromvars(task)) are unchanged, and tasks without them work as before.Speed: each
computecall fetches the needed event types for all its patients in one query.Example and checks
examples/autoimprove_features_mimic3.pychecks one hand-written feature on the full synthetic MIMIC-III, with no search and no LLM. The feature is hospital admissions in the 365 days before discharge, used to predict next-visit mortality:(It runs in about 20 seconds. Coverage is below 100% because a third of the synthetic stays end before they begin.)
Tests
tests/core/test_autoimprove_features.pyhas 10 tests:The earlier autoimprove and metrics tests still pass (48 in total), as do the doctests, ruff and
tools/check_pr_rules.py.🤖 Generated with Claude Code
https://claude.ai/code/session_015ntMLEmFsQEQJKTmPGGw4T