5.2. Viewing MLflow Results#

After running optimizations with MLflow enabled, you can view and analyze results using several methods.

5.2.2. Using the Python API#

Query MLflow programmatically for custom analysis:

5.2.2.1. Basic Run Retrieval#

import mlflow
from mlflow.tracking import MlflowClient

# Get experiment
experiment = mlflow.get_experiment_by_name("mloptimizer")

# Search all runs
all_runs = mlflow.search_runs(
    experiment_ids=[experiment.experiment_id],
    order_by=["start_time DESC"]
)

print(f"Found {len(all_runs)} runs")
print(all_runs[['run_id', 'start_time', 'metrics.final_best_fitness']])

5.2.2.2. Getting Parent Runs Only#

To filter for parent runs (optimization-level):

import re

# Parent runs have timestamp-based names
parent_runs = [
    r for r in all_runs.itertuples()
    if re.match(r'^\d{8}_\d{6}_', getattr(r, 'tags.mlflow.runName', ''))
]

print(f"Found {len(parent_runs)} optimization runs")

5.2.2.3. Retrieving Generation History#

Get generation-level metrics for a specific run:

from mlflow.tracking import MlflowClient

client = MlflowClient()
run_id = "your_run_id_here"  # From parent run

# Get generation best fitness history
gen_best = client.get_metric_history(run_id, "generation_best_fitness")
gen_avg = client.get_metric_history(run_id, "generation_avg_fitness")

# Print evolution
for metric in gen_best:
    print(f"Generation {metric.step}: Best={metric.value:.4f}")

5.2.2.4. Plotting Evolution#

Visualize fitness evolution across generations:

import matplotlib.pyplot as plt
from mlflow.tracking import MlflowClient

client = MlflowClient()
run_id = "your_run_id_here"

# Get metric history
gen_best = client.get_metric_history(run_id, "generation_best_fitness")
gen_avg = client.get_metric_history(run_id, "generation_avg_fitness")
gen_worst = client.get_metric_history(run_id, "generation_worst_fitness")

# Extract data
generations = [m.step for m in gen_best]
best_fitness = [m.value for m in gen_best]
avg_fitness = [m.value for m in gen_avg]
worst_fitness = [m.value for m in gen_worst]

# Create plot
plt.figure(figsize=(10, 6))
plt.plot(generations, best_fitness, 'g-o', label='Best', linewidth=2)
plt.plot(generations, avg_fitness, 'b-s', label='Average', linewidth=2)
plt.plot(generations, worst_fitness, 'r-^', label='Worst', linewidth=2)
plt.xlabel('Generation', fontsize=12)
plt.ylabel('Fitness', fontsize=12)
plt.title('Evolution of Population Fitness', fontsize=14)
plt.legend(fontsize=10)
plt.grid(True, alpha=0.3)
plt.tight_layout()
plt.savefig('evolution.png', dpi=150)
plt.show()

5.2.2.5. Comparing Multiple Runs#

Compare hyperparameters and results across runs:

import mlflow
import pandas as pd

# Get all runs from experiment
runs = mlflow.search_runs(experiment_ids=["1"])

# Select comparison columns
comparison = runs[[
    'run_id',
    'metrics.final_best_fitness',
    'params.population_size',
    'params.generations',
    'tags.estimator_class',
    'tags.early_stopped',
    'tags.optimization_time_seconds'
]].copy()

# Sort by performance
comparison = comparison.sort_values(
    'metrics.final_best_fitness',
    ascending=False
)

print(comparison)

5.2.3. Using the Extraction Script#

mloptimizer provides a ready-to-use extraction script for comprehensive analysis:

python scripts/mlflow_extract.py

This script automatically:

  1. Finds all MLflow experiments

  2. Extracts runs with metrics and parameters

  3. Analyzes generation evolution

  4. Exports results to CSV files:

    • mlflow_all_runs.csv - Complete run data

    • mlflow_runs_simple.csv - Key metrics and parameters

    • mlflow_hyperparameter_analysis.csv - Hyperparameter statistics

    • mlflow_generation_summary.csv - Evolution across generations

Example output:

================================================================================
MLFLOW RESULTS EXTRACTION
================================================================================

MLflow tracking URI: file:./mlruns

--------------------------------------------------------------------------------
AVAILABLE EXPERIMENTS
--------------------------------------------------------------------------------

Found 2 experiments:
  - Experiment ID: 0, Name: Default
  - Experiment ID: 1, Name: mloptimizer

Analyzing experiment: mloptimizer (ID: 1)

================================================================================
BEST RUN ANALYSIS
================================================================================

Best run ID: a7f3c9e8d4b5...
Start time: 2026-01-18 16:21:24
Status: FINISHED
Duration: 18.72 seconds

----------------------------------------
METRICS
----------------------------------------
  final_best_fitness: 0.965675
  generation_avg_fitness: 0.960300
  generation_best_fitness: 0.965675

----------------------------------------
HYPERPARAMETERS
----------------------------------------
  generations: 10
  population_size: 20
  early_stopping: True
  patience: 3

================================================================================
EVOLUTION ANALYSIS (ACROSS GENERATIONS)
================================================================================

Generation  Best      Average   Worst     StdDev
0          0.9615    0.9557    0.9498    0.0047
1          0.9615    0.9557    0.9498    0.0047
2          0.9625    0.9590    0.9555    0.0028
3          0.9629    0.9578    0.9527    0.0041
4          0.9657    0.9603    0.9549    0.0043

5.2.4. Analyzing Tags and Metadata#

Retrieve and analyze run metadata:

import mlflow

# Get a specific run
run = mlflow.get_run(run_id)

# Access tags
print("Dataset Information:")
print(f"  Samples: {run.data.tags.get('dataset_samples')}")
print(f"  Features: {run.data.tags.get('dataset_features')}")
print(f"  Classes: {run.data.tags.get('dataset_classes')}")

print("\nOptimization Results:")
print(f"  Estimator: {run.data.tags.get('estimator_class')}")
print(f"  Early stopped: {run.data.tags.get('early_stopped')}")
print(f"  Total evaluations: {run.data.tags.get('total_evaluations')}")
print(f"  Time: {run.data.tags.get('optimization_time_seconds')}s")

# Access parameters
print("\nConfiguration:")
print(f"  Population: {run.data.params.get('population_size')}")
print(f"  Generations: {run.data.params.get('generations')}")
print(f"  Parallel: {run.data.params.get('use_parallel')}")

5.2.5. Exporting Data for External Analysis#

Export MLflow data for use in other tools:

import mlflow
import pandas as pd

# Get all runs
runs = mlflow.search_runs(experiment_ids=["1"])

# Export to CSV
runs.to_csv('mlflow_results.csv', index=False)

# Export to Excel
runs.to_excel('mlflow_results.xlsx', index=False)

# Export to JSON
runs.to_json('mlflow_results.json', orient='records')

Tip

The MLflow UI is the fastest way to get an overview of your experiments. Use the Python API for custom analysis and automated reporting.

Note

Generation-level metrics use the step parameter in MLflow, allowing you to visualize evolution as a time series in the MLflow UI.