Model Computation

doetools fits one ordinary least-squares (MLR) model for each imported response. The same configured model matrix is used for every response. The fitted models provide coefficients, ANOVA data, diagnostic metrics, and model-based plots.

This section covers model setup, fitting, and the available summary tables.

Quick Navigation:

Note

Before computing models, ensure:

  • that you have imported your response data using import_responses()

  • that you have defined the appropriate model terms (linear, interaction, quadratic) via set_model_terms()

Response conditions are optional. Set them with set_response_conditions() only for Pareto analysis or plots that use response limits and objectives.

Set Model Terms

Define the terms to include in the regression model. "all" includes every available term of that type; use None to omit a term type.

Note

If you want to visualize the leverage surface you need to set the model terms first.

Design.set_model_terms(terms)[source]

Specify the model terms for regression analysis.

Compiles terms for the factors in this design and builds the model matrix used for fitting. Process-factor terms include main effects, interactions, and quadratics; mixture terms are specified through the Scheffe options on ModelTerms.

Parameters:

terms (ModelTerms) – Requested process and mixture model terms.

Raises:

ValueError – If the requested terms are invalid for the design or the compiled model has more terms than experimental runs.

Return type:

None

Notes

The model matrix is constructed from the coded design matrix. Calling this method again replaces the previous model specification and matrix.

The ModelTerms class provides a convenient way to specify model terms:

class doetools.ModelTerms(intercept=True, pro_main='all', pro_int2='all', pro_quadratic='all', pro_int3=None, scheffe_pol_order=None, mix_main=None, mix_int2=None, mix_int3=None)[source]

Request specification for model terms in process and mixture designs.

This class is used to specify which terms should be included in a model before it is compiled into a ModelSpec. It supports both process factors (with quadratic terms) and mixture factors (with Scheffe polynomials).

Parameters:
  • intercept (bool) – Whether to include an intercept. It cannot be used with mixture factors. Defaults to True.

  • pro_main (Union[Literal['all'], list[str], None]) – Process main effects. Defaults to "all".

  • pro_int2 (Union[Literal['all'], list[tuple[str, str]], None]) – Two-factor process interactions. Defaults to "all".

  • pro_quadratic (Union[Literal['all'], list[str], None]) – Process quadratic terms. Defaults to "all".

  • pro_int3 (Union[Literal['all'], list[tuple[str, str, str]], None]) – Three-factor process interactions. Defaults to None.

  • scheffe_pol_order (int | None) – Scheffe polynomial order for mixture factors (1, 2, or 3). Defaults to None.

  • mix_main (Union[Literal['all'], list[str], None]) – Mixture main effects. Defaults to None.

  • mix_int2 (Union[Literal['all'], list[tuple[str, str]], None]) – Two-component mixture terms. Defaults to None.

  • mix_int3 (Union[Literal['all'], list[tuple[str, str, str]], None]) – Three-component mixture terms. Defaults to None.

Notes

Setting scheffe_pol_order fills in unspecified mixture terms. Order 1 includes main effects, order 2 also includes two-component terms, and order 3 also includes three-component terms.

Example:

from doetools import ModelTerms

# Screening: main effects only
terms = ModelTerms(
    intercept=True,
    pro_main="all",
    pro_int2=None,
    pro_quadratic=None,
)
design.set_model_terms(terms)

# Optimization: full quadratic model
terms = ModelTerms(
    intercept=True,
    pro_main="all",
    pro_int2="all",
    pro_quadratic="all",
)
design.set_model_terms(terms)

# Mixture design: quadratic Scheffe polynomial
terms = ModelTerms(
    intercept=False,
    pro_main=None,
    pro_int2=None,
    pro_quadratic=None,
    scheffe_pol_order=2,
)
design.set_model_terms(terms)

Set Response Condition

Set optional optimization goals for each response: lower/upper reference limits and maximize/minimize flags. These conditions are not used to fit the MLR model. Pareto analysis uses only the maximize/minimize directions; response limits are displayed as plot guides and do not remove Pareto candidates.

Design.set_response_conditions(lower_limits, upper_limits, maximize)[source]

Define optimization criteria for response variables.

Objective directions are used by Pareto analysis. Lower and upper limits are reference guides for plots and do not remove Pareto candidates. Conditions are not required to fit an MLR model. Response names must already have been defined, normally by passing responses to export_experiments.

Parameters:
  • lower_limits (List[float | None]) – Lower limits in response-list order. Use None where no lower limit is required.

  • upper_limits (List[float | None]) – Upper limits in response-list order. Use None where no upper limit is required.

  • maximize (List[bool]) – Whether to maximize (True) or minimize (False) each response.

Raises:
  • ValueError – If a supplied list does not have one entry for every response, a limit is non-finite, or a lower limit exceeds its upper limit.

  • TypeError – If limits are not numeric or None, or directions are not booleans.

Return type:

None

Example:

# Maximize yield, minimize cost, target range for purity
design.set_response_conditions(
    lower_limits=[70, None, 95],    # 70% min yield, no min cost, 95% min purity
    upper_limits=[None, 200, 100],  # no max yield, $200 max cost, 100% max purity
    maximize=[True, False, True]     # maximize yield & purity, minimize cost
)

Compute MLR Model

Fit separate MLR models using the defined model terms and imported responses. The method also identifies replicate groups, which are used for pure-error and lack-of-fit calculations when applicable.

Design.compute_mlr_model()[source]

Fit multiple linear regression models to the response data.

Fits one ordinary least-squares model for each imported response using the current model matrix. Replicate groups are identified automatically and used in the pure-error and lack-of-fit calculations when applicable.

Raises:

ValueError – If responses have not been imported or model terms have not been defined.

Return type:

None

Notes

Call set_model_terms() and import_responses() before fitting. The fitted models are then available to prediction and summary getters, and model-based plots.

Example:

# After importing responses and setting model terms
design.compute_mlr_model()

Compute a Pareto Front

After fitting the response models and assigning an objective direction (maximize or minimize) to each selected response, evaluate the models over a deterministic candidate grid. factor_levels selects exact continuous and categorical levels. Unspecified process factors use all their declared levels. Use mixture_grid for mixture resolution.

Design.compute_pareto_front(responses=None, *, factor_levels=None, mixture_include=(), mixture_grid=None, max_candidates=100000)

Compute the Pareto front over every domain-valid candidate.

Response lower and upper limits are reference guides for plots; they do not restrict Pareto candidates. Factor bounds, mixture constraints, and filters set with set_domain_filters define the candidate domain.

Return type:

None

design.compute_pareto_front(
    responses=["Yield", "Cost"],
    factor_levels={
        "Temperature": [40, 50, 60],
        "Catalyst": ["A", "C"],
    },
)

Response lower and upper limits are not hard constraints in this computation. They remain reference guides on the resulting 2D Pareto plot.

Model Statistics

These methods summarize in compact pd.DataFrame tables the results of regression analysis, including coefficient estimates, ANOVA results, model quality metrics, and diagnostic tests.

Coefficient Summary

Get regression coefficients with standard errors and significance tests.

DesignSummaryMixin.get_coefficient_summary(response)[source]

Return a defensive copy of a response coefficient table.

Return type:

DataFrame

Example:

coef_summary = design.get_coefficient_summary(response="Yield")
print(coef_summary)

# Output columns: Variable | Coefficient | Std_Error | Conf_Int |
#                 Lower_CI | Upper_CI | p_value

ANOVA Summary

Get ANOVA decomposition table.

DesignSummaryMixin.get_anova_summary(response)[source]

Return ANOVA dataframe for the specified response

Return type:

DataFrame

Example:

anova_summary = design.get_anova_summary(response="Yield")
print(anova_summary)

# Output columns: Source | SS | df | MS
# Pure Error and Lack of Fit rows are included only when available.

Diagnostic Metrics

Get model quality metrics (R², Adjusted R², RMSE, etc.).

DesignSummaryMixin.get_metric_summary(response)[source]

Return a defensive one-row table of fitted model metrics.

Return type:

DataFrame

Example:

metric_summary = design.get_metric_summary(response="Yield")
print(metric_summary)

# Output columns: R2 | R2_adj | Q2 | PRESS | RMSE | RMSE_CV

Model F-test

Get F-test results for overall model significance.

DesignSummaryMixin.get_model_f_test(response)[source]

Return the fitted-model F test for one response.

Return type:

DataFrame

Example:

f_test = design.get_model_f_test(response="Yield")
print(f_test)

# Output columns: F_value | F_crit_95% | F_crit_99% | p_value

Interpretation:

  • Null Hypothesis: All coefficients (except intercept) are zero

  • p-value < 0.05: Model is statistically significant (reject null hypothesis)

  • p-value > 0.05: Model does not explain variance better than the mean

Lack-of-Fit Test

Get lack-of-fit F-test results. The method returns an empty table if the fitted model has no usable pure-error and lack-of-fit degrees of freedom.

DesignSummaryMixin.get_lof_f_test(response)[source]

Return LOF F-test results, or an empty table when no LOF exists.

Return type:

DataFrame

Example:

lof_test = design.get_lof_f_test(response="Yield")
print(lof_test)

# Output columns: F_value | F_crit_95% | F_crit_99% | p_value

Interpretation:

  • Null Hypothesis: No lack of fit (model is adequate)

  • p-value > 0.05: Cannot detect lack of fit → model is adequate

  • p-value < 0.05: Significant lack of fit → model inadequate (add terms or transform)

  • Requires replicates: Pure error needed to separate model inadequacy from noise

Variance Inflation Factors

Get variance inflation factors to detect multicollinearity.

DesignSummaryMixin.get_vif()[source]

Return a defensive copy of model-matrix VIF diagnostics.

Return type:

DataFrame

Example:

vif_summary = design.get_vif()
print(vif_summary)

# Output columns: Term | VIF

Interpretation:

  • VIF = 1: No multicollinearity

  • VIF < 5: Low multicollinearity (good)

  • 5 ≤ VIF < 10: Moderate multicollinearity (potential concern)

  • VIF ≥ 10: High multicollinearity (problematic - inflates standard errors)

Dispersion Matrix

Get coefficient dispersion (covariance) matrix.

DesignSummaryMixin.get_dispersion_matrix(response, tol=1e-08)[source]

Return a full-precision, copy-safe parameter dispersion matrix.

Return type:

DataFrame

Example:

dispersion = design.get_dispersion_matrix(response="Yield")
print(dispersion)

Interpretation:

  • Diagonal elements: Variances of coefficient estimates

  • Off-diagonal elements: Covariances between coefficient estimates

Replicate Summary

Get statistics for replicate groups.

DesignSummaryMixin.get_replicate_summary(response)[source]

Return replicate statistics, or an empty table when not applicable.

Return type:

DataFrame

Example:

replicate_summary = design.get_replicate_summary(response="Yield")
print(replicate_summary)

# Output columns: Run Index | n* | Mean | Var | Std Dev | dof

Interpretation:

  • n*: Number of replicates at that design point

  • Mean: Average response across replicates

  • Var / Std Dev: Measurement variability at that point

  • High variance: Inconsistent measurements