Skip to content

Example: Full Validation Pipeline

End-to-end validation workflow — from training to deployment confidence.

import prandtl as pr
from prandtl import cross_validate, learning_curve, residual_analysis, metrics

# 1. Generate data
X, Y = pr.sample(
    pr.analytical.cl_flat_plate,
    bounds=[(-5, 15), (0.01, 0.1)],
    n=200, method="lhs", seed=42
)

# 2. Train
surrogate = pr.Surrogate(params=["alpha", "camber"], outputs=["CL"], method="gp")
surrogate.fit(X, Y)

# 3. Cross-validate
cv = cross_validate(surrogate, X, Y, cv=5)
print(f"CV MAE: {cv['CL']['mae_mean']:.4f} ± {cv['CL']['mae_std']:.4f}")

# 4. Learning curve
curve = learning_curve(surrogate, X, Y, sizes=[20, 50, 100, 150, 200])
print("Sizes:", curve["train_sizes"])
print("Train MAE:", [f"{x:.4f}" for x in curve["train_mae"]])
print("Val MAE:  ", [f"{x:.4f}" for x in curve["val_mae"]])
# If val_mae stops improving → enough data

# 5. Residual diagnostics
X_test, Y_test = pr.sample(
    pr.analytical.cl_flat_plate,
    bounds=[(-5, 15), (0.01, 0.1)],
    n=50, seed=99
)
Y_pred = surrogate.predict(X_test)
res = residual_analysis(Y_test, Y_pred)

for output in res:
    r = res[output]
    is_normal = r["shapiro_p"] > 0.05
    print(f"Shapiro-Wilk p={r['shapiro_p']:.3f}{'normal ✓' if is_normal else 'non-normal ✗'}")
    print(f"  Skewness: {r['skewness']:.3f}")
    print(f"  Kurtosis: {r['kurtosis']:.3f}")

# 6. Final metrics
report = metrics(Y_test, Y_pred)
print(f"Final R²: {report['CL']['r2']:.4f}")
print(f"Final MAE: {report['CL']['mae']:.4f}")

Interpreting the results

Check Good sign Warning sign
CV MAE Stable across folds High variance → uneven data
Learning curve val_mae plateaus Still improving → need more data
Shapiro-Wilk p > 0.05 p < 0.05 → systematic bias
Skewness ~0 > ±0.5 → directional bias