root@kaus.com:~/projects$ cat drug-transporter-ml.md
Drug Transporter ML
archivedUC San Diego · 2018 – 2020 · San Diego, CA
Kbit · page guide
1 / 4
Use the section map on long studies.
Jump between methodology, results, experiments, limitations, and related writing without losing your place.
2 / 4
The narrative carries the claim.
Read each section as problem, method, evidence, and boundary. Negative results remain part of the story.
3 / 4
Inspect figures alongside the narrative.
Read figures in place, scroll wide charts or tables horizontally, and follow any source links for the underlying evidence.
4 / 4
Keep exploring the corpus.
The code behind a cited biomedical publication (Journal of Biological Chemistry, 2020).
An archived Python research implementation for OAT1/OAT3 substrate classification, combining feature-subset search and NEAT. A reproduction audit separates the published study, historical scratch runs, and what the consolidated code actually does.
Technologies
- Python
- scikit-learn
- NEAT
Skills
- Cheminformatics
- Feature engineering
- Genetic algorithms
Links
- 3 bundled metabolite datasets, 32 molecular descriptor columns
- 2020 Journal of Biological Chemistry publication
- 10 passing software checks on repair a88149c, with synthetic GA execution
Overview
I built Python machine-learning tools for a question posed by transporter researchers: which molecular properties help distinguish compounds handled by OAT1 and OAT3? The work contributed to the 2020 Journal of Biological Chemistry paper, "Unique metabolite preferences of the drug transporters OAT1 and OAT3 analyzed by machine learning." My contribution was the software and modeling implementation, developed alongside researchers who supplied the biological context.
The repository now serves a second purpose: it shows what can go wrong when a research implementation becomes an archive. A September 2026 audit found that successful classifier calls had been mistaken for verification of the complete feature-search program. The program could label a result with two feature names while evaluating every column. That changed this case study: the useful story includes the research design, the defect, and the evidence needed to repair it.
The research question
OAT1 and OAT3 are kidney transporters with overlapping roles, yet the paper investigates molecular differences among their substrates. Its reported finding links OAT3 preference with more structurally complex compounds, including more rings and chiral centers. The paper is the source for that scientific result. The maintenance checks described here concern software behavior and do not repeat the study.
For the implementation, each molecule becomes a row of numeric descriptors rather than an image or a sequence. A model predicts a transporter class from those descriptors. The engineering question is whether searching feature subsets or evolving transformations can produce a useful, inspectable classifier. A high score alone would not explain which inputs it used, whether selection overfit the evaluation data, or whether another researcher could run the same program.
Data and architecture
Three datasets, each a CSV of molecules with 32 shared descriptor columns and a transporter-class label: OAT1OAT3Small.csv (51 metabolites, 3-class: 17 Both, 12 OAT1-only, 22 OAT3-only), OAT1OAT3Big.csv (73 metabolites, same 3-class scheme: 17 Both, 21 OAT1, 35 OAT3), and OAT1OAT3OATP.csv (137 metabolites combining kidney and liver transporters, 6-class: 73 kidney rows plus 64 liver rows split 29 Both OATP, 20 OATP1B1, 15 OATP1B3).
The shared loader produces a matrix, labels, and column names. Three modules consume that interface: a feature-subset search using Random Forest and Decision Tree classifiers, a NEAT classifier, and a NEAT feature transformer feeding a Random Forest. Utilities supply the classification-accuracy function, population setup, checkpointing, and interactive prompts. The intended architecture is compact enough to inspect without a service, database, or deployed API.
The legacy directory retains earlier implementations, including a five-classifier search, dataset-specific variants, parallel search, and an ID3 decision tree. Keeping those versions preserves the development history. It does not establish which exact source, environment, and outputs produced every published number. A consolidated implementation should not silently stand in for a pinned historical experiment.
Intended architecture · drug-transporter-ml · source 4cd3f66. The archived subset-search implementation does not fully follow this design; see the reproduction audit below.
Three search methods, three evaluation questions
The brute-force method is intended to enumerate every size-k subset, fit two classifiers on that subset, and save their cross-validation scores next to its column names. Exhaustive enumeration removes one search heuristic, but it does not remove statistical uncertainty. Choosing the best subset on the same folds used to score it can overfit the selection criterion. An independent performance estimate needs an outer evaluation procedure or untouched data.
The module called feature-selection GA evolves a neural network that consumes the raw descriptors and predicts a class. Its fitness is training-set accuracy, so it is searching a classifier rather than reporting held-out performance. The feature-engineering GA instead evolves six transformed features for a downstream Random Forest. Its fitness uses leave-one-out or ten-fold cross-validation, depending on the dataset. Evolution still repeatedly selects against that score. Neither a rising fitness curve nor a winning genome alone establishes generalization.
The utility named auc computes the fraction of correct class predictions. It is classification accuracy, not area under a receiver-operating-characteristic curve. Preserving that distinction matters more than the function's historical name: otherwise readers can mistake a training objective for a different statistical measurement.
What the reproduction audit found
The July audit exercised data loading and classifier helpers and reported scratch-run scores. It did not establish that the complete subset-search loop was correct. Reviewing the consolidated source at commit 4cd3f66 in September exposed the missing connection: feature_indices determined the CSV labels, but both eval_classifier calls received the full data matrix. A plausible accuracy and a plausible pair of feature names could therefore appear together without describing the same experiment.
A second defect affected completeness. Results were buffered in batches of ten, but the program never wrote the final partial batch. With 32 single-feature combinations it would omit two rows. With 496 two-feature combinations it would omit six. Checking that a CSV existed, or inspecting only its first rows, would miss that failure.
Startup also depended on the operator's working directory. The documented package command conflicted with absolute imports, datasets and configs used relative paths, and output directories were assumed to exist. The four NEAT configs omitted a key required by the previously tested neat-python 2.0.0 environment. These are separate failure modes: a config-only patch cannot verify the search or make the advertised workflow reproducible.
A successful model call did not verify the search
These checks follow the experiment from its selected inputs to its saved output. None measures predictive accuracy.
| Required behavior | Before · 4cd3f66 | Verified repair · a88149c |
|---|---|---|
| Feature names match the evaluated columns | Each row names a subset, but both classifiers receive all columns. | Pass: both classifiers receive exactly the named two columns for each of three synthetic subsets. |
| Every evaluated subset is saved | Only complete batches of ten rows are written; the remainder is discarded. | Pass: all three rows survive a partial batch; all twelve survive a full batch plus remainder, in order. |
| A clean checkout can start and write output | Package imports, working-directory paths, missing output folders and NEAT configuration interrupt the documented workflow. | Pass: CLI startup, three datasets, four configs, checkpoint round-trip, and both GA entrypoints on tiny synthetic inputs. Graphics were intercepted in these checks. |
Ten checks passed on Windows with Python 3.12.14. The repair is published for review and has not been merged into the default branch. The synthetic GA checks use two genomes and one generation; they make no claim about model quality.
A later local repair fixes optional network pruning. Native SVG checks preserve required outputs and their input paths while removing disconnected branches. These use artificial graphs, with no trained model. Interactive desktop plotting is still unverified, and this additional repair is not in the public review branch.
The repair and its verification
Repair a88149c sends the selected columns to the classifiers, flushes the CSV remainder, makes package imports and resource paths consistent, creates output directories, and updates the NEAT configuration contract. Its first three regression tests use a small matrix with distinctive column values and inspect the actual subset-search loop. They fail against the original implementation and pass after the repair: the recorded inputs match the names, and both a three-row partial batch and a twelve-row batch-plus-remainder are fully saved.
The full suite contains ten passing checks. It also starts the documented command, loads all three datasets, parses all four configs, and saves and restores a checkpoint in an initially absent output directory. Both real GA entrypoints complete one generation using two genomes and six artificial rows. That fixture uses seed 1729, two-tree Random Forests, and intercepted plot calls. It tests execution through the fitness functions without fitting models to the biomedical datasets or claiming research performance.
The checks pass on Windows with Python 3.12.14 and a recorded dependency lock, including a clean source snapshot using the same isolated environment. Those checks intercepted graphics. A later local repair, 6f1dfac, fixes optional network pruning and passes native SVG rendering checks on artificial graphs. Interactive desktop plotting remains unverified. The earlier repair is available on a review branch, not the default branch; the visualization repair has not been pushed. A full paper reproduction would additionally need the original experiment protocol, seeds, selection procedure, environment, and retained outputs. It remains a separate undertaking.
What changed in the presentation
This page previously called the brute-force path correct end to end. That statement is withdrawn. Historical helper-level accuracy ranges cannot prove that the orchestrator supplied the right columns or saved every result. The same boundary applies to scratch-run charts: without a retained runner and raw measurements, they are insufficient evidence for a new quantitative comparison.
The architecture and differing evaluation objectives remain useful to explain. The published paper remains the source for its own findings. The maintenance audit makes the archive more inspectable by identifying the failing contracts and the checks needed to repair them, without relabeling a software fix as a scientific replication.
Lessons and limits
The durable lesson is to verify the relationship between inputs, labels, and saved outputs, not just whether a model returns a number. In a search pipeline, the feature names are part of the experiment identity. If they do not match the matrix passed to the estimator, a clean-looking table can describe experiments that never happened. Completeness is another contract: the number of retained rows should agree with the declared search space.
This remains an archived research project rather than a deployed predictor. No new full feature sweep, evolutionary study, or independent biomedical validation was performed for this portfolio audit. Small-sample uncertainty and repeated selection against cross-validation remain relevant even after implementation defects are fixed. Repairing the code makes the next experiment possible to inspect. It does not predetermine its result.
notes
- The default-branch snapshot at 4cd3f66 has correctness and startup defects. Repair a88149c passes ten bounded checks and is published for review, but is not merged. Use the linked repair commit to reproduce the new checks.
- The published paper, archived code, and later maintenance checks are separate evidence. This audit does not reproduce the paper's experiments or establish a new accuracy result.