Latest Post

Reinforcement Learning for Credit Scoring: Applications in Fintech

Here’s something that’ll blow your mind: the way fintech companies decide whether to lend you money is getting a serious upgrade. And I’m not talking about minor tweaks to old formulas — I’m talking about reinforcement learning algorithms that literally learn from every lending decision they make.

TPOT AutoML Tutorial: Genetic Programming for Pipeline Optimization

You’ve spent three days manually testing different preprocessing steps, trying 15 different algorithms, and tuning countless hyperparameters. Your best model hits 82% accuracy, and you’re wondering if you’re missing something obvious. What if there’s a better pipeline combination you never even thought to try?

I used to think AutoML was lazy data science — just letting algorithms do your job for you. Then I actually used TPOT on a project where I was stuck, and it found a pipeline I never would’ve considered that beat my best manual attempt by 6%. That’s when it clicked: AutoML isn’t about replacing your skills, it’s about exploring the massive search space of possible pipelines way faster than you ever could manually.

Let me show you how TPOT uses genetic programming to evolve machine learning pipelines, because this thing is genuinely clever.

TPOT AutoML Tutorial

What Makes TPOT Different from Other AutoML

AutoML tools are everywhere now — AutoGluon, H2O AutoML, Auto-sklearn, and more. They’re all trying to automate the tedious parts of machine learning. But TPOT (Tree-based Pipeline Optimization Tool) takes a unique approach: genetic programming.

Instead of trying every combination systematically or using Bayesian optimization, TPOT treats pipelines like organisms. It creates a population of random pipelines, evaluates their fitness, lets the best ones “reproduce” with random mutations, and repeats this evolutionary process for multiple generations.

Why this matters:

  • Explores unconventional pipeline combinations you’d never try
  • Can discover complex preprocessing chains automatically
  • Doesn’t get stuck in local optima as easily
  • Actually fun to watch evolve (yeah, I’m a nerd)

I’ve used both grid search and TPOT on the same problem. Grid search found a solid solution in the space I defined. TPOT found a better solution in a space I didn’t even know existed. That’s the power of evolutionary search.

Installing TPOT and Getting Started

Let’s get practical. TPOT is built on scikit-learn, so if you know sklearn, TPOT will feel familiar.

python

pip install tpot

That’s the basic install. For the full experience with XGBoost and other extras:

python

pip install tpot[all]

Quick compatibility check:

  • Python 3.7+
  • scikit-learn 1.0+
  • NumPy, pandas, and the usual suspects
  • Works on CPU (GPU support is limited)

The installation is straightforward, but TPOT can be heavy during evolution. Make sure you’ve got decent CPU resources or plan to wait a while.

Your First TPOT Pipeline: The Basics

Let’s build a simple classifier to understand the workflow. I’ll use the classic iris dataset because it’s small and fast — perfect for learning.

python

from tpot import TPOTClassifier
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
# Load data
iris = load_iris()
X_train, X_test, y_train, y_test = train_test_split(
iris.data, iris.target, test_size=0.2, random_state=42
)
# Initialize TPOT
tpot = TPOTClassifier(
generations=5,
population_size=20,
verbosity=2,
random_state=42
)
# Let TPOT find the best pipeline
tpot.fit(X_train, y_train)
# Evaluate on test set
print(f"Test Accuracy: {tpot.score(X_test, y_test):.3f}")
# Export the best pipeline
tpot.export('best_pipeline.py')

That’s it. You’ve just told TPOT to evolve 5 generations of 20 pipelines each, automatically finding the best combination of preprocessing and modeling steps.


Loving the article? ☕
 If you’d like to help me keep writing stories like this, consider supporting me on Buy Me a Coffee: https://buymeacoffee.com/samaustin. Even a small contribution means a lot!


What Just Happened?

TPOT created an initial population of 20 random pipelines. Each pipeline might include different preprocessors (scalers, feature selection, PCA), different models (random forests, logistic regression, gradient boosting), and different hyperparameters.

It evaluated each pipeline using cross-validation, ranked them by performance, and let the best ones “reproduce” with mutations (changing hyperparameters, swapping models, adding preprocessing steps). After 5 generations of this evolutionary process, it gave you the best pipeline it found.

The export() function saves the optimized pipeline as actual Python code you can inspect, modify, and use in production. No black box—you see exactly what TPOT built.

Understanding the Key Parameters

TPOT has a lot of knobs to turn. Let me explain the ones that actually matter.

Generations and Population Size

Generations controls how many iterations of evolution run. More generations = more optimization time but potentially better results.

Population size determines how many pipelines exist in each generation. Larger populations explore more diversity but take longer to evaluate.

python

tpot = TPOTClassifier(
generations=10, # More generations = better optimization
population_size=50, # Larger population = more diversity
random_state=42
)

My typical settings:

  • Quick test: 5 generations, 20 population
  • Serious optimization: 25–50 generations, 50–100 population
  • Production search: 100 generations, 100 population (run overnight)

The computational cost is generations × population_size × CV folds × time per pipeline. It adds up fast.

Verbosity: See What’s Happening

Set verbosity=2 to watch the evolution happen in real-time. It's actually fascinating:

python

tpot = TPOTClassifier(
generations=5,
population_size=20,
verbosity=2, # Shows generation progress and best scores
random_state=42
)

You’ll see output like:

Generation 1 - Current best internal CV score: 0.9667
Generation 2 - Current best internal CV score: 0.9733
Generation 3 - Current best internal CV score: 0.9800

Watching scores improve over generations never gets old. It’s like watching your AI actually learn :)

Scoring Metrics: What to Optimize

TPOT defaults to accuracy for classification and MSE for regression. But you should specify what actually matters for your problem.

python

tpot = TPOTClassifier(
generations=10,
population_size=50,
scoring='roc_auc', # Optimize for AUC instead of accuracy
cv=5,
random_state=42
)

Common scoring options:

  • Classification: 'accuracy', 'roc_auc', 'f1', 'f1_weighted', 'precision', 'recall'
  • Regression: 'neg_mean_squared_error', 'neg_mean_absolute_error', 'r2'

For imbalanced classification, I always use 'f1' or 'roc_auc' instead of accuracy. Optimizing for the right metric matters more than you think.

Configuration: Controlling the Search Space

This is where things get interesting. You can tell TPOT which algorithms to consider.

python

tpot = TPOTClassifier(
generations=10,
population_size=50,
config_dict='TPOT light', # Faster, simpler algorithms
random_state=42
)

Built-in configurations:

  • 'TPOT light': Fast algorithms, good for quick searches
  • 'TPOT MDR': Focus on feature selection and construction
  • 'TPOT sparse': Optimized for sparse data
  • None (default): All available algorithms

For most projects, I start with 'TPOT light' for fast iteration, then run the full search overnight when I'm serious about optimization.

Regression with TPOT: It’s Not Just Classification

TPOT handles regression just as well as classification. The API is nearly identical.

python

from tpot import TPOTRegressor
from sklearn.datasets import load_diabetes
from sklearn.model_selection import train_test_split
# Load regression data
diabetes = load_diabetes()
X_train, X_test, y_train, y_test = train_test_split(
diabetes.data, diabetes.target, test_size=0.2, random_state=42
)
# Initialize TPOT regressor
tpot = TPOTRegressor(
generations=10,
population_size=50,
scoring='neg_mean_absolute_error',
cv=5,
verbosity=2,
random_state=42
)
# Optimize
tpot.fit(X_train, y_train)
# Evaluate
print(f"Test Score: {tpot.score(X_test, y_test):.3f}")
# Export pipeline
tpot.export('best_regression_pipeline.py')

Same evolutionary process, different algorithms in the search space. TPOT considers linear models, tree-based regressors, neural networks, and ensemble methods automatically.

Advanced Features: Custom Pipelines and Operators

Once you’re comfortable with basics, TPOT lets you customize the search space extensively.

Custom Configuration Dictionary

You can specify exactly which algorithms and hyperparameter ranges to explore:

python

custom_config = {
'sklearn.ensemble.RandomForestClassifier': {
'n_estimators': [50, 100, 200],
'max_depth': range(1, 11),
'min_samples_split': range(2, 21),
'min_samples_leaf': range(1, 11)
},
'sklearn.linear_model.LogisticRegression': {
'C': [0.001, 0.01, 0.1, 1.0, 10.0],
'penalty': ['l1', 'l2'],
'solver': ['liblinear']
}
}
tpot = TPOTClassifier(
generations=20,
population_size=50,
config_dict=custom_config,
random_state=42
)

This limits TPOT to only exploring Random Forests and Logistic Regression with specified hyperparameter ranges. Faster searches when you know what class of algorithms works well.

Template Pipelines: Structure the Search

Templates force TPOT to follow specific pipeline structures:

python

tpot = TPOTClassifier(
generations=10,
population_size=50,
template='Selector-Transformer-Classifier',
random_state=42
)

This ensures every pipeline has feature selection → transformation → classification in that order. Useful when you know certain preprocessing is required.

Common templates:

  • 'Classifier': Just a classifier, no preprocessing
  • 'Transformer-Classifier': One preprocessing step + classifier
  • 'Selector-Transformer-Classifier': Feature selection + transform + classifier

I use templates when I have domain knowledge about what preprocessing is necessary, but I’m unsure about the specific methods.

Warm Starting: Resume Optimization

Ever wondered if running TPOT longer would find something better? Warm starting lets you resume from where you left off.

python

# First run
tpot = TPOTClassifier(
generations=10,
population_size=50,
verbosity=2,
random_state=42,
warm_start=True
)
tpot.fit(X_train, y_train)
# Continue evolving from generation 10
tpot.fit(X_train, y_train) # Runs another 10 generations

Each fit() call with warm_start=True continues from the current best population. Useful for incremental optimization when you're not sure how long to run.

Parallel Processing: Speed Things Up

TPOT supports parallel evaluation through n_jobs:

python

tpot = TPOTClassifier(
generations=20,
population_size=100,
n_jobs=-1, # Use all CPU cores
verbosity=2,
random_state=42
)

Performance impact:

  • Single core: 100 pipelines might take 2 hours
  • 8 cores: Same 100 pipelines take 20–30 minutes

The parallelization is at the pipeline evaluation level. Each CPU core evaluates different pipelines simultaneously. Major speedup with minimal code changes.

Exported Pipelines: Understanding the Output

When TPOT exports your best pipeline, you get actual Python code. Let me show you what it looks like:

python

# Sample exported pipeline
import numpy as np
import pandas as pd
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import make_pipeline
# NOTE: Make sure that the outcome column is labeled 'target' in the data file
tpot_data = pd.read_csv('PATH/TO/DATA/FILE', sep='COLUMN_SEPARATOR', dtype=np.float64)
features = tpot_data.drop('target', axis=1)
training_features, testing_features, training_target, testing_target = \
train_test_split(features, tpot_data['target'], random_state=42)
# Average CV score on the training set was: 0.9733333333333334
exported_pipeline = make_pipeline(
StandardScaler(),
RandomForestClassifier(bootstrap=True, max_depth=10, max_features=0.7,
min_samples_leaf=1, min_samples_split=2, n_estimators=100)
)
exported_pipeline.fit(training_features, training_target)
results = exported_pipeline.predict(testing_features)

This is production-ready code. You can modify it, integrate it into your system, or just understand exactly what TPOT built. No black box magic — just sklearn pipelines.

Real-World Example: Complete Workflow

Let me show you a realistic example with a proper dataset and workflow.

python

import pandas as pd
from tpot import TPOTClassifier
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report, confusion_matrix
# Load your data
df = pd.read_csv('your_data.csv')
X = df.drop('target', axis=1)
y = df['target']
# Split data
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, stratify=y, random_state=42
)
# Initialize TPOT with production-ready settings
tpot = TPOTClassifier(
generations=50,
population_size=100,
cv=5,
scoring='f1_weighted',
n_jobs=-1,
verbosity=2,
random_state=42,
early_stop=10 # Stop if no improvement for 10 generations
)
# Run optimization (this will take a while)
print("Starting TPOT optimization...")
tpot.fit(X_train, y_train)
# Evaluate on test set
y_pred = tpot.predict(X_test)
print("\nTest Set Results:")
print(f"Accuracy: {tpot.score(X_test, y_test):.3f}")
print("\nClassification Report:")
print(classification_report(y_test, y_pred))
print("\nConfusion Matrix:")
print(confusion_matrix(y_test, y_pred))
# Export the best pipeline
tpot.export('optimized_pipeline.py')
print("\nPipeline exported to optimized_pipeline.py")
# Get the fitted pipeline object
best_pipeline = tpot.fitted_pipeline_
print(f"\nBest Pipeline: {best_pipeline}")

This workflow handles everything: proper train/test splitting, comprehensive evaluation, and pipeline export. Run it overnight on your dataset and wake up to an optimized solution.

Common Mistakes and Gotchas

Let me save you from my painful lessons.

Mistake 1: Not Setting Random State

python

# BAD - results not reproducible
tpot = TPOTClassifier(generations=10, population_size=50)
# GOOD - reproducible results
tpot = TPOTClassifier(generations=10, population_size=50, random_state=42)

Without random_state, you get different pipelines every run. Makes debugging and comparison impossible.

Mistake 2: Using All Your Data in TPOT

python

# WRONG - no holdout test set
tpot.fit(X, y) # Using all data
tpot.score(X, y) # Scoring on training data
# RIGHT - proper train/test split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)
tpot.fit(X_train, y_train)
tpot.score(X_test, y_test) # Unbiased evaluation

TPOT uses cross-validation internally during optimization, but you still need a holdout test set for final evaluation. Otherwise you’re measuring how well TPOT overfit your data.

Mistake 3: Running Too Few Generations

python

# Probably insufficient
tpot = TPOTClassifier(generations=3, population_size=10)
# More reasonable for real optimization
tpot = TPOTClassifier(generations=25, population_size=50)

I see people run 3 generations with 10 pipelines and complain TPOT didn’t find anything good. That’s 30 total pipeline evaluations — barely scratching the surface. Give evolution time to work.

Mistake 4: Ignoring Memory and Time Constraints

TPOT can eat RAM and CPU time aggressively:

python

# Set reasonable limits
tpot = TPOTClassifier(
generations=20,
population_size=50,
max_time_mins=120, # Stop after 2 hours
max_eval_time_mins=5, # Skip pipelines taking over 5 minutes
n_jobs=-1,
random_state=42
)

Use max_time_mins and max_eval_time_mins to prevent runaway optimization that consumes all resources.

TPOT vs Manual Pipeline Building

Let’s be honest about when TPOT makes sense and when it doesn’t.

When TPOT Wins

Exploring unknown territory: New dataset, no idea what works? TPOT explores widely and might find surprising solutions.

Time-constrained optimization: Set it running overnight and wake up to multiple strong candidates automatically.

Baseline establishment: Quick way to establish what’s possible before diving into manual tuning.

Complex preprocessing chains: TPOT might discover preprocessing sequences you’d never consider.

When Manual Building Wins

Domain expertise matters: If you know Random Forests work well for your problem, just use Random Forests with proper tuning.

Interpretability required: TPOT might build complex ensembles when you need simple, explainable models.

Resource constraints: TPOT is computationally expensive. Sometimes you can’t afford the search.

Production constraints: Complex TPOT pipelines might be hard to deploy or maintain.

IMO, the best approach is hybrid. Use TPOT to explore and establish baselines. Then take insights from the exported pipeline and refine manually for production.

Comparing TPOT to Other AutoML Tools

Quick comparison to help you choose:

TPOT strengths:

  • Open source and free
  • Genetic programming finds creative solutions
  • Exports actual sklearn code
  • Full control over search space

Auto-sklearn strengths:

  • Often finds better solutions faster
  • Bayesian optimization is more efficient than genetic programming
  • Meta-learning from past datasets
  • Better for tabular data specifically

AutoGluon strengths:

  • Easiest to use (literally 3 lines of code)
  • Excellent ensemble methods
  • Great for quick prototyping
  • Strong performance out-of-box

I use TPOT when I want to understand the evolved pipeline and potentially modify it. For pure prediction accuracy competitions, Auto-sklearn often edges it out. For speed, AutoGluon wins.

The Evolutionary Perspective

Here’s what makes TPOT genuinely interesting from a CS perspective: it’s applying biological evolution principles to machine learning pipelines.

Genetic programming concepts in TPOT:

  • Individuals: Each pipeline is an “organism”
  • Fitness: Cross-validation score determines survival
  • Selection: Best pipelines more likely to reproduce
  • Crossover: Combining pieces of two pipelines
  • Mutation: Random changes to operators or hyperparameters

This isn’t just a metaphor — TPOT implements actual genetic programming algorithms. Watching generations improve mirrors natural selection in compressed time.

The philosophical question: are we “discovering” optimal pipelines that exist in some platonic sense, or “creating” them through evolutionary pressure? Either way, it works :/

Practical Tips for Success

After using TPOT on dozens of projects, here’s what actually matters:

Start small, scale up: Begin with 5 generations and 20 population on a data sample. Make sure everything works before committing to overnight runs.

Monitor the first few generations: If score isn’t improving early, something’s wrong. Check your data, scoring metric, or search space.

Use early stopping: Set early_stop=10 to quit if no improvement for 10 generations. Saves time on plateaued searches.

Inspect exported pipelines: Don’t just trust the black box. Look at what TPOT built and understand why it works.

Iterate based on results: TPOT found feature selection helpful? Try more feature engineering. It picked ensemble methods? Explore ensembles manually.

TPOT is a tool for exploration and inspiration, not a magic solution that eliminates thinking. Use it to augment your skills, not replace them.

The Bottom Line

TPOT won’t replace your machine learning skills. It won’t automatically handle data cleaning, feature engineering, or understanding your business problem. What it will do is explore the vast space of possible pipelines way faster than you can manually.

Think of TPOT as having a tireless assistant who tests thousands of pipeline combinations while you sleep. You still need to frame the problem, prepare the data, interpret results, and make final decisions. But TPOT handles the tedious exploration part.

Start with small experiments. Get comfortable with the workflow. Then unleash it on real problems where you’re stuck or want to establish strong baselines quickly. The evolved pipelines might surprise you — and that’s exactly the point.

Now go evolve some pipelines and see what genetic programming discovers in your data :)

Comments