# 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 в планировании эксперимента.")