From a79cf0cc191190ab45a9f2121b3a7cb4e6b67566 Mon Sep 17 00:00:00 2001 From: Artemiy Date: Thu, 30 Jul 2026 15:00:37 +0500 Subject: [PATCH] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D1=8B=20=D0=B4=D0=B2=D0=B5=20=D1=84=D1=83=D0=BD=D0=BA?= =?UTF-8?q?=D1=86=D0=B8=D0=B8=20=D0=B4=D0=BB=D1=8F=20=D0=B0=D0=BD=D0=B0?= =?UTF-8?q?=D0=BB=D0=B8=D0=B7=D0=B0=20=D0=A6=D0=9A=D0=9F=20=D0=BF=D0=BB?= =?UTF-8?q?=D0=B0=D0=BD=D0=B0:=20build=5Fquadratic=5FX=20=D0=B8=20analyze?= =?UTF-8?q?=5Fquadratic=5Fmodel?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/statistics.py | 100 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) diff --git a/core/statistics.py b/core/statistics.py index 27bdc53..e95751b 100644 --- a/core/statistics.py +++ b/core/statistics.py @@ -208,3 +208,103 @@ def anova_regression(y, y_pred, X, center_indices=None): "MS_pe": MS_pe, "MS_lof": MS_lof, "F_lof": F_lof, "p_lof": p_lof } +# core/statistics.py (дополнение) + +def build_quadratic_X(plan): + """ + Строит расширенную матрицу регрессоров для квадратичной модели. + plan: numpy array (N x k) – матрица плана в кодированных переменных. + Возвращает: X (N x p), где p = 1 + 2k + k*(k-1)//2 + (свободный член, линейные, квадраты, попарные произведения) + """ + N, k = plan.shape + X = np.ones((N, 1)) # свободный член + X = np.hstack([X, plan]) # линейные (k столбцов) + X = np.hstack([X, plan**2]) # квадраты (k столбцов) + # взаимодействия (k*(k-1)//2 столбцов) + for i in range(k): + for j in range(i+1, k): + X = np.hstack([X, (plan[:, i] * plan[:, j]).reshape(-1, 1)]) + return X + +def fit_quadratic_model(plan, y): + """ + Выполняет регрессию для квадратичной модели по матрице плана. + Возвращает словарь с результатами (аналогично compute_regression, но с добавлением структуры). + """ + X = build_quadratic_X(plan) + reg = compute_regression(X, y) # используем существующую функцию + # Добавляем информацию о структуре модели + k = plan.shape[1] + p_total = X.shape[1] + reg["k"] = k + reg["X"] = X + reg["plan"] = plan + reg["p_total"] = p_total + # Можно добавить имена коэффициентов (для вывода) + coef_names = ["Свободный член"] + coef_names += [f"x{i+1}" for i in range(k)] + coef_names += [f"x{i+1}²" for i in range(k)] + for i in range(k): + for j in range(i+1, k): + coef_names.append(f"x{i+1}·x{j+1}") + reg["coef_names"] = coef_names + return reg + +def analyze_quadratic_model(beta, k, X, y): + """ + Анализирует квадратичную модель: находит стационарную точку и тип экстремума. + beta – коэффициенты (включая все члены модели) + k – число факторов + X – матрица регрессоров (для расчёта предсказанных значений) + y – отклик + Возвращает словарь с результатами. + """ + # Извлекаем коэффициенты + b0 = beta[0] + b_lin = beta[1:1+k] # линейные + b_quad = beta[1+k:1+2*k] # квадраты + b_inter = beta[1+2*k:] # взаимодействия + + # Строим матрицу B (гессиан) для квадратичной формы + B = np.diag(2 * b_quad) + idx = 0 + for i in range(k): + for j in range(i+1, k): + B[i, j] = b_inter[idx] + B[j, i] = b_inter[idx] + idx += 1 + + # Стационарная точка: x* = -0.5 * inv(B) * b_lin + try: + x_star = -0.5 * np.linalg.solve(B, b_lin) + except np.linalg.LinAlgError: + x_star = None + + # Предсказанное значение в стационарной точке + if x_star is not None: + y_star = b0 + np.dot(b_lin, x_star) + np.dot(x_star, B @ x_star) / 2 + else: + y_star = None + + # Тип экстремума + if x_star is not None: + eigvals = np.linalg.eigvalsh(B) + if np.all(eigvals < 0): + extremum_type = "Максимум" + elif np.all(eigvals > 0): + extremum_type = "Минимум" + elif np.any(eigvals < 0) and np.any(eigvals > 0): + extremum_type = "Седловая точка" + else: + extremum_type = "Неопределён (есть нулевые собственные значения)" + else: + extremum_type = "Не найден (матрица B вырождена)" + + return { + "x_star": x_star, + "y_star": y_star, + "extremum_type": extremum_type, + "B": B, + "eigenvalues": np.linalg.eigvalsh(B) if x_star is not None else None + }