Compare commits
2 Commits
901a5e5c7b
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| a79cf0cc19 | |||
| 4cd38048d7 |
@@ -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
|
||||
}
|
||||
|
||||
@@ -2,8 +2,11 @@
|
||||
"""
|
||||
Главное меню программы.
|
||||
Загружает проект при старте и предоставляет доступ ко всем подменю.
|
||||
Обрабатывает прерывание Ctrl+C для корректного выхода.
|
||||
"""
|
||||
from core.fs import load_project
|
||||
|
||||
import sys
|
||||
from core.fs import load_project, save_project_partial
|
||||
from editor import editor_menu
|
||||
from plan import plan_menu
|
||||
from response import response_menu
|
||||
@@ -15,33 +18,45 @@ PROJECT_FILE = "project.json"
|
||||
def main():
|
||||
mixture, design, responses = load_project(PROJECT_FILE)
|
||||
|
||||
while True:
|
||||
print("\n" + "=" * 50)
|
||||
print("ГЛАВНОЕ МЕНЮ")
|
||||
print("1. Редактор состава")
|
||||
print("2. Планирование эксперимента")
|
||||
print("3. Ввод значений отклика")
|
||||
print("4. Анализ значений")
|
||||
print("5. Крутое восхождение")
|
||||
print("6. Выход")
|
||||
print("=" * 50)
|
||||
choice = input("Выберите пункт: ").strip()
|
||||
try:
|
||||
while True:
|
||||
print("\n" + "=" * 50)
|
||||
print("ГЛАВНОЕ МЕНЮ")
|
||||
print("1. Редактор состава")
|
||||
print("2. Планирование эксперимента")
|
||||
print("3. Ввод значений отклика")
|
||||
print("4. Анализ значений")
|
||||
print("5. Крутое восхождение")
|
||||
print("6. Выход")
|
||||
print("=" * 50)
|
||||
choice = input("Выберите пункт: ").strip()
|
||||
|
||||
if choice == "6":
|
||||
print("До свидания! (данные не сохранены автоматически)")
|
||||
break
|
||||
elif choice == "1":
|
||||
editor_menu(mixture)
|
||||
elif choice == "2":
|
||||
design = plan_menu(mixture, design)
|
||||
elif choice == "3":
|
||||
responses = response_menu(design, responses)
|
||||
elif choice == "4":
|
||||
analysis_menu(mixture, design, responses)
|
||||
elif choice == "5":
|
||||
ascent_menu(mixture, design, responses)
|
||||
if choice == "6":
|
||||
print("До свидания! (данные не сохранены автоматически)")
|
||||
break
|
||||
elif choice == "1":
|
||||
editor_menu(mixture)
|
||||
elif choice == "2":
|
||||
design = plan_menu(mixture, design)
|
||||
elif choice == "3":
|
||||
responses = response_menu(design, responses)
|
||||
elif choice == "4":
|
||||
analysis_menu(mixture, design, responses)
|
||||
elif choice == "5":
|
||||
ascent_menu(mixture, design, responses)
|
||||
else:
|
||||
print("Неверный пункт.")
|
||||
except KeyboardInterrupt:
|
||||
print("\n\nОбнаружено прерывание (Ctrl+C).")
|
||||
# Спрашиваем, хочет ли пользователь сохранить текущий проект
|
||||
save_choice = input("Сохранить текущий проект перед выходом? (y/n, Enter = нет): ").strip().lower()
|
||||
if save_choice == 'y':
|
||||
save_project_partial(PROJECT_FILE, mixture, design, responses)
|
||||
print("Проект сохранён.")
|
||||
else:
|
||||
print("Неверный пункт.")
|
||||
print("Выход без сохранения.")
|
||||
print("До свидания!")
|
||||
sys.exit(0)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
Reference in New Issue
Block a user