diff --git a/app/menu_load.py b/app/menu_load.py index 685d0ac..4a9a13e 100644 --- a/app/menu_load.py +++ b/app/menu_load.py @@ -1,6 +1,8 @@ from app.utils.system import clear_console from app.zadachi.zadacha1 import zadacha1 from app.zadachi.zadacha2 import zadacha2 +from app.zadachi.zadacha3 import zadacha3 +from app.zadachi.zadacha4 import zadacha4 class menu: @@ -13,6 +15,10 @@ class menu: print('\nMain Menu:') print('1. Задача 1') print('2. Задача 2') + print('3. Задача 3') + print('4. Задача 4') + print('5. Задача 5 (недоступно)') + print('6. Задача 6 (недоступно)') print('0. Exit') choice = input('Select an option: ') @@ -22,6 +28,14 @@ class menu: self.zadacha1_menu() # Переход к подменю Задачи 1 elif choice == '2': self.zadacha2_menu() # Переход к подменю Задачи 2 + elif choice == '3': + self.zadacha3_menu() # Переход к подменю Задачи 3 + elif choice == '4': + self.zadacha4_menu() # Добавлен вызов меню задачи 4 + elif choice == '5': + print('Временно недоступно') + elif choice == '6': + print('Временно недоступно') elif choice == '0': print('Exiting program...') break @@ -33,8 +47,8 @@ class menu: clear_console() while True: print('\nЗадача 1:') - print('1. линейно') - print('2. квадратично') + print('1. Линейно сгенерировать массив Y, зависящий от x') + print('2. Квадратично сгенерировать массив Y, зависящий от x') print('0. Назад') choice = input('Выберите подкатегорию: ') @@ -93,3 +107,51 @@ class menu: break # Вернуться в основное меню else: print('Неверный выбор, попробуйте снова.') + + def zadacha3_menu(self): + """Меню для задачи 3 (построение графика регрессии и расчет метрик).""" + clear_console() + z1 = zadacha1() # Используем объект задачи 1 для генерации данных + z2 = zadacha2() # Используем объект задачи 2 для расчета коэффициентов + + while True: + print('\nЗадача 3:') + print('1. Построить график регрессии и рассчитать метрики') + print('0. Назад') + + choice = input('Выберите подкатегорию: ') + + clear_console() + + if choice == '1': + x_data, y_data = z1.create_lin_array() + b0, b1 = z2.calculate_coefficients(x_data, y_data) + + # Создаем объект задачи 3 и выполняем построение графика + z3 = zadacha3(x_data, y_data, b0, b1) + z3.plot_regression() + elif choice == '0': + break # Вернуться в основное меню + else: + print('Неверный выбор, попробуйте снова.') + def zadacha4_menu(self): + """Меню для задачи 4 (работа с полиномиальными данными).""" + clear_console() + z4 = zadacha4() # Создаем объект задачи 4 + + while True: + print('\nЗадача 4:') + print('1. Провести визуальный анализ остатков') + print('0. Назад') + + choice = input('Выберите подкатегорию: ') + + clear_console() + + if choice == '1': + z4 = zadacha4() + z4.analyze_residuals() + elif choice == '0': + break + else: + print('Неверный выбор, попробуйте снова.') diff --git a/app/zadachi/zadacha3.py b/app/zadachi/zadacha3.py index e69de29..1c9e37a 100644 --- a/app/zadachi/zadacha3.py +++ b/app/zadachi/zadacha3.py @@ -0,0 +1,54 @@ +import numpy as np +import matplotlib.pyplot as plt + +class zadacha3: + def __init__(self, X, Y, b0, b1): + self.X = X + self.Y = Y + self.b0 = b0 + self.b1 = b1 + + def calculate_sse(self): + """ + Функция для расчета суммы квадратов ошибок (SSE) + :return: SSE + """ + Y_pred = self.b0 + self.b1 * self.X + sse = np.sum((self.Y - Y_pred) ** 2) + return sse + + def calculate_r_squared(self): + """ + Функция для расчета коэффициента детерминации R^2 + :return: R^2 + """ + y_mean = np.mean(self.Y) + ss_total = np.sum((self.Y - y_mean) ** 2) + ss_residual = self.calculate_sse() + r_squared = 1 - (ss_residual / ss_total) + return r_squared + + def plot_regression(self): + """ + Функция для построения графика регрессии и отображения метрик SSE и R^2 + """ + Y_pred = self.b0 + self.b1 * self.X + + plt.figure(figsize=(10, 6)) + + # График рассеяния и регрессионная прямая + plt.subplot(2, 1, 1) + plt.scatter(self.X, self.Y, label='Данные') + plt.plot(self.X, Y_pred, color='red', label='Регрессия') + plt.title("Линейная регрессия") + plt.xlabel("X") + plt.ylabel("Y") + plt.legend() + + # Расчет метрик и отображение на графике + sse = self.calculate_sse() + r_squared = self.calculate_r_squared() + plt.text(0.05, 0.95, f"SSE: {sse:.2f}\nR^2: {r_squared:.2f}", + transform=plt.gca().transAxes, verticalalignment='top') + + plt.show() diff --git a/app/zadachi/zadacha4.py b/app/zadachi/zadacha4.py index e69de29..10728dd 100644 --- a/app/zadachi/zadacha4.py +++ b/app/zadachi/zadacha4.py @@ -0,0 +1,62 @@ +import numpy as np +import matplotlib.pyplot as plt +from app.zadachi.zadacha2 import zadacha2 +from app.zadachi.zadacha1 import zadacha1 + +class zadacha4: + def __init__(self): + self.z1 = zadacha1() + self.z2 = zadacha2() + + def analyze_residuals(self): + """ + Выполняет визуальный анализ остатков по линейной модели. + Строит графики 2*2: скаттерограмма, график исходной зависимости, + распределение остатков и гистограмму остатков. + """ + # Генерируем данные + X, Y = self.z1.create_lin_array() + + # Рассчитываем коэффициенты методом наименьших квадратов + b0, b1 = self.z2.calculate_coefficients(X, Y) + + # Предсказанные значения + Y_pred = self.z2.predict(X, b0, b1) + + # Вычисляем остатки + residuals = Y - Y_pred + + # Создаем графики 2*2 + fig, axs = plt.subplots(2, 2, figsize=(12, 8)) + + # Первый график: скаттерограмма с линией МНК + axs[0, 0].scatter(X, Y, label='Данные с шумом', alpha=0.6) + axs[0, 0].plot(X, Y_pred, color='red', label='Прямая по МНК') + axs[0, 0].set_title('Скаттерограмма и прямая по МНК') + axs[0, 0].legend() + + # Второй график: исходная зависимость и линия МНК + axs[0, 1].scatter(X, Y, label='Данные', alpha=0.6) + axs[0, 1].plot(X, self.z1.create_lin_array(b0, b1, len(X))[1], color='green', label='Истинная линия') + axs[0, 1].plot(X, Y_pred, color='red', linestyle='--', label='Прямая по МНК') + axs[0, 1].set_title('Истинная линия и прямая по МНК') + axs[0, 1].legend() + + # Третий график: распределение остатков + axs[1, 0].scatter(X, residuals, color='purple', alpha=0.6) + axs[1, 0].axhline(y=0, color='red', linestyle='--') + axs[1, 0].set_title('Распределение остатков') + + # Четвертый график: гистограмма остатков + axs[1, 1].hist(residuals, bins=30, color='orange', edgecolor='black', alpha=0.7) + axs[1, 1].set_title('Гистограмма остатков') + + # Выравниваем графики и отображаем + plt.tight_layout() + plt.show() + + # Отдельное окно для гистограммы + plt.figure() + plt.hist(residuals, bins=30, color='orange', edgecolor='black', alpha=0.7) + plt.title('Гистограмма остатков (отдельно)') + plt.show() \ No newline at end of file diff --git a/main.py b/main.py index 613f6fc..a088d68 100644 --- a/main.py +++ b/main.py @@ -1,6 +1,11 @@ - +from app.utils.config import debug from app.menu_load import menu if __name__ == "__main__": - mn = menu() - mn.main_menu() + if debug == True: + print("Running in debug mode...") + from test_module.debug_main import debug_main_start + debug_main_start() + else: + mn = menu() + mn.main_menu()