Выполнил: Меркулов Алексей Дмитриевич
Изучить принципы метода анализа иерархий. Произвести оценку и выбор наилучшей стиральной машины из 6 предложенных вариантов по 6 критериям, используя МАИ.
Тема: Выбор бытовой техники. Стиральная машина
Критерии оценки:
Матрица сравнения критериев
| Критерий | Цена | Качество стирки | Энергоэффективность | Уровень шума | Вместимость | Дополнительные функции |
|---|---|---|---|---|---|---|
| Цена | 1.000 | 0.333 | 0.500 | 0.250 | 0.333 | 0.200 |
| Качество стирки | 3.000 | 1.000 | 2.000 | 0.500 | 1.000 | 0.333 |
| Энергоэффективность | 2.000 | 0.500 | 1.000 | 0.333 | 0.500 | 0.250 |
| Уровень шума | 4.000 | 2.000 | 3.000 | 1.000 | 2.000 | 0.500 |
| Вместимость | 3.000 | 1.000 | 2.000 | 0.500 | 1.000 | 0.333 |
| Дополнительные функции | 5.000 | 3.000 | 4.000 | 2.000 | 3.000 | 1.000 |
По критерию: Цена
Матрица сравнения альтернатив по критерию 'Цена'
| Критерий | Samsung WW70J5260JW | LG F2J6HS0W | Bosch WAN28281 | Indesit IWSC 51051 | Beko WRE 6512 BSW | Zanussi ZWSO6103 |
|---|---|---|---|---|---|---|
| Samsung WW70J5260JW | 1.000 | 0.333 | 0.250 | 2.000 | 0.500 | 0.200 |
| LG F2J6HS0W | 3.000 | 1.000 | 0.500 | 4.000 | 2.000 | 0.333 |
| Bosch WAN28281 | 4.000 | 2.000 | 1.000 | 5.000 | 3.000 | 0.500 |
| Indesit IWSC 51051 | 0.500 | 0.250 | 0.200 | 1.000 | 0.333 | 0.167 |
| Beko WRE 6512 BSW | 2.000 | 0.500 | 0.333 | 3.000 | 1.000 | 0.250 |
| Zanussi ZWSO6103 | 5.000 | 3.000 | 2.000 | 6.000 | 4.000 | 1.000 |
По критерию: Качество стирки
Матрица сравнения альтернатив по критерию 'Качество стирки'
| Критерий | Samsung WW70J5260JW | LG F2J6HS0W | Bosch WAN28281 | Indesit IWSC 51051 | Beko WRE 6512 BSW | Zanussi ZWSO6103 |
|---|---|---|---|---|---|---|
| Samsung WW70J5260JW | 1.000 | 2.000 | 0.500 | 4.000 | 3.000 | 0.333 |
| LG F2J6HS0W | 0.500 | 1.000 | 0.333 | 3.000 | 2.000 | 0.250 |
| Bosch WAN28281 | 2.000 | 3.000 | 1.000 | 5.000 | 4.000 | 0.500 |
| Indesit IWSC 51051 | 0.250 | 0.333 | 0.200 | 1.000 | 0.500 | 0.167 |
| Beko WRE 6512 BSW | 0.333 | 0.500 | 0.250 | 2.000 | 1.000 | 0.200 |
| Zanussi ZWSO6103 | 3.000 | 4.000 | 2.000 | 6.000 | 5.000 | 1.000 |
По критерию: Энергоэффективность
Матрица сравнения альтернатив по критерию 'Энергоэффективность'
| Критерий | Samsung WW70J5260JW | LG F2J6HS0W | Bosch WAN28281 | Indesit IWSC 51051 | Beko WRE 6512 BSW | Zanussi ZWSO6103 |
|---|---|---|---|---|---|---|
| Samsung WW70J5260JW | 1.000 | 0.500 | 0.333 | 3.000 | 2.000 | 0.250 |
| LG F2J6HS0W | 2.000 | 1.000 | 0.500 | 4.000 | 3.000 | 0.333 |
| Bosch WAN28281 | 3.000 | 2.000 | 1.000 | 5.000 | 4.000 | 0.500 |
| Indesit IWSC 51051 | 0.333 | 0.250 | 0.200 | 1.000 | 0.500 | 0.167 |
| Beko WRE 6512 BSW | 0.500 | 0.333 | 0.250 | 2.000 | 1.000 | 0.200 |
| Zanussi ZWSO6103 | 4.000 | 3.000 | 2.000 | 6.000 | 5.000 | 1.000 |
По критерию: Уровень шума
Матрица сравнения альтернатив по критерию 'Уровень шума'
| Критерий | Samsung WW70J5260JW | LG F2J6HS0W | Bosch WAN28281 | Indesit IWSC 51051 | Beko WRE 6512 BSW | Zanussi ZWSO6103 |
|---|---|---|---|---|---|---|
| Samsung WW70J5260JW | 1.000 | 0.500 | 0.333 | 3.000 | 2.000 | 0.250 |
| LG F2J6HS0W | 2.000 | 1.000 | 0.500 | 4.000 | 3.000 | 0.333 |
| Bosch WAN28281 | 3.000 | 2.000 | 1.000 | 5.000 | 4.000 | 0.500 |
| Indesit IWSC 51051 | 0.333 | 0.250 | 0.200 | 1.000 | 0.500 | 0.167 |
| Beko WRE 6512 BSW | 0.500 | 0.333 | 0.250 | 2.000 | 1.000 | 0.200 |
| Zanussi ZWSO6103 | 4.000 | 3.000 | 2.000 | 6.000 | 5.000 | 1.000 |
По критерию: Вместимость
Матрица сравнения альтернатив по критерию 'Вместимость'
| Критерий | Samsung WW70J5260JW | LG F2J6HS0W | Bosch WAN28281 | Indesit IWSC 51051 | Beko WRE 6512 BSW | Zanussi ZWSO6103 |
|---|---|---|---|---|---|---|
| Samsung WW70J5260JW | 1.000 | 0.333 | 0.500 | 2.000 | 0.500 | 0.250 |
| LG F2J6HS0W | 3.000 | 1.000 | 2.000 | 4.000 | 2.000 | 0.500 |
| Bosch WAN28281 | 2.000 | 0.500 | 1.000 | 3.000 | 1.000 | 0.333 |
| Indesit IWSC 51051 | 0.500 | 0.250 | 0.333 | 1.000 | 0.333 | 0.200 |
| Beko WRE 6512 BSW | 2.000 | 0.500 | 1.000 | 3.000 | 1.000 | 0.333 |
| Zanussi ZWSO6103 | 4.000 | 2.000 | 3.000 | 5.000 | 3.000 | 1.000 |
По критерию: Дополнительные функции
Матрица сравнения альтернатив по критерию 'Дополнительные функции'
| Критерий | Samsung WW70J5260JW | LG F2J6HS0W | Bosch WAN28281 | Indesit IWSC 51051 | Beko WRE 6512 BSW | Zanussi ZWSO6103 |
|---|---|---|---|---|---|---|
| Samsung WW70J5260JW | 1.000 | 0.500 | 0.333 | 3.000 | 2.000 | 0.250 |
| LG F2J6HS0W | 2.000 | 1.000 | 0.500 | 4.000 | 3.000 | 0.333 |
| Bosch WAN28281 | 3.000 | 2.000 | 1.000 | 5.000 | 4.000 | 0.500 |
| Indesit IWSC 51051 | 0.333 | 0.250 | 0.200 | 1.000 | 0.500 | 0.167 |
| Beko WRE 6512 BSW | 0.500 | 0.333 | 0.250 | 2.000 | 1.000 | 0.200 |
| Zanussi ZWSO6103 | 4.000 | 3.000 | 2.000 | 6.000 | 5.000 | 1.000 |
| Критерий | Вес приоритета |
|---|---|
| Цена | 0.0512 |
| Качество стирки | 0.1364 |
| Энергоэффективность | 0.0803 |
| Уровень шума | 0.2317 |
| Вместимость | 0.1364 |
| Дополнительные функции | 0.3639 |
Проверка согласованности матрицы критериев:
По критерию: Цена
| Альтернатива | Локальный приоритет |
|---|---|
| Samsung WW70J5260JW | 0.0643 |
| LG F2J6HS0W | 0.1602 |
| Bosch WAN28281 | 0.2516 |
| Indesit IWSC 51051 | 0.0425 |
| Beko WRE 6512 BSW | 0.1009 |
| Zanussi ZWSO6103 | 0.3806 |
Согласованность: CR = 0.0197 (✓)
По критерию: Качество стирки
| Альтернатива | Локальный приоритет |
|---|---|
| Samsung WW70J5260JW | 0.1602 |
| LG F2J6HS0W | 0.1009 |
| Bosch WAN28281 | 0.2516 |
| Indesit IWSC 51051 | 0.0425 |
| Beko WRE 6512 BSW | 0.0643 |
| Zanussi ZWSO6103 | 0.3806 |
Согласованность: CR = 0.0197 (✓)
По критерию: Энергоэффективность
| Альтернатива | Локальный приоритет |
|---|---|
| Samsung WW70J5260JW | 0.1009 |
| LG F2J6HS0W | 0.1602 |
| Bosch WAN28281 | 0.2516 |
| Indesit IWSC 51051 | 0.0425 |
| Beko WRE 6512 BSW | 0.0643 |
| Zanussi ZWSO6103 | 0.3806 |
Согласованность: CR = 0.0197 (✓)
По критерию: Уровень шума
| Альтернатива | Локальный приоритет |
|---|---|
| Samsung WW70J5260JW | 0.1009 |
| LG F2J6HS0W | 0.1602 |
| Bosch WAN28281 | 0.2516 |
| Indesit IWSC 51051 | 0.0425 |
| Beko WRE 6512 BSW | 0.0643 |
| Zanussi ZWSO6103 | 0.3806 |
Согласованность: CR = 0.0197 (✓)
По критерию: Вместимость
| Альтернатива | Локальный приоритет |
|---|---|
| Samsung WW70J5260JW | 0.0803 |
| LG F2J6HS0W | 0.2317 |
| Bosch WAN28281 | 0.1364 |
| Indesit IWSC 51051 | 0.0512 |
| Beko WRE 6512 BSW | 0.1364 |
| Zanussi ZWSO6103 | 0.3639 |
Согласованность: CR = 0.0118 (✓)
По критерию: Дополнительные функции
| Альтернатива | Локальный приоритет |
|---|---|
| Samsung WW70J5260JW | 0.1009 |
| LG F2J6HS0W | 0.1602 |
| Bosch WAN28281 | 0.2516 |
| Indesit IWSC 51051 | 0.0425 |
| Beko WRE 6512 BSW | 0.0643 |
| Zanussi ZWSO6103 | 0.3806 |
Согласованность: CR = 0.0197 (✓)
Матрица локальных приоритетов
| Альтернатива | Цена | Качество стирки | Энергоэффективность | Уровень шума | Вместимость | Дополнительные функции |
|---|---|---|---|---|---|---|
| Samsung WW70J5260JW | 0.0643 | 0.1602 | 0.1009 | 0.1009 | 0.0803 | 0.1009 |
| LG F2J6HS0W | 0.1602 | 0.1009 | 0.1602 | 0.1602 | 0.2317 | 0.1602 |
| Bosch WAN28281 | 0.2516 | 0.2516 | 0.2516 | 0.2516 | 0.1364 | 0.2516 |
| Indesit IWSC 51051 | 0.0425 | 0.0425 | 0.0425 | 0.0425 | 0.0512 | 0.0425 |
| Beko WRE 6512 BSW | 0.1009 | 0.0643 | 0.0643 | 0.0643 | 0.1364 | 0.0643 |
| Zanussi ZWSO6103 | 0.3806 | 0.3806 | 0.3806 | 0.3806 | 0.3639 | 0.3806 |
| Альтернатива | Глобальный приоритет | Рейтинг |
|---|---|---|
| Samsung WW70J5260JW | 0.1043 | |
| LG F2J6HS0W | 0.1619 | |
| Bosch WAN28281 | 0.2358 | |
| Indesit IWSC 51051 | 0.0437 | |
| Beko WRE 6512 BSW | 0.0760 | |
| Zanussi ZWSO6103 | 0.3783 | ✓ ЛУЧШАЯ |
Наилучшей альтернативой является: Zanussi ZWSO6103
Обоснование: Данная модель показала наивысший глобальный приоритет (0.3783) среди всех рассмотренных альтернатив, что свидетельствует о ее превосходстве по совокупности оцениваемых критериев.
# lab5_ahp_analysis.py
# -*- coding: utf-8 -*-
"""
Лабораторная работа №5: Метод анализа иерархий (МАИ)
Выбор стиральной машины по 6 критериям из 6 альтернатив
"""
import os
import numpy as np
import datetime
from typing import List, Tuple, Dict, Any
import sys
# Попытка импортировать python-docx для генерации .docx отчёта
try:
from docx import Document
from docx.shared import Inches, Pt
PYDOCX_AVAILABLE = True
except Exception:
PYDOCX_AVAILABLE = False
def read_own_source() -> Tuple[bool, str]:
"""
Пытается прочитать исходный код текущего файла и вернуть (успех, текст).
Возвращает (False, сообщение об ошибке) при неудаче.
"""
try:
current_file = os.path.abspath(__file__)
except Exception:
current_file = os.path.abspath(sys.argv[0]) if sys.argv and sys.argv[0] else None
if not current_file or not os.path.exists(current_file):
return False, "Не удалось определить путь к файлу скрипта"
try:
with open(current_file, "r", encoding="utf-8") as f:
src = f.read()
return True, src
except Exception as e:
return False, f"Ошибка при чтении исходного кода: {e}"
class AHPCalculator:
"""Класс для реализации метода анализа иерархий"""
def __init__(self):
self.consistency_index = {
1: 0.0, 2: 0.0, 3: 0.58, 4: 0.9, 5: 1.12,
6: 1.24, 7: 1.32, 8: 1.41, 9: 1.45, 10: 1.49
}
def calculate_priority_vector(self, matrix: np.ndarray) -> np.ndarray:
"""Вычисление вектора приоритетов методом среднего геометрического"""
n = matrix.shape[0]
# Вычисление среднего геометрического для каждой строки
geometric_means = np.prod(matrix, axis=1) ** (1/n)
# Нормализация вектора
priority_vector = geometric_means / np.sum(geometric_means)
return priority_vector
def calculate_consistency(self, matrix: np.ndarray, priority_vector: np.ndarray) -> Dict[str, float]:
"""Расчет показателей согласованности"""
n = matrix.shape[0]
# Вычисление главного собственного значения
weighted_sum = np.dot(matrix, priority_vector)
lambda_max = np.sum(weighted_sum / priority_vector) / n
# Индекс согласованности
CI = (lambda_max - n) / (n - 1) if n > 1 else 0
# Отношение согласованности
RI = self.consistency_index.get(n, 1.45)
CR = CI / RI if RI != 0 else 0
return {
'lambda_max': lambda_max,
'CI': CI,
'RI': RI,
'CR': CR,
'is_consistent': CR <= 0.1
}
class AHPModel:
"""Модель для выбора стиральной машины методом АИ"""
def __init__(self):
self.criteria = [
"Цена",
"Качество стирки",
"Энергоэффективность",
"Уровень шума",
"Вместимость",
"Дополнительные функции"
]
self.alternatives = [
"Samsung WW70J5260JW",
"LG F2J6HS0W",
"Bosch WAN28281",
"Indesit IWSC 51051",
"Beko WRE 6512 BSW",
"Zanussi ZWSO6103"
]
self.ahp = AHPCalculator()
# Матрица парных сравнений критериев
self.criteria_matrix = self._create_criteria_matrix()
# Матрицы парных сравнений альтернатив по каждому критерию
self.alternative_matrices = self._create_alternative_matrices()
# Результаты расчетов
self.results = {}
def _create_criteria_matrix(self) -> np.ndarray:
"""Создание матрицы парных сравнений критериев"""
# Шкала Саати: 1 - равная важность, 9 - абсолютно важнее
matrix = np.array([
[1, 1/3, 1/2, 1/4, 1/3, 1/5], # Цена
[3, 1, 2, 1/2, 1, 1/3], # Качество стирки
[2, 1/2, 1, 1/3, 1/2, 1/4], # Энергоэффективность
[4, 2, 3, 1, 2, 1/2], # Уровень шума
[3, 1, 2, 1/2, 1, 1/3], # Вместимость
[5, 3, 4, 2, 3, 1] # Дополнительные функции
])
return matrix
def _create_alternative_matrices(self) -> List[np.ndarray]:
"""Создание матриц парных сравнений альтернатив по критериям"""
matrices = []
# Матрицы для каждого критерия (6 критериев)
# 1. Цена (чем дешевле - тем лучше)
matrices.append(np.array([
[1, 1/3, 1/4, 2, 1/2, 1/5], # Samsung
[3, 1, 1/2, 4, 2, 1/3], # LG
[4, 2, 1, 5, 3, 1/2], # Bosch
[1/2, 1/4, 1/5, 1, 1/3, 1/6], # Indesit
[2, 1/2, 1/3, 3, 1, 1/4], # Beko
[5, 3, 2, 6, 4, 1] # Zanussi
]))
# 2. Качество стирки
matrices.append(np.array([
[1, 2, 1/2, 4, 3, 1/3], # Samsung
[1/2, 1, 1/3, 3, 2, 1/4], # LG
[2, 3, 1, 5, 4, 1/2], # Bosch
[1/4, 1/3, 1/5, 1, 1/2, 1/6], # Indesit
[1/3, 1/2, 1/4, 2, 1, 1/5], # Beko
[3, 4, 2, 6, 5, 1] # Zanussi
]))
# 3. Энергоэффективность
matrices.append(np.array([
[1, 1/2, 1/3, 3, 2, 1/4], # Samsung
[2, 1, 1/2, 4, 3, 1/3], # LG
[3, 2, 1, 5, 4, 1/2], # Bosch
[1/3, 1/4, 1/5, 1, 1/2, 1/6], # Indesit
[1/2, 1/3, 1/4, 2, 1, 1/5], # Beko
[4, 3, 2, 6, 5, 1] # Zanussi
]))
# 4. Уровень шума
matrices.append(np.array([
[1, 1/2, 1/3, 3, 2, 1/4], # Samsung
[2, 1, 1/2, 4, 3, 1/3], # LG
[3, 2, 1, 5, 4, 1/2], # Bosch
[1/3, 1/4, 1/5, 1, 1/2, 1/6], # Indesit
[1/2, 1/3, 1/4, 2, 1, 1/5], # Beko
[4, 3, 2, 6, 5, 1] # Zanussi
]))
# 5. Вместимость
matrices.append(np.array([
[1, 1/3, 1/2, 2, 1/2, 1/4], # Samsung
[3, 1, 2, 4, 2, 1/2], # LG
[2, 1/2, 1, 3, 1, 1/3], # Bosch
[1/2, 1/4, 1/3, 1, 1/3, 1/5], # Indesit
[2, 1/2, 1, 3, 1, 1/3], # Beko
[4, 2, 3, 5, 3, 1] # Zanussi
]))
# 6. Дополнительные функции
matrices.append(np.array([
[1, 1/2, 1/3, 3, 2, 1/4], # Samsung
[2, 1, 1/2, 4, 3, 1/3], # LG
[3, 2, 1, 5, 4, 1/2], # Bosch
[1/3, 1/4, 1/5, 1, 1/2, 1/6], # Indesit
[1/2, 1/3, 1/4, 2, 1, 1/5], # Beko
[4, 3, 2, 6, 5, 1] # Zanussi
]))
return matrices
def get_alternative_descriptions(self) -> List[Dict[str, str]]:
"""Возвращает словесное описание альтернатив"""
descriptions = [
{
"name": "Samsung WW70J5260JW",
"price": "Средняя цена",
"quality": "Отличное качество стирки",
"energy": "Класс A++",
"noise": "Низкий уровень шума (52 дБ)",
"capacity": "Загрузка 7 кг",
"features": "Умные функции, цифровой дисплей"
},
{
"name": "LG F2J6HS0W",
"price": "Высокая цена",
"quality": "Превосходное качество стирки",
"energy": "Класс A+++",
"noise": "Очень низкий уровень шума (48 дБ)",
"capacity": "Загрузка 8 кг",
"features": "Паровая обработка, смарт-управление"
},
{
"name": "Bosch WAN28281",
"price": "Высокая цена",
"quality": "Отличное качество стирки",
"energy": "Класс A++",
"noise": "Низкий уровень шума (50 дБ)",
"capacity": "Загрузка 7 кг",
"features": "Антиаллергенная программа, защита от детей"
},
{
"name": "Indesit IWSC 51051",
"price": "Низкая цена",
"quality": "Хорошее качество стирки",
"energy": "Класс A+",
"noise": "Средний уровень шума (58 дБ)",
"capacity": "Загрузка 5 кг",
"features": "Базовые функции, простой интерфейс"
},
{
"name": "Beko WRE 6512 BSW",
"price": "Низкая цена",
"quality": "Хорошее качество стирки",
"energy": "Класс A++",
"noise": "Средний уровень шума (56 дБ)",
"capacity": "Загрузка 6 кг",
"features": "Эко-программы, быстрая стирка"
},
{
"name": "Zanussi ZWSO6103",
"price": "Средняя цена",
"quality": "Очень хорошее качество стирки",
"energy": "Класс A++",
"noise": "Низкий уровень шума (53 дБ)",
"capacity": "Загрузка 6 кг",
"features": "Функция защиты от сминания, таймер"
}
]
return descriptions
def analyze(self) -> Dict[str, Any]:
"""Выполнение полного анализа МАИ"""
# 1. Расчет приоритетов критериев
criteria_pv = self.ahp.calculate_priority_vector(self.criteria_matrix)
criteria_consistency = self.ahp.calculate_consistency(self.criteria_matrix, criteria_pv)
# 2. Расчет приоритетов альтернатив по каждому критерию
alternative_pvs = []
alternative_consistencies = []
for i, matrix in enumerate(self.alternative_matrices):
pv = self.ahp.calculate_priority_vector(matrix)
consistency = self.ahp.calculate_consistency(matrix, pv)
alternative_pvs.append(pv)
alternative_consistencies.append(consistency)
# 3. Формирование матрицы локальных приоритетов альтернатив
local_priorities_matrix = np.column_stack(alternative_pvs)
# 4. Иерархический синтез - расчет глобальных приоритетов
global_priorities = np.dot(local_priorities_matrix, criteria_pv)
# 5. Определение лучшей альтернативы
best_index = np.argmax(global_priorities)
best_alternative = self.alternatives[best_index]
# Сохранение результатов
self.results = {
'criteria_priorities': criteria_pv.tolist(),
'criteria_consistency': criteria_consistency,
'alternative_priorities': [pv.tolist() for pv in alternative_pvs],
'alternative_consistencies': alternative_consistencies,
'local_priorities_matrix': local_priorities_matrix.tolist(),
'global_priorities': global_priorities.tolist(),
'best_alternative': best_alternative,
'best_index': best_index,
'criteria_matrix': self.criteria_matrix.tolist(),
'alternative_matrices': [matrix.tolist() for matrix in self.alternative_matrices]
}
return self.results
class AHPMarkdownReport:
"""Класс для генерации полного отчета в Markdown для ЛР5"""
def __init__(self, ahp_model: AHPModel, analysis_results: Dict[str, Any]):
self.model = ahp_model
self.results = analysis_results
def add_header(self, title: str, level: int = 1) -> str:
return f"{'#' * level} {title}\n\n"
def add_table(self, data: List[List[Any]], headers: List[str], title: str = "") -> str:
table_str = ""
if title:
table_str += f"**{title}**\n\n"
table_str += "| " + " | ".join(headers) + " |\n"
table_str += "|" + "|".join(["---"] * len(headers)) + "|\n"
for row in data:
table_str += "| " + " | ".join(map(str, row)) + " |\n"
table_str += "\n"
return table_str
def add_matrix_table(self, matrix: List[List[float]], row_labels: List[str],
col_labels: List[str], title: str = "") -> str:
"""Создание таблицы для матрицы парных сравнений"""
table_str = ""
if title:
table_str += f"**{title}**\n\n"
# Заголовок с метками столбцов
table_str += "| Критерий | " + " | ".join(col_labels) + " |\n"
table_str += "|" + "|".join(["---"] * (len(col_labels) + 1)) + "|\n"
# Данные матрицы
for i, row in enumerate(matrix):
table_str += f"| **{row_labels[i]}** | " + " | ".join([f"{x:.3f}" for x in row]) + " |\n"
table_str += "\n"
return table_str
def add_code_section(self) -> str:
success, src = read_own_source()
section = self.add_header("Исходный код программы", 2)
if success:
section += "```python\n" + src
if not src.endswith("\n"):
section += "\n"
section += "```\n"
else:
section += f"*Не удалось прочитать исходный код: {src}*\n"
return section
def generate_report(self) -> str:
report = self.add_header("Лабораторная работа №5: Метод анализа иерархий (МАИ)", 1)
report += "**Выполнил:** Меркулов Алексей Дмитриевич\n"
# Цель работы
report += self.add_header("Цель работы", 2)
report += "Изучить принципы метода анализа иерархий. Произвести оценку и выбор наилучшей стиральной машины из 6 предложенных вариантов по 6 критериям, используя МАИ.\n\n"
# Описание задачи и критериев
report += self.add_header("Описание задачи", 2)
report += "**Тема:** Выбор бытовой техники. Стиральная машина\n\n"
report += "**Критерии оценки:**\n"
for i, criterion in enumerate(self.model.criteria, 1):
report += f"{i}. {criterion}\n"
report += "\n"
# Описание альтернатив
report += self.add_header("Описание альтернатив", 2)
descriptions = self.model.get_alternative_descriptions()
for desc in descriptions:
report += f"### {desc['name']}\n"
report += f"- **Цена:** {desc['price']}\n"
report += f"- **Качество стирки:** {desc['quality']}\n"
report += f"- **Энергоэффективность:** {desc['energy']}\n"
report += f"- **Уровень шума:** {desc['noise']}\n"
report += f"- **Вместимость:** {desc['capacity']}\n"
report += f"- **Дополнительные функции:** {desc['features']}\n\n"
# Матрицы парных сравнений
report += self.add_header("Матрицы парных сравнений", 2)
# Матрица критериев
report += self.add_header("Матрица парных сравнений критериев", 3)
report += self.add_matrix_table(
self.results['criteria_matrix'],
self.model.criteria,
self.model.criteria,
"Матрица сравнения критериев"
)
# Матрицы альтернатив
report += self.add_header("Матрицы парных сравнений альтернатив", 3)
for i, criterion in enumerate(self.model.criteria):
report += f"**По критерию: {criterion}**\n\n"
report += self.add_matrix_table(
self.results['alternative_matrices'][i],
self.model.alternatives,
self.model.alternatives,
f"Матрица сравнения альтернатив по критерию '{criterion}'"
)
# Результаты расчетов
report += self.add_header("Результаты расчетов", 2)
# Приоритеты критериев
report += self.add_header("Приоритеты критериев", 3)
criteria_table = []
for i, criterion in enumerate(self.model.criteria):
criteria_table.append([
criterion,
f"{self.results['criteria_priorities'][i]:.4f}"
])
report += self.add_table(criteria_table, ["Критерий", "Вес приоритета"])
# Согласованность критериев
consistency = self.results['criteria_consistency']
report += "**Проверка согласованности матрицы критериев:**\n"
report += f"- λ_max = {consistency['lambda_max']:.4f}\n"
report += f"- CI = {consistency['CI']:.4f}\n"
report += f"- RI = {consistency['RI']:.4f}\n"
report += f"- CR = {consistency['CR']:.4f}\n"
report += f"- **Согласованность:** {'✓ Приемлемая' if consistency['is_consistent'] else '✗ Неприемлемая'}\n\n"
# Приоритеты альтернатив по критериям
report += self.add_header("Локальные приоритеты альтернатив", 3)
for i, criterion in enumerate(self.model.criteria):
report += f"**По критерию: {criterion}**\n\n"
alt_table = []
for j, alternative in enumerate(self.model.alternatives):
alt_table.append([
alternative,
f"{self.results['alternative_priorities'][i][j]:.4f}"
])
report += self.add_table(alt_table, ["Альтернатива", "Локальный приоритет"])
# Согласованность
cons = self.results['alternative_consistencies'][i]
report += f"Согласованность: CR = {cons['CR']:.4f} ({'✓' if cons['is_consistent'] else '✗'})\n\n"
# Сводная таблица локальных приоритетов
report += self.add_header("Сводная таблица локальных приоритетов альтернатив", 3)
summary_headers = ["Альтернатива"] + self.model.criteria
summary_data = []
for i, alternative in enumerate(self.model.alternatives):
row = [alternative]
for j in range(len(self.model.criteria)):
row.append(f"{self.results['local_priorities_matrix'][i][j]:.4f}")
summary_data.append(row)
report += self.add_table(summary_data, summary_headers, "Матрица локальных приоритетов")
# Глобальные приоритеты
report += self.add_header("Вектор глобальных приоритетов", 3)
global_table = []
for i, alternative in enumerate(self.model.alternatives):
global_table.append([
alternative,
f"{self.results['global_priorities'][i]:.4f}",
"✓ ЛУЧШАЯ" if i == self.results['best_index'] else ""
])
report += self.add_table(global_table, ["Альтернатива", "Глобальный приоритет", "Рейтинг"])
# Вывод
report += self.add_header("Вывод", 2)
report += f"**Наилучшей альтернативой является:** {self.results['best_alternative']}\n\n"
report += f"**Обоснование:** Данная модель показала наивысший глобальный приоритет ({self.results['global_priorities'][self.results['best_index']]:.4f}) "
report += "среди всех рассмотренных альтернатив, что свидетельствует о ее превосходстве по совокупности оцениваемых критериев.\n\n"
# Исходный код
report += self.add_code_section()
return report
class AHPDocxReport:
"""Класс для генерации отчета в формате DOCX для ЛР5"""
def __init__(self, ahp_model: AHPModel, analysis_results: Dict[str, Any]):
self.model = ahp_model
self.results = analysis_results
def generate_docx_report(self, filename: str = "ahp_report.docx") -> str:
"""
Генерация отчёта в формате DOCX для метода анализа иерархий
"""
out_path = os.path.join("results", filename)
if not PYDOCX_AVAILABLE:
print("python-docx не установлен — DOCX отчёт не будет создан")
return out_path
try:
doc = Document()
# --- Заголовок лабораторной ---
doc.add_heading('Лабораторная работа №5: Метод анализа иерархий (МАИ)', level=1)
doc.add_paragraph('Выбор стиральной машины по 6 критериям')
doc.add_paragraph('Студент: Меркулов Алексей Дмитриевич')
doc.add_paragraph('') # пустая строка
# Цель работы
doc.add_heading('Цель работы', level=2)
doc.add_paragraph('Изучить принципы метода анализа иерархий. Произвести оценку и выбор наилучшей стиральной машины из 6 предложенных вариантов по 6 критериям, используя МАИ.')
# Описание задачи
doc.add_heading('Описание задачи', level=2)
doc.add_paragraph('Тема: Выбор бытовой техники. Стиральная машина')
doc.add_paragraph('Критерии оценки:')
for criterion in self.model.criteria:
doc.add_paragraph(criterion, style='List Bullet')
# Альтернативы
doc.add_heading('Описание альтернатив', level=2)
descriptions = self.model.get_alternative_descriptions()
for desc in descriptions:
doc.add_heading(desc['name'], level=3)
doc.add_paragraph(f"Цена: {desc['price']}")
doc.add_paragraph(f"Качество стирки: {desc['quality']}")
doc.add_paragraph(f"Энергоэффективность: {desc['energy']}")
doc.add_paragraph(f"Уровень шума: {desc['noise']}")
doc.add_paragraph(f"Вместимость: {desc['capacity']}")
doc.add_paragraph(f"Дополнительные функции: {desc['features']}")
# Матрицы парных сравнений
doc.add_heading('Матрицы парных сравнений', level=2)
# Матрица критериев
doc.add_heading('Матрица критериев', level=3)
table = doc.add_table(rows=len(self.model.criteria)+1, cols=len(self.model.criteria)+1)
# Заголовки
hdr_cells = table.rows[0].cells
hdr_cells[0].text = 'Критерий'
for j, criterion in enumerate(self.model.criteria, 1):
hdr_cells[j].text = criterion
# Данные
for i, criterion in enumerate(self.model.criteria, 1):
row_cells = table.rows[i].cells
row_cells[0].text = criterion
for j in range(len(self.model.criteria)):
row_cells[j+1].text = f"{self.results['criteria_matrix'][i-1][j]:.3f}"
# Результаты расчетов
doc.add_heading('Результаты расчетов', level=2)
# Приоритеты критериев
doc.add_heading('Приоритеты критериев', level=3)
for i, criterion in enumerate(self.model.criteria):
doc.add_paragraph(f"{criterion}: {self.results['criteria_priorities'][i]:.4f}")
# Согласованность
consistency = self.results['criteria_consistency']
doc.add_paragraph(f"Индекс согласованности (CI): {consistency['CI']:.4f}")
doc.add_paragraph(f"Отношение согласованности (CR): {consistency['CR']:.4f}")
doc.add_paragraph(f"Согласованность: {'Приемлемая' if consistency['is_consistent'] else 'Неприемлемая'}")
# Глобальные приоритеты
doc.add_heading('Глобальные приоритеты альтернатив', level=3)
for i, alternative in enumerate(self.model.alternatives):
marker = " ← ЛУЧШАЯ" if i == self.results['best_index'] else ""
doc.add_paragraph(f"{alternative}: {self.results['global_priorities'][i]:.4f}{marker}")
# Вывод
doc.add_heading('Вывод', level=2)
doc.add_paragraph(f"Наилучшей альтернативой является: {self.results['best_alternative']}")
doc.add_paragraph(f"Глобальный приоритет: {self.results['global_priorities'][self.results['best_index']]:.4f}")
# Исходный код
success_src, src_text = read_own_source()
doc.add_heading('Исходный код программы', level=2)
if success_src:
for line in src_text.splitlines():
p = doc.add_paragraph()
run = p.add_run(line)
try:
run.font.name = 'Courier New'
run.font.size = Pt(8)
except Exception:
pass
else:
doc.add_paragraph("Не удалось прочитать исходный код скрипта: " + src_text)
# Сохранение файла
doc.save(out_path)
print(f"DOCX-отчёт сохранён: {out_path}")
except Exception as e:
print(f"Ошибка при генерации DOCX-отчёта: {e}")
raise e
return out_path
def main():
"""Основная функция для выполнения лабораторной работы №5"""
# Создаем модель МАИ
ahp_model = AHPModel()
# Выполняем анализ
print("Выполняется анализ методом МАИ...")
results = ahp_model.analyze()
# Создаем папку для результатов
os.makedirs("results", exist_ok=True)
# Генерируем Markdown отчет
md_reporter = AHPMarkdownReport(ahp_model, results)
md_report = md_reporter.generate_report()
# Сохраняем Markdown отчет
with open("README.md", "w", encoding="utf-8") as f:
f.write(md_report)
print("Markdown отчет сохранен: README.md")
# Генерируем DOCX отчет
docx_reporter = AHPDocxReport(ahp_model, results)
docx_path = docx_reporter.generate_docx_report()
# Выводим основные результаты в консоль
print("\n=== РЕЗУЛЬТАТЫ АНАЛИЗА МЕТОДОМ МАИ ===")
print(f"Наилучшая альтернатива: {results['best_alternative']}")
print(f"Глобальный приоритет: {results['global_priorities'][results['best_index']]:.4f}")
print("\nРейтинг всех альтернатив:")
for i, alternative in enumerate(ahp_model.alternatives):
marker = " ← ЛУЧШАЯ" if i == results['best_index'] else ""
print(f"{i+1}. {alternative}: {results['global_priorities'][i]:.4f}{marker}")
print(f"\nСогласованность матрицы критериев: CR = {results['criteria_consistency']['CR']:.4f} "
f"({'Приемлемая' if results['criteria_consistency']['is_consistent'] else 'Неприемлемая'})")
print(f"\nОтчеты сохранены в папке results:")
print(f"- Markdown отчет: README.md")
if PYDOCX_AVAILABLE:
print(f"- DOCX отчет: {docx_path}")
return results
if __name__ == "__main__":
main()