183 lines
8.8 KiB
Python
183 lines
8.8 KiB
Python
# analysis.py
|
|
"""
|
|
Анализ экспериментальных данных: регрессия, проверка значимости, дисперсия в центре.
|
|
"""
|
|
import numpy as np
|
|
from core.table_io import handle_table_output
|
|
from core.statistics import (
|
|
compute_regression,
|
|
get_center_indices,
|
|
compute_center_stats,
|
|
chi2_confidence_interval,
|
|
get_t_critical,
|
|
regression_summary
|
|
)
|
|
|
|
def analysis_menu(mixture, design, responses):
|
|
if not design.plan or not responses:
|
|
print("Нет данных для анализа: план или отклики пусты.")
|
|
input("Нажмите Enter для продолжения...")
|
|
return
|
|
|
|
active_indices = design._active_indices()
|
|
k = len(active_indices)
|
|
if k < 2:
|
|
print("Для анализа необходимо минимум 2 активных фактора.")
|
|
input("Нажмите Enter для продолжения...")
|
|
return
|
|
|
|
factor_names = []
|
|
for idx in active_indices:
|
|
ing_index = idx + 1
|
|
if ing_index < len(mixture.ings):
|
|
factor_names.append(mixture.ings[ing_index].name)
|
|
else:
|
|
factor_names.append(f"x{idx+1}")
|
|
|
|
print("\nВведите уровень значимости alpha (например, 0.05, 0.01, 0.001):")
|
|
while True:
|
|
try:
|
|
alpha_input = input("alpha (по умолчанию 0.05): ").strip()
|
|
if alpha_input == "":
|
|
alpha = 0.05
|
|
else:
|
|
alpha = float(alpha_input)
|
|
if alpha <= 0 or alpha >= 1:
|
|
print("alpha должна быть в интервале (0, 1).")
|
|
continue
|
|
break
|
|
except ValueError:
|
|
print("Введите число.")
|
|
|
|
plan_matrix = np.array([[row[j] for j in active_indices] for row in design.plan])
|
|
N = plan_matrix.shape[0]
|
|
X = np.hstack([np.ones((N, 1)), plan_matrix])
|
|
df_res = N - (k + 1)
|
|
|
|
while True:
|
|
print("\n" + "=" * 50)
|
|
print("АНАЛИЗ ЗНАЧЕНИЙ")
|
|
print(f"Уровень значимости α = {alpha}")
|
|
print("Доступные отклики:")
|
|
for idx, resp in enumerate(responses, start=1):
|
|
print(f"{idx}. {resp['name']}")
|
|
print(f"{len(responses)+1}. Анализировать все отклики")
|
|
print("(Enter - выход в главное меню)")
|
|
print("=" * 50)
|
|
choice = input("Выберите отклик для анализа: ").strip()
|
|
if choice == "":
|
|
break
|
|
try:
|
|
idx = int(choice) - 1
|
|
if idx < 0:
|
|
print("Неверный номер.")
|
|
continue
|
|
if idx < len(responses):
|
|
analyze_single_response(responses[idx], X, k, df_res, design, alpha, factor_names)
|
|
input("Нажмите Enter для продолжения...")
|
|
elif idx == len(responses):
|
|
for resp in responses:
|
|
print(f"\n--- Анализ отклика '{resp['name']}' ---")
|
|
analyze_single_response(resp, X, k, df_res, design, alpha, factor_names)
|
|
input("Нажмите Enter для продолжения...")
|
|
else:
|
|
print("Неверный номер.")
|
|
except ValueError:
|
|
print("Введите число.")
|
|
|
|
def analyze_single_response(response, X, k, df_res, design, alpha, factor_names):
|
|
y = np.array(response["values"])
|
|
N = len(y)
|
|
if N != X.shape[0]:
|
|
print(f"Ошибка: число значений отклика ({N}) не соответствует числу опытов ({X.shape[0]})")
|
|
return
|
|
|
|
reg = compute_regression(X, y)
|
|
beta = reg["beta"]
|
|
se = reg["se"]
|
|
t_stats = reg["t_stats"]
|
|
s2_res = reg["s2_res"]
|
|
df_res_actual = reg["df_res"]
|
|
y_pred = reg["y_pred"]
|
|
|
|
if np.isnan(beta).any():
|
|
print("Ошибка при расчёте регрессии: матрица вырождена.")
|
|
return
|
|
|
|
def print_and_get_tcrit(beta, se, t_stats, df_res, y_pred, y, k, factor_names, alpha):
|
|
summary = regression_summary(y, y_pred, k, df_res)
|
|
r2 = summary["r2"]
|
|
r2_adj = summary["r2_adj"]
|
|
f_stat = summary["f_stat"]
|
|
f_pvalue = summary["f_pvalue"]
|
|
|
|
print("\n=== Регрессионный анализ ===")
|
|
print(f"Число опытов: {len(y)}")
|
|
print(f"Число факторов: {k}")
|
|
print(f"Степени свободы остатков: {df_res}")
|
|
print(f"Стандартная ошибка регрессии: {np.sqrt(s2_res) if not np.isnan(s2_res) else np.nan:.6f}")
|
|
print(f"Множественный R: {np.sqrt(r2) if not np.isnan(r2) else np.nan:.6f}")
|
|
print(f"R-квадрат: {r2:.6f}")
|
|
print(f"Скорректированный R-квадрат: {r2_adj:.6f}")
|
|
print(f"F-статистика: {f_stat:.4f}, p-value: {f_pvalue:.6f}")
|
|
|
|
t_crit = get_t_critical(df_res, alpha=alpha)
|
|
print("\nКоэффициенты регрессии:")
|
|
headers = ["Коэффициент", "Значение", "Станд. ошибка", "t-статистика", f"|t| > t_крит({alpha})?"]
|
|
rows = []
|
|
coef_names = ["Свободный член"] + factor_names
|
|
for i, name in enumerate(coef_names):
|
|
sig = "Да" if (not np.isnan(t_stats[i]) and abs(t_stats[i]) > t_crit and not np.isnan(t_crit)) else "Нет"
|
|
rows.append([
|
|
name,
|
|
f"{beta[i]:.6f}",
|
|
f"{se[i]:.6f}",
|
|
f"{t_stats[i]:.4f}",
|
|
sig
|
|
])
|
|
handle_table_output(headers, rows, title="", ask_each_time=True)
|
|
if not np.isnan(t_crit):
|
|
print(f"Критическое значение t (alpha={alpha}, df={df_res}): {t_crit:.4f}")
|
|
return t_crit
|
|
|
|
t_crit = print_and_get_tcrit(beta, se, t_stats, df_res_actual, y_pred, y, k, factor_names, alpha)
|
|
|
|
center_indices = get_center_indices(design.plan, design._active_indices())
|
|
if len(center_indices) >= 2:
|
|
y_center = y[center_indices]
|
|
center_mean, center_var = compute_center_stats(y_center)
|
|
print("\n=== Анализ центральных точек ===")
|
|
print(f"Количество центральных точек: {len(center_indices)}")
|
|
print(f"Среднее значение отклика в центре: {center_mean:.6f}")
|
|
print(f"Дисперсия в центре (несмещённая): {center_var:.6f}")
|
|
print(f"Стандартное отклонение: {np.sqrt(center_var):.6f}")
|
|
lower, upper = chi2_confidence_interval(center_var, len(center_indices), alpha=alpha)
|
|
if not np.isnan(lower):
|
|
print(f"Доверительный интервал для дисперсии (уровень доверия {1-alpha}): [{lower:.6f}, {upper:.6f}]")
|
|
else:
|
|
print("\nНедостаточно центральных точек (нужно минимум 2).")
|
|
|
|
if k > 0 and not np.isnan(t_crit):
|
|
print("\nХотите исключить незначимые факторы и пересчитать модель?")
|
|
choice = input("(y/n, по умолчанию n): ").strip().lower()
|
|
if choice == 'y':
|
|
significant = [True] + [abs(t_stats[i]) > t_crit for i in range(1, k+1)]
|
|
if all(significant):
|
|
print("Все факторы значимы. Упрощённая модель не отличается от полной.")
|
|
return
|
|
X_new = X[:, significant]
|
|
reg_new = compute_regression(X_new, y)
|
|
beta_new = reg_new["beta"]
|
|
se_new = reg_new["se"]
|
|
t_stats_new = reg_new["t_stats"]
|
|
df_res_new = reg_new["df_res"]
|
|
y_pred_new = reg_new["y_pred"]
|
|
if np.isnan(beta_new).any():
|
|
print("Ошибка при пересчёте упрощённой модели.")
|
|
return
|
|
factor_names_new = ["Свободный член"] + [factor_names[i-1] for i in range(1, k+1) if significant[i]]
|
|
k_new = len(factor_names_new) - 1
|
|
print("\n=== Упрощённая модель (исключены незначимые факторы) ===")
|
|
print_and_get_tcrit(beta_new, se_new, t_stats_new, df_res_new, y_pred_new, y, k_new, factor_names_new[1:], alpha)
|
|
print("\nСовет: для использования упрощённой модели в крутом восхождении установите шаги для исключённых факторов равными 0 в планировании эксперимента.")
|