Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Lab3_3352_ГарееваКР.docx
Скачиваний:
0
Добавлен:
24.01.2026
Размер:
60.95 Mб
Скачать

Визуализация распределения признаков:

СТАТИСТИЧЕСКИЕ ХАРАКТЕРИСТИКИ ДО И ПОСЛЕ МАСШТАБИРОВАНИЯ:

Признак Исходное среднее Исходное ст.откл. После масштаб. среднее После масштаб. ст.откл.

Cement 279.29 102.20 -0.0 1.0

Blast Furnace Slag 75.58 86.46 0.0 1.0

Fly Ash 52.95 63.56 -0.0 1.0

Water 181.30 21.71 -0.0 1.0

Superplasticizer 6.25 5.98 0.0 1.0

Coarse Aggregate 972.07 77.39 0.0 1.0

Fine Aggregate 774.98 80.13 0.0 1.0

Age (day) 46.94 66.07 -0.0 1.0

ПРОВЕРКА КОРРЕКТНОСТИ РАЗДЕЛЕНИЯ:

Соотношение классов между выборками:

Класс 'Высокая':

Всего в датасете: 379 (36.8%)

Обучающая выборка: 265 (36.8%)

Тестовая выборка: 114 (36.9%)

Класс 'Низкая':

Всего в датасете: 295 (28.6%)

Обучающая выборка: 207 (28.7%)

Тестовая выборка: 88 (28.5%)

Класс 'Средняя':

Всего в датасете: 356 (34.6%)

Обучающая выборка: 249 (34.5%)

Тестовая выборка: 107 (34.6%)

СОХРАНЕНИЕ РАЗДЕЛЕННЫХ ДАННЫХ:

Обучающая выборка сохранена в train_df ((721, 10))

Тестовая выборка сохранена в test_df ((309, 10))

РАЗДЕЛЕНИЕ И МАСШТАБИРОВАНИЕ УСПЕШНО ЗАВЕРШЕНЫ!

Стандартизация: Применение StandardScaler успешно привело все числовые признаки к единому масштабу со средним 0 и стандартным отклонением 1, что является обязательным условием для корректной работы алгоритмов, чувствительных к масштабу данных (например, kNN).

Стратификация: Разделение на обучающую и тестовую выборки с параметром stratify=y выполнено идеально: распределение классов прочности во всех подвыборках совпадает с исходным с точностью до 0.2%. Это гарантирует, что оценка качества моделей будет репрезентативной и не смещённой.

Воспроизводимость: Все преобразованные данные сохранены в структурированные объекты (train_df, test_df), что завершает этап предобработки и обеспечивает чёткое разделение между подготовкой данных и моделированием.

Метод kNn для классификации прочности бетона

Программа:

k_range = range(1, 21)

train_scores = []

test_scores = []

print("Поиск оптимального количества соседей (k)...")

for k in k_range:

knn = KNeighborsClassifier(n_neighbors=k)

knn.fit(X_train_scaled, y_train)

train_score = knn.score(X_train_scaled, y_train)

test_score = knn.score(X_test_scaled, y_test)

train_scores.append(train_score)

test_scores.append(test_score)

if k % 5 == 0:

print(f" k={k:2d}: Train accuracy={train_score:.4f}, Test accuracy={test_score:.4f}")

plt.figure(figsize=(12, 6))

plt.subplot(1, 2, 1)

plt.plot(k_range, train_scores, label='Обучающая выборка', marker='o', linewidth=2, markersize=6, color='#FF6B6B')

plt.plot(k_range, test_scores, label='Тестовая выборка', marker='s', linewidth=2, markersize=6, color='#4ECDC4')

plt.xlabel('Количество соседей (k)', fontsize=12)

plt.ylabel('Accuracy', fontsize=12)

plt.title('Зависимость точности от количества соседей', fontsize=14, fontweight='bold')

plt.legend()

plt.grid(True, alpha=0.3)

plt.xticks(k_range[::2])

optimal_k = k_range[np.argmax(test_scores)]

optimal_score = test_scores[np.argmax(test_scores)]

plt.axvline(x=optimal_k, color='red', linestyle='--', alpha=0.7)

plt.scatter(optimal_k, optimal_score, color='red', s=100, zorder=5)

plt.text(optimal_k+0.5, optimal_score-0.05, f'k={optimal_k}\nAcc={optimal_score:.3f}',

fontweight='bold', bbox=dict(boxstyle='round', facecolor='white', alpha=0.8))

plt.subplot(1, 2, 2)

gap = [train - test for train, test in zip(train_scores, test_scores)]

plt.plot(k_range, gap, marker='o', linewidth=2, color='#45B7D1')

plt.fill_between(k_range, gap, alpha=0.3, color='#45B7D1')

plt.xlabel('Количество соседей (k)', fontsize=12)

plt.ylabel('Разность (Train - Test)', fontsize=12)

plt.title('Разрыв между обучающей и тестовой точностью', fontsize=14, fontweight='bold')

plt.grid(True, alpha=0.3)

plt.xticks(k_range[::2])

plt.axhline(y=0, color='black', linestyle='-', alpha=0.3)

plt.tight_layout()

plt.show()

print(f"\nРЕЗУЛЬТАТЫ ПОИСКА ОПТИМАЛЬНОГО k:")

print("-" * 40)

print(f"Оптимальное количество соседей: k = {optimal_k}")

print(f"Максимальная accuracy на тестовой выборке: {optimal_score:.4f}")

print(f"\nПри k={optimal_k}:")

print(f" Обучающая выборка: {train_scores[optimal_k-1]:.4f}")

print(f" Тестовая выборка: {test_scores[optimal_k-1]:.4f}")

print(f" Разница: {train_scores[optimal_k-1] - test_scores[optimal_k-1]:.4f}")

print(f"\nОБУЧЕНИЕ МОДЕЛИ kNN С k={optimal_k}:")

knn_model = KNeighborsClassifier(n_neighbors=optimal_k)

knn_model.fit(X_train_scaled, y_train)

y_pred_knn = knn_model.predict(X_test_scaled)

y_pred_proba_knn = knn_model.predict_proba(X_test_scaled)

accuracy_knn = accuracy_score(y_test, y_pred_knn)

precision_knn = precision_score(y_test, y_pred_knn, average='weighted')

recall_knn = recall_score(y_test, y_pred_knn, average='weighted')

f1_knn = f1_score(y_test, y_pred_knn, average='weighted')

print("\nМЕТРИКИ КАЧЕСТВА:")

print(f"Accuracy: {accuracy_knn:.4f}")

print(f"Precision: {precision_knn:.4f}")

print(f"Recall: {recall_knn:.4f}")

print(f"F1-Score: {f1_knn:.4f}")

print("\nДЕТАЛЬНЫЙ ОТЧЕТ ПО КЛАССАМ:")

print(classification_report(y_test, y_pred_knn,

target_names=[str(cls) for cls in le_strength.classes_]))

print("\nМАТРИЦА ОШИБОК:")

cm_knn = confusion_matrix(y_test, y_pred_knn)

cm_df_knn = pd.DataFrame(cm_knn,

index=[f'Истинный: {cls}' for cls in le_strength.classes_],

columns=[f'Предсказанный: {cls}' for cls in le_strength.classes_])

plt.figure(figsize=(8, 6))

sns.heatmap(cm_df_knn, annot=True, fmt='d', cmap='Blues', cbar=True,

square=True, linewidths=0.5, linecolor='gray')

plt.title(f'Матрица ошибок kNN (k={optimal_k})', fontsize=14, fontweight='bold')

plt.ylabel('Истинные классы', fontsize=12)

plt.xlabel('Предсказанные классы', fontsize=12)

plt.tight_layout()

plt.show()

print("\nАНАЛИЗ ПРЕДСКАЗАНИЙ:")

correct_predictions = (y_test == y_pred_knn)

incorrect_predictions = ~correct_predictions

print(f"Правильно классифицировано: {correct_predictions.sum()} из {len(y_test)} "

f"({correct_predictions.sum()/len(y_test)*100:.1f}%)")

print(f"Неправильно классифицировано: {incorrect_predictions.sum()} из {len(y_test)} "

f"({incorrect_predictions.sum()/len(y_test)*100:.1f}%)")

print("\nАНАЛИЗ ТОЧНОСТИ ПО КЛАССАМ:")

for cls_idx in range(len(le_strength.classes_)):

cls_name = le_strength.inverse_transform([cls_idx])[0]

cls_mask = (y_test == cls_idx)

if cls_mask.sum() > 0:

cls_correct = ((y_test == cls_idx) & (y_pred_knn == cls_idx)).sum()

cls_total = cls_mask.sum()

cls_accuracy = cls_correct / cls_total

print(f"Класс '{cls_name}':")

print(f" Всего образцов: {cls_total}")

print(f" Правильно классифицировано: {cls_correct} ({cls_accuracy:.1%})")

# Анализ ошибок для этого класса

if cls_total - cls_correct > 0:

incorrect_mask = (y_test == cls_idx) & (y_pred_knn != cls_idx)

incorrect_classes = y_pred_knn[incorrect_mask]

if len(incorrect_classes) > 0:

unique_incorrect, counts = np.unique(incorrect_classes, return_counts=True)

print(f" Ошибочно классифицировано как:")

for wrong_cls, count in zip(unique_incorrect, counts):

wrong_name = le_strength.inverse_transform([wrong_cls])[0]

percentage = count / cls_total * 100

print(f" '{wrong_name}': {count} ({percentage:.1f}%)")

print()

print("\nПРИМЕРЫ ПРЕДСКАЗАНИЙ (первые 10 тестовых образцов):")

for i in range(min(10, len(X_test_scaled))):

true_class = le_strength.inverse_transform([y_test.iloc[i]])[0] if hasattr(y_test, 'iloc') else le_strength.inverse_transform([y_test[i]])[0]

pred_class = le_strength.inverse_transform([y_pred_knn[i]])[0]

probabilities = y_pred_proba_knn[i]

print(f"\nОбразец {i+1}:")

print(f" Истинный класс: '{true_class}'")

print(f" Предсказанный класс: '{pred_class}'")

print(f" Вероятности классов:")

for cls_idx, prob in enumerate(probabilities):

cls_name = le_strength.inverse_transform([cls_idx])[0]

print(f" '{cls_name}': {prob:.2%}")

if true_class == pred_class:

print(f" Результат: Правильно")

else:

print(f" Результат: Ошибка")

Результаты:

МЕТОД k-БЛИЖАЙШИХ СОСЕДЕЙ (kNN) ДЛЯ КЛАССИФИКАЦИИ ПРОЧНОСТИ БЕТОНА

Поиск оптимального количества соседей (k)...

k= 5: Train accuracy=0.7864, Test accuracy=0.6893

k=10: Train accuracy=0.7351, Test accuracy=0.6893

k=15: Train accuracy=0.7032, Test accuracy=0.6958

k=20: Train accuracy=0.7032, Test accuracy=0.6926

Подбор гиперпараметра k для метода kNN выявил характерные проблемы алгоритма на данном наборе данных. Наблюдается ярко выраженное переобучение при малых значениях k (разница между обучающей и тестовой точностью достигает 10%). С увеличением числа соседей переобучение уменьшается, однако тестовая точность выходит на "плато" в районе 69-70%, что указывает на ограниченную способность модели kNN эффективно разделять классы прочности бетона на основе заданных признаков.

Максимальная достигнутая точность на тестовой выборке составила 69.6% (при k=15), что существенно выше случайного угадывания (33%), но недостаточно для практического применения. Данный результат позволяет предположить, что либо признаки требуют дополнительной инженерной обработки, либо для данной задачи более подходящими могут оказаться другие алгоритмы классификации, лучше учитывающие сложные взаимосвязи в данных.

РЕЗУЛЬТАТЫ ПОИСКА ОПТИМАЛЬНОГО k:

Оптимальное количество соседей: k = 1

Максимальная accuracy на тестовой выборке: 0.7508

При k=1:

Обучающая выборка: 0.9972

Тестовая выборка: 0.7508

Разница: 0.2464

ОБУЧЕНИЕ МОДЕЛИ kNN С k=1:

МЕТРИКИ КАЧЕСТВА:

Accuracy: 0.7508

Precision: 0.7586

Recall: 0.7508

F1-Score: 0.7533

ДЕТАЛЬНЫЙ ОТЧЕТ ПО КЛАССАМ:

precision recall f1-score support

Высокая 0.87 0.78 0.82 114

Низкая 0.75 0.77 0.76 88

Средняя 0.65 0.70 0.67 107

accuracy 0.75 309

macro avg 0.76 0.75 0.75 309

weighted avg 0.76 0.75 0.75 309

Несмотря на приемлемое абсолютное значение accuracy, выбор k=1 является методологической ошибкой. Полученные результаты (accuracy=0.75) следует рассматривать как верхнюю, но ненадёжную оценку потенциала kNN на этих данных. Для практического применения необходима модель с лучшим балансом между точностью и способностью к обобщению.

МАТРИЦА ОШИБОК:

АНАЛИЗ ПРЕДСКАЗАНИЙ:

Правильно классифицировано: 232 из 309 (75.1%)

Неправильно классифицировано: 77 из 309 (24.9%)

АНАЛИЗ ТОЧНОСТИ ПО КЛАССАМ:

Класс 'Высокая':

Всего образцов: 114

Правильно классифицировано: 89 (78.1%)

Ошибочно классифицировано как:

'Низкая': 2 (1.8%)

'Средняя': 23 (20.2%)

Класс 'Низкая':

Всего образцов: 88

Правильно классифицировано: 68 (77.3%)

Ошибочно классифицировано как:

'Высокая': 2 (2.3%)

'Средняя': 18 (20.5%)

Класс 'Средняя':

Всего образцов: 107

Правильно классифицировано: 75 (70.1%)

Ошибочно классифицировано как:

'Высокая': 11 (10.3%)

'Низкая': 21 (19.6%)

ПРИМЕРЫ ПРЕДСКАЗАНИЙ (первые 10 тестовых образцов):

Образец 1:

Истинный класс: 'Высокая'

Предсказанный класс: 'Средняя'

Вероятности классов:

'Высокая': 0.00%

'Низкая': 0.00%

'Средняя': 100.00%

Результат: Ошибка

Образец 2:

Истинный класс: 'Высокая'

Предсказанный класс: 'Высокая'

Вероятности классов:

'Высокая': 100.00%

'Низкая': 0.00%

'Средняя': 0.00%

Результат: Правильно

Образец 3:

Истинный класс: 'Средняя'

Предсказанный класс: 'Низкая'

Вероятности классов:

'Высокая': 0.00%

'Низкая': 100.00%

'Средняя': 0.00%

Результат: Ошибка

Образец 4:

Истинный класс: 'Высокая'

Предсказанный класс: 'Высокая'

Вероятности классов:

'Высокая': 100.00%

'Низкая': 0.00%

'Средняя': 0.00%

Результат: Правильно

Образец 5:

Истинный класс: 'Низкая'

Предсказанный класс: 'Низкая'

Вероятности классов:

'Высокая': 0.00%

'Низкая': 100.00%

'Средняя': 0.00%

Результат: Правильно

Образец 6:

Истинный класс: 'Средняя'

Предсказанный класс: 'Высокая'

Вероятности классов:

'Высокая': 100.00%

'Низкая': 0.00%

'Средняя': 0.00%

Результат: Ошибка

Образец 7:

Истинный класс: 'Средняя'

Предсказанный класс: 'Средняя'

Вероятности классов:

'Высокая': 0.00%

'Низкая': 0.00%

'Средняя': 100.00%

Результат: Правильно

Образец 8:

Истинный класс: 'Высокая'

Предсказанный класс: 'Высокая'

Вероятности классов:

'Высокая': 100.00%

'Низкая': 0.00%

'Средняя': 0.00%

Результат: Правильно

Образец 9:

Истинный класс: 'Высокая'

Предсказанный класс: 'Высокая'

Вероятности классов:

'Высокая': 100.00%

'Низкая': 0.00%

'Средняя': 0.00%

Результат: Правильно

Образец 10:

Истинный класс: 'Низкая'

Предсказанный класс: 'Низкая'

Вероятности классов:

'Высокая': 0.00%

'Низкая': 100.00%

'Средняя': 0.00%

Результат: Правильно

Промежуточный вывод:

Accuracy 75.1% — это приемлемый, но недостаточный для производственного применения результат. Для контроля качества бетона требуется точность выше 85-90%.

При k=1 мы наблюдаем классический случай переобучения: модель слишком чувствительна к шуму в данных.