- •Распределение классов прочности
- •Визуализация распределения классов прочности бетона
- •Анализ сбалансированных классов
- •Визуализация взаимосвязей между признаками
- •Предобработка данных
- •Разделение данных и масштабирование
- •Визуализация распределения признаков:
- •Метод kNn для классификации прочности бетона
- •Метод дерева решений для классификации прочности бетона
- •Обучение и оценка дерева решений для классификации бетона
- •Обучение и оценка дерева решений
- •Визуализация дерева решений
- •Кривые для оценки качества классификации бетона
- •Визуализация roc-кривых для классификации прочности бетона
Визуализация распределения признаков:
СТАТИСТИЧЕСКИЕ ХАРАКТЕРИСТИКИ ДО И ПОСЛЕ МАСШТАБИРОВАНИЯ:
Признак Исходное среднее Исходное ст.откл. После масштаб. среднее После масштаб. ст.откл.
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 мы наблюдаем классический случай переобучения: модель слишком чувствительна к шуму в данных.
