Пример #1
0
    def test_four_fac_linear(self):
        """Tests a 4 factor optimal design with a linear model.

        This should select 5 corners of the hypercube.
        """
        optimal_data = build_optimal(4, order=ModelOrder.linear)

        model = make_model(optimal_data.columns, ModelOrder.linear, True)
        X = dmatrix(model, optimal_data)
        XtXi = np.linalg.inv(np.dot(np.transpose(X), X))
        d = np.linalg.det(XtXi)

        self.assertAlmostEqual(d, 4.34028E-4, delta=1e-3)
Пример #2
0
    def test_optimal(self):
        """Tests a simple 2 factor optimal design

        This is a 6 run design using a quadratic model, from the Meyer and
        Nachtsheim 1995 paper.
        """
        optimal_data = build_optimal(2, order=ModelOrder.quadratic)

        model = make_model(optimal_data.columns, ModelOrder.quadratic, True)
        X = dmatrix(model, optimal_data)
        XtXi = np.linalg.inv(np.dot(np.transpose(X), X))
        d = np.linalg.det(XtXi)

        self.assertAlmostEqual(d, 3.73506e-3, delta=1e-3)
Пример #3
0
    def test_linear(cls):
        """Checks the optimality of linear simplex lattice designs."""
        answer_d = [ 1 ] * 29
        actual_d = []
        order = ModelOrder.linear
        for i in range(2, 31):
            design = build_simplex_lattice(i, order)
            model = "-1 + " + make_model(design.columns, order,
                                         include_powers=False)
            x_matrix = patsy.dmatrix(model,
                                     design,
                                     return_type="dataframe")
            actual_d.append(det_xtxi(x_matrix, use_log=False))

        np.testing.assert_allclose(answer_d, actual_d, rtol=1e-5)
Пример #4
0
    def test_cubic(cls):
        """Checks the optimality of cubic simplex lattice designs."""
        answer_d = [
            2.2096470973347775, 13.228395211331954, 39.6547285196038,
            88.08632361788068, 165.1201784728033, 277.35271609131553,
            431.37986869540055, 633.7971466915958, 891.1996956551948,
            1210.1823437751189, 1597.3396416379908, 2059.265895808832,
        ]
        actual_d = []
        order = ModelOrder.cubic
        for i in range(2, 14):
            design = build_simplex_lattice(i, order)
            model = "-1 + " + make_model(design.columns, order,
                                         include_powers=False)
            x_matrix = patsy.dmatrix(model,
                                     design,
                                     return_type="dataframe")
            actual_d.append(det_xtxi(x_matrix, use_log=True))

        np.testing.assert_allclose(answer_d, actual_d, rtol=1e-4)
Пример #5
0
def build_optimal(factor_count, **kwargs):
    r"""Builds an optimal design.

    This uses the Coordinate-Exchange algorithm from Meyer and Nachtsheim 1995
    :cite:`MeyerNachtsheim1995`.

    :param factor_count: The number of factors to build for.
    :type factor_count: integer

    :Keyword Arguments:
        * **order** (:class:`ModelOrder <dexpy.model.ModelOrder>`) -- \
            Builds a design for this order model. \
            Mutually exclusive with the **model** parameter.
        * **model** (`patsy formula <https://patsy.readthedocs.io>`_) -- \
            Builds a design for this model formula. \
            Mutually exclusive with the **order** parameter.
        * **run_count** (`integer`) -- \
            The number of runs to use in the design. This must be equal\
            to or greater than the rank of the model.
    """
    factor_names = dexpy.design.get_factor_names(factor_count)

    model = kwargs.get('model', None)
    if model is None:
        order = kwargs.get('order', ModelOrder.quadratic)
        model = make_model(factor_names, order, True)

    run_count = kwargs.get('run_count', 0)

    # first generate a valid starting design
    (design, X) = bootstrap(factor_names, model, run_count)

    functions = []
    for _, subterms in X.design_info.term_codings.items():
        sub_funcs = []
        for subterm in subterms:
            for factor in subterm.factors:
                eval_code = X.design_info.factor_infos[factor].state[
                    'eval_code']
                if eval_code[0] == 'I':
                    eval_code = eval_code[1:]
                sub_funcs.append(eval_code)
        if not sub_funcs:
            functions.append("1")  # intercept
        else:
            functions.append("*".join(sub_funcs))

    full_func = "[" + ",".join(functions) + "]"
    code = compile(full_func, "<string>", "eval")

    steps = 12
    low = -1
    high = 1

    XtXi = np.linalg.inv(np.dot(np.transpose(X), X))
    (_, d_optimality) = np.linalg.slogdet(XtXi)

    design_improved = True
    swaps = 0
    evals = 0
    min_change = 1.0 + np.finfo(float).eps
    while design_improved:

        design_improved = False
        for i in range(0, len(design)):

            design_point = design.iloc[i]

            for f in range(0, factor_count):

                original_value = design_point[f]
                original_expanded = X[i]
                best_step = -1
                best_point = []
                best_change = min_change

                for s in range(0, steps):

                    design_point[f] = low + ((high - low) / (steps - 1)) * s
                    new_point = expand_point(design_point, code)
                    change_in_d = delta(X, XtXi, i, new_point)
                    evals += 1

                    if change_in_d - best_change > np.finfo(float).eps:
                        best_point = new_point
                        best_step = s
                        best_change = change_in_d

                if best_step >= 0:

                    # update X with the best point
                    design_point[f] = low + ((high - low) /
                                             (steps - 1)) * best_step
                    XtXi = update(XtXi, best_point, X[i])
                    X[i] = best_point

                    d_optimality -= math.log(best_change)
                    design_improved = True
                    swaps += 1

                else:

                    # restore the original design point value
                    design_point[f] = original_value
                    X[i] = original_expanded

    logging.info("{} swaps evaluated, {} executed ({:.2f}%)".format(
        evals, swaps, 100 * (swaps / evals)))

    return design
Пример #6
0
from patsy import dmatrix
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt

reaction_design = dexpy.optimal.build_optimal(2, order=ModelOrder.quadratic)

column_names = ['time', 'temp']
actual_lows = {'time': 40, 'temp': 80}
actual_highs = {'time': 50, 'temp': 90}

reaction_design.columns = column_names

print(coded_to_actual(reaction_design, actual_lows, actual_highs))

quad_model = make_model(reaction_design.columns, ModelOrder.quadratic)
X = dmatrix(quad_model, reaction_design)
XtX = np.dot(np.transpose(X), X)
d = np.linalg.det(XtX)

print("|(X'X)| for quadratic 2 factor optimal design: {}".format(d))

fg = sns.lmplot('time', 'temp', data=reaction_design, fit_reg=False)
ax = fg.axes[0, 0]
ax.set_xticks([-1, 0, 1])
ax.set_xticklabels(['40 min', '45 min', '50 min'])
ax.set_yticks([-1, 0, 1])
ax.set_yticklabels(['80C', '85C', '90C'])
plt.show()

reaction_design = dexpy.optimal.build_optimal(2,