Model Evaluation¶
Evaluate fitted spike models: convergence diagnostics, sparsity analysis, replicate parameter correlations, global epistasis plots, and mutation parameter export.
Outline
Load fitted models and training data
Convergence diagnostics
Shift sparsity analysis
Replicate parameter correlations
Global epistasis plots
Export mutations DataFrame and intermediate CSVs
[1]:
import warnings
warnings.filterwarnings("ignore")
import os
import pickle
import sys
sys.path.insert(0, "notebooks")
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import multidms.plot
from multidms.model_collection import ModelCollection
from _common import load_config, combine_replicate_muts
[2]:
config_path = "config/config.yaml"
downstream_config_path = "config/config_downstream.yaml"
output_dir = None
[3]:
# Parameters
config_path = "config/config.yaml"
downstream_config_path = "config/config_downstream.yaml"
output_dir = "results-prod-294-naive-baseline-arm"
[4]:
config = load_config(config_path, downstream_config_path)
spike = config["spike"]
fit_config = spike["fitting"]
lasso_choice = spike["lasso_choice"]
condition_titles = spike["condition_titles"]
condition_colors = spike["condition_colors"]
experiment_conditions = spike["experiment_conditions"]
if output_dir is None:
output_dir = spike.get("output_dir", "results")
Load data¶
[5]:
with open(os.path.join(output_dir, "fit_collection.pkl"), "rb") as f:
fit_collection_df = pickle.load(f)
func_score_df = pd.read_csv(
os.path.join(output_dir, "training_functional_scores.csv")
).fillna({"aa_substitutions": ""})
model_collection = ModelCollection(fit_collection_df)
print(f"Loaded {len(fit_collection_df)} fitted models")
print(f"Loaded {len(func_score_df):,} training variants")
Loaded 20 fitted models
Loaded 303,007 training variants
Convergence diagnostics¶
[6]:
# Build summary table with fitted alpha and beta0 parameters
summary_rows = []
for _, row in model_collection.fit_models.iterrows():
jm = row.model._jax_model
r = {
"dataset": row.dataset_name,
"fusionreg": row.fusionreg,
"converged": row.converged,
"fit_time": row.fit_time,
}
# Alpha: shared scalar or per-condition dict
if hasattr(jm.α, "items"):
for cond in experiment_conditions:
title = condition_titles.get(cond, cond)
r[f"alpha_{title}"] = float(jm.α[cond])
else:
r["alpha"] = float(jm.α)
# Per-condition loss
for cond in experiment_conditions:
loss_col = f"{cond}_loss_training"
if loss_col in model_collection.fit_models.columns:
r[f"loss_{condition_titles.get(cond, cond)}"] = row[loss_col]
# Fitted beta0 per condition
for cond in experiment_conditions:
title = condition_titles.get(cond, cond)
r[f"beta0_{title}"] = float(jm.φ[cond].β0)
summary_rows.append(r)
summary_df = pd.DataFrame(summary_rows)
print(f"{summary_df['converged'].sum()}/{len(summary_df)} models converged\n")
summary_df.round(3)
19/20 models converged
[6]:
| dataset | fusionreg | converged | fit_time | alpha | loss_Delta | loss_BA.1 | loss_BA.2 | beta0_Delta | beta0_BA.1 | beta0_BA.2 | |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | rep_1 | 0.000 | True | 604 | 20.917 | 0.226 | 0.233 | 0.234 | -1.383 | -1.384 | -1.436 |
| 1 | rep_1 | 0.000 | True | 629 | 20.721 | 0.226 | 0.232 | 0.233 | -1.373 | -1.380 | -1.421 |
| 2 | rep_1 | 0.000 | True | 656 | 20.673 | 0.226 | 0.231 | 0.234 | -1.379 | -1.386 | -1.425 |
| 3 | rep_1 | 0.000 | True | 552 | 20.450 | 0.228 | 0.230 | 0.238 | -1.374 | -1.396 | -1.424 |
| 4 | rep_1 | 0.000 | True | 294 | 19.980 | 0.235 | 0.234 | 0.253 | -1.299 | -1.323 | -1.422 |
| 5 | rep_1 | 0.000 | True | 569 | 17.786 | 0.271 | 0.232 | 0.281 | -1.174 | -1.191 | -1.228 |
| 6 | rep_1 | 0.000 | True | 226 | 15.177 | 0.359 | 0.235 | 0.325 | -0.909 | -0.957 | -1.036 |
| 7 | rep_1 | 0.000 | True | 497 | 14.535 | 0.456 | 0.232 | 0.366 | -0.917 | -0.924 | -0.974 |
| 8 | rep_1 | 0.001 | True | 429 | 14.165 | 0.471 | 0.232 | 0.399 | -0.884 | -0.889 | -0.960 |
| 9 | rep_1 | 0.001 | False | 1321 | 4.082 | 0.511 | 0.242 | 0.434 | 1.615 | 1.578 | 1.638 |
| 10 | rep_2 | 0.000 | True | 829 | 21.582 | 0.266 | 0.190 | 0.190 | -1.431 | -1.431 | -1.481 |
| 11 | rep_2 | 0.000 | True | 815 | 21.508 | 0.266 | 0.190 | 0.190 | -1.429 | -1.430 | -1.482 |
| 12 | rep_2 | 0.000 | True | 788 | 20.868 | 0.266 | 0.189 | 0.191 | -1.396 | -1.399 | -1.448 |
| 13 | rep_2 | 0.000 | True | 707 | 20.988 | 0.267 | 0.187 | 0.193 | -1.417 | -1.426 | -1.468 |
| 14 | rep_2 | 0.000 | True | 308 | 20.783 | 0.277 | 0.190 | 0.208 | -1.356 | -1.388 | -1.532 |
| 15 | rep_2 | 0.000 | True | 187 | 19.274 | 0.307 | 0.194 | 0.236 | -1.214 | -1.260 | -1.464 |
| 16 | rep_2 | 0.000 | True | 186 | 17.151 | 0.386 | 0.195 | 0.280 | -1.029 | -1.103 | -1.252 |
| 17 | rep_2 | 0.000 | True | 520 | 15.154 | 0.513 | 0.189 | 0.337 | -0.959 | -0.982 | -1.031 |
| 18 | rep_2 | 0.001 | True | 263 | 14.312 | 0.559 | 0.191 | 0.382 | -0.873 | -0.895 | -0.957 |
| 19 | rep_2 | 0.001 | True | 278 | 13.869 | 0.564 | 0.191 | 0.409 | -0.813 | -0.850 | -0.907 |
[7]:
conv_data = model_collection.convergence_trajectory_df(
id_vars=("dataset_name", "fusionreg")
)
multidms.plot.convergence_trajectory(
conv_data,
id_cols=["dataset_name", "fusionreg"],
title="Convergence trajectories",
)
[7]: