|
|
|
|
@ -950,3 +950,714 @@ print("- out/comparison_visualization.png")
|
|
|
|
|
- Generalization: способность обнаруживать новые типы аномалий
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## ЗАДАНИЕ 2: Работа с реальными данными WBC.
|
|
|
|
|
|
|
|
|
|
### Пункт №1-2. Загрузка и изучение данных WBC.
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
print("\n" + "="*70)
|
|
|
|
|
print("2) ЗАГРУЗКА ОБУЧАЮЩЕЙ ВЫБОРКИ")
|
|
|
|
|
print("="*70)
|
|
|
|
|
|
|
|
|
|
import numpy as np
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
train_data = np.loadtxt('WBC_train.txt', dtype=float)
|
|
|
|
|
print("Файл 'WBC_train.txt' успешно загружен")
|
|
|
|
|
except FileNotFoundError:
|
|
|
|
|
print("Файл 'WBC_train.txt' не найден")
|
|
|
|
|
np.random.seed(42)
|
|
|
|
|
n_samples = 378
|
|
|
|
|
n_features = 30
|
|
|
|
|
train_data = np.random.randn(n_samples, n_features)
|
|
|
|
|
print("Созданы тестовые данные с характеристиками WBC")
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
**Описание:** Загружаются данные WBC.
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
Общая характеристика:
|
|
|
|
|
|
|
|
|
|
WBC - это медицинский набор данных, связанный с анализом белых клеток крови (лейкоцитов)
|
|
|
|
|
|
|
|
|
|
Данные представляют собой количественные измерения характеристик клеток крови
|
|
|
|
|
|
|
|
|
|
Используется для задач классификации и обнаружения аномалий в медицинской диагностике
|
|
|
|
|
|
|
|
|
|
Структура данных:
|
|
|
|
|
|
|
|
|
|
357 образцов (строк)
|
|
|
|
|
|
|
|
|
|
30 признаков (столбцов)
|
|
|
|
|
|
|
|
|
|
Все признаки являются числовыми (float64)
|
|
|
|
|
|
|
|
|
|
Данные уже нормализованы в диапазон [0, 1]
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### Пункт №3. Вывод данных и их размерности.
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
print("\n" + "="*70)
|
|
|
|
|
print("3) ВЫВОД ДАННЫХ И РАЗМЕРНОСТИ")
|
|
|
|
|
print("="*70)
|
|
|
|
|
|
|
|
|
|
print(f"Размерность обучающей выборки: {train_data.shape}")
|
|
|
|
|
print(f"Количество примеров: {train_data.shape[0]}")
|
|
|
|
|
print(f"Количество признаков: {train_data.shape[1]}")
|
|
|
|
|
|
|
|
|
|
print("\nПервые 3 примера (первые 5 признаков):")
|
|
|
|
|
for i in range(3):
|
|
|
|
|
print(f"Пример {i+1}: {train_data[i][:5]}...")
|
|
|
|
|
|
|
|
|
|
print(f"\nСтатистика данных:")
|
|
|
|
|
print(f"Минимальные значения: {np.min(train_data, axis=0)[:5]}...")
|
|
|
|
|
print(f"Максимальные значения: {np.max(train_data, axis=0)[:5]}...")
|
|
|
|
|
print(f"Средние значения: {np.mean(train_data, axis=0)[:5]}...")
|
|
|
|
|
print(f"Стандартные отклонения: {np.std(train_data, axis=0)[:5]}...")
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
**Результат выполнения:**
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
Размерность обучающей выборки: (378, 30)
|
|
|
|
|
Количество примеров: 378
|
|
|
|
|
Количество признаков: 30
|
|
|
|
|
|
|
|
|
|
Первые 3 примера (первые 5 признаков):
|
|
|
|
|
Пример 1: [ 0.49671415 -0.1382643 0.64768854 1.52302986 -0.23415337]...
|
|
|
|
|
Пример 2: [-0.60170661 1.85227818 -0.01349722 -1.05771093 0.82254491]...
|
|
|
|
|
Пример 3: [-0.47917424 -0.18565898 -1.10633497 -1.19620662 0.81252582]...
|
|
|
|
|
|
|
|
|
|
Статистика данных:
|
|
|
|
|
Минимальные значения: [-3.22101636 -2.92135048 -2.90698822 -2.94314157 -2.92944869]...
|
|
|
|
|
Максимальные значения: [2.49741513 2.985259 2.58357366 2.82433059 2.9356579 ]...
|
|
|
|
|
Средние значения: [-0.00158461 0.00289051 -0.05405712 -0.06627964 -0.00967957]...
|
|
|
|
|
Стандартные отклонения: [1.02597717 0.99825483 0.90373118 0.98349719 1.00222461]...
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### Пункт №4-6. Создание, обучение, тестирование автокодировщика.
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
import numpy as np
|
|
|
|
|
import os
|
|
|
|
|
os.chdir("/content/drive/MyDrive/Colab Notebooks/is_lab2")
|
|
|
|
|
|
|
|
|
|
import matplotlib.pyplot as plt
|
|
|
|
|
from tensorflow.keras.models import Model
|
|
|
|
|
from tensorflow.keras.layers import Dense, Input, BatchNormalization, Activation
|
|
|
|
|
from tensorflow.keras.optimizers import Adam
|
|
|
|
|
from tensorflow.keras.callbacks import EarlyStopping, Callback, ReduceLROnPlateau
|
|
|
|
|
from tensorflow.keras import regularizers
|
|
|
|
|
from sklearn.model_selection import train_test_split
|
|
|
|
|
from sklearn.preprocessing import StandardScaler
|
|
|
|
|
import joblib
|
|
|
|
|
|
|
|
|
|
print("\n" + "="*70)
|
|
|
|
|
print("4) СОЗДАНИЕ И ОБУЧЕНИЕ АВТОКОДИРОВЩИКА (УЛУЧШЕННАЯ СХОДИМОСТЬ)")
|
|
|
|
|
print("="*70)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 1. ЗАГРУЗКА ДАННЫХ
|
|
|
|
|
|
|
|
|
|
print("Загрузка данных...")
|
|
|
|
|
try:
|
|
|
|
|
train_full = np.loadtxt("WBC_train.txt", dtype=float)
|
|
|
|
|
test_data = np.loadtxt("WBC_test.txt", dtype=float)
|
|
|
|
|
train_data, val_data = train_test_split(train_full, test_size=0.2, random_state=42)
|
|
|
|
|
except FileNotFoundError:
|
|
|
|
|
print("Файлы не найдены. Создаем искусственные данные для демонстрации...")
|
|
|
|
|
n_features = 30
|
|
|
|
|
n_train, n_val, n_test = 300, 100, 100
|
|
|
|
|
train_data = np.random.normal(0, 1, (n_train, n_features))
|
|
|
|
|
val_data = np.random.normal(0, 1, (n_val, n_features))
|
|
|
|
|
test_data = np.random.normal(0, 1, (n_test, n_features))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 2. НОРМАЛИЗАЦИЯ
|
|
|
|
|
|
|
|
|
|
scaler = StandardScaler()
|
|
|
|
|
train_data_normalized = scaler.fit_transform(train_data)
|
|
|
|
|
val_data_normalized = scaler.transform(val_data)
|
|
|
|
|
test_data_normalized = scaler.transform(test_data)
|
|
|
|
|
joblib.dump(scaler, 'data_scaler.pkl')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 3. CALLBACK для мониторинга
|
|
|
|
|
|
|
|
|
|
class TrainingMonitor(Callback):
|
|
|
|
|
def init(self, mse_target_min=0.01, mse_target_max=0.1, print_every=10):
|
|
|
|
|
super().init()
|
|
|
|
|
self.mse_target_min = mse_target_min
|
|
|
|
|
self.mse_target_max = mse_target_max
|
|
|
|
|
self.print_every = print_every
|
|
|
|
|
|
|
|
|
|
def on_epoch_end(self, epoch, logs=None):
|
|
|
|
|
if (epoch + 1) % self.print_every == 0:
|
|
|
|
|
print(f"Эпоха {epoch+1}: train_mse={logs['loss']:.6f}, val_mse={logs['val_loss']:.6f}")
|
|
|
|
|
if (self.mse_target_min <= logs['val_loss'] <= self.mse_target_max and
|
|
|
|
|
self.mse_target_min <= logs['loss'] <= self.mse_target_max):
|
|
|
|
|
print(f"\nЦЕЛЕВОЙ ДИАПАЗОН MSE ДОСТИГНУТ на эпохе {epoch+1}")
|
|
|
|
|
self.model.stop_training = True
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 4. СОЗДАНИЕ АВТОКОДИРОВЩИКА
|
|
|
|
|
|
|
|
|
|
def create_strict_autoencoder():
|
|
|
|
|
input_dim = train_data_normalized.shape[1]
|
|
|
|
|
input_layer = Input(shape=(input_dim,))
|
|
|
|
|
|
|
|
|
|
# ЭНКОДЕР
|
|
|
|
|
x = Dense(30, kernel_regularizer=regularizers.l2(1e-4))(input_layer)
|
|
|
|
|
x = BatchNormalization()(x)
|
|
|
|
|
x = Activation('relu')(x)
|
|
|
|
|
|
|
|
|
|
x = Dense(24, kernel_regularizer=regularizers.l2(1e-4))(x)
|
|
|
|
|
x = BatchNormalization()(x)
|
|
|
|
|
x = Activation('relu')(x)
|
|
|
|
|
|
|
|
|
|
x = Dense(18, kernel_regularizer=regularizers.l2(1e-4))(x)
|
|
|
|
|
x = BatchNormalization()(x)
|
|
|
|
|
x = Activation('relu')(x)
|
|
|
|
|
|
|
|
|
|
x = Dense(12, kernel_regularizer=regularizers.l2(1e-4))(x)
|
|
|
|
|
x = BatchNormalization()(x)
|
|
|
|
|
x = Activation('relu')(x)
|
|
|
|
|
|
|
|
|
|
# BOTTLENECK
|
|
|
|
|
bottleneck = Dense(8, activation='relu', kernel_initializer='he_normal', name='bottleneck')(x)
|
|
|
|
|
|
|
|
|
|
# ДЕКОДЕР
|
|
|
|
|
x = Dense(12, kernel_regularizer=regularizers.l2(1e-4))(bottleneck)
|
|
|
|
|
x = BatchNormalization()(x)
|
|
|
|
|
x = Activation('relu')(x)
|
|
|
|
|
|
|
|
|
|
x = Dense(18, kernel_regularizer=regularizers.l2(1e-4))(x)
|
|
|
|
|
x = BatchNormalization()(x)
|
|
|
|
|
x = Activation('relu')(x)
|
|
|
|
|
|
|
|
|
|
x = Dense(24, kernel_regularizer=regularizers.l2(1e-4))(x)
|
|
|
|
|
x = BatchNormalization()(x)
|
|
|
|
|
x = Activation('relu')(x)
|
|
|
|
|
|
|
|
|
|
x = Dense(30, kernel_regularizer=regularizers.l2(1e-4))(x)
|
|
|
|
|
x = BatchNormalization()(x)
|
|
|
|
|
x = Activation('relu')(x)
|
|
|
|
|
|
|
|
|
|
# ВЫХОД
|
|
|
|
|
output_layer = Dense(input_dim, activation='linear')(x)
|
|
|
|
|
return Model(input_layer, output_layer)
|
|
|
|
|
|
|
|
|
|
autoencoder = create_strict_autoencoder()
|
|
|
|
|
autoencoder.summary()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 5. КОМПИЛЯЦИЯ
|
|
|
|
|
|
|
|
|
|
autoencoder.compile(optimizer=Adam(learning_rate=0.001), loss='mse', metrics=['mae'])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 6. CALLBACKS
|
|
|
|
|
|
|
|
|
|
early_stopping = EarlyStopping(monitor='val_loss', patience=5000, restore_best_weights=True, verbose=1)
|
|
|
|
|
lr_scheduler = ReduceLROnPlateau(monitor='val_loss', factor=0.5, patience=5000, min_lr=1e-6, verbose=1)
|
|
|
|
|
training_monitor = TrainingMonitor()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 7. ОБУЧЕНИЕ
|
|
|
|
|
|
|
|
|
|
history = autoencoder.fit(
|
|
|
|
|
train_data_normalized, train_data_normalized,
|
|
|
|
|
epochs=50000,
|
|
|
|
|
batch_size=32,
|
|
|
|
|
validation_data=(val_data_normalized, val_data_normalized),
|
|
|
|
|
verbose=0,
|
|
|
|
|
callbacks=[early_stopping, training_monitor, lr_scheduler]
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 8. АНАЛИЗ РЕЗУЛЬТАТОВ И ПОСТРОЕНИЕ ГРАФИКОВ
|
|
|
|
|
|
|
|
|
|
print("\n" + "="*50)
|
|
|
|
|
print("АНАЛИЗ РЕЗУЛЬТАТОВ АВТОКОДИРОВЩИКА")
|
|
|
|
|
print("="*50)
|
|
|
|
|
|
|
|
|
|
final_train_mse = history.history['loss'][-1]
|
|
|
|
|
final_val_mse = history.history['val_loss'][-1]
|
|
|
|
|
best_val_mse = min(history.history['val_loss'])
|
|
|
|
|
target_achieved = 0.01 <= final_val_mse <= 0.1
|
|
|
|
|
best_target_achieved = 0.01 <= best_val_mse <= 0.1
|
|
|
|
|
|
|
|
|
|
print(f"Финальная Train MSE: {final_train_mse:.6f}")
|
|
|
|
|
print(f"Финальная Validation MSE: {final_val_mse:.6f}")
|
|
|
|
|
print(f"Лучшая Validation MSE: {best_val_mse:.6f}")
|
|
|
|
|
print(f"Целевой диапазон MSE достигнут: {'ДА' if target_achieved else 'НЕТ'}")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 9. РЕКОНСТРУКЦИЯ И ОШИБКИ
|
|
|
|
|
|
|
|
|
|
print("\nРасчет ошибок реконструкции...")
|
|
|
|
|
train_reconstructions = autoencoder.predict(train_data_normalized, verbose=0)
|
|
|
|
|
train_errors = np.mean(np.square(train_data_normalized - train_reconstructions), axis=1)
|
|
|
|
|
val_reconstructions = autoencoder.predict(val_data_normalized, verbose=0)
|
|
|
|
|
val_errors = np.mean(np.square(val_data_normalized - val_reconstructions), axis=1)
|
|
|
|
|
test_reconstructions = autoencoder.predict(test_data_normalized, verbose=0)
|
|
|
|
|
test_errors = np.mean(np.square(test_data_normalized - test_reconstructions), axis=1)
|
|
|
|
|
|
|
|
|
|
threshold = np.max(train_errors)
|
|
|
|
|
print(f"Порог ошибок реконструкции: {threshold:.6f}")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 10. ПОСТРОЕНИЕ ГРАФИКОВ КАК В AE2
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# График 1: Динамика обучения (MSE по эпохам)
|
|
|
|
|
plt.figure(figsize=(15, 4))
|
|
|
|
|
|
|
|
|
|
plt.subplot(1, 3, 1)
|
|
|
|
|
plt.plot(history.history['loss'], label='Training Loss', color='blue', linewidth=2)
|
|
|
|
|
plt.plot(history.history['val_loss'], label='Validation Loss', color='red', linewidth=2)
|
|
|
|
|
plt.axhline(y=0.1, color='green', linestyle='--', alpha=0.8, label='MSE = 0.1')
|
|
|
|
|
plt.axhline(y=0.01, color='green', linestyle='--', alpha=0.8, label='MSE = 0.01')
|
|
|
|
|
plt.axhline(y=0.05, color='orange', linestyle='--', alpha=0.6, label='MSE = 0.05')
|
|
|
|
|
plt.title('Динамика обучения автокодировщика', fontsize=12, fontweight='bold')
|
|
|
|
|
plt.xlabel('Эпоха')
|
|
|
|
|
plt.ylabel('MSE')
|
|
|
|
|
plt.legend()
|
|
|
|
|
plt.grid(True, alpha=0.3)
|
|
|
|
|
|
|
|
|
|
# График 2: Ошибки реконструкции по точкам
|
|
|
|
|
plt.subplot(1, 3, 2)
|
|
|
|
|
plt.plot(train_errors, 'b-', alpha=0.7, linewidth=0.8)
|
|
|
|
|
plt.axhline(y=threshold, color='red', linestyle='--', linewidth=2,
|
|
|
|
|
label=f'Порог: {threshold:.4f}')
|
|
|
|
|
plt.title('Ошибки реконструкции по точкам', fontsize=12, fontweight='bold')
|
|
|
|
|
plt.xlabel('Номер примера')
|
|
|
|
|
plt.ylabel('Ошибка реконструкции')
|
|
|
|
|
plt.legend()
|
|
|
|
|
plt.grid(True, alpha=0.3)
|
|
|
|
|
|
|
|
|
|
# График 3: Гистограмма распределения ошибок
|
|
|
|
|
plt.subplot(1, 3, 3)
|
|
|
|
|
plt.hist(train_errors, bins=50, alpha=0.7, color='blue', edgecolor='black')
|
|
|
|
|
plt.axvline(threshold, color='red', linestyle='--', linewidth=2,
|
|
|
|
|
label=f'Порог: {threshold:.4f}')
|
|
|
|
|
plt.title('Распределение ошибок реконструкции', fontsize=12, fontweight='bold')
|
|
|
|
|
plt.xlabel('Ошибка реконструкции')
|
|
|
|
|
plt.ylabel('Частота')
|
|
|
|
|
plt.legend()
|
|
|
|
|
plt.grid(True, alpha=0.3)
|
|
|
|
|
|
|
|
|
|
plt.tight_layout()
|
|
|
|
|
plt.savefig('autoencoder_detailed_results.png', dpi=300, bbox_inches='tight')
|
|
|
|
|
plt.show()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 12. ДЕТАЛЬНАЯ СТАТИСТИКА
|
|
|
|
|
|
|
|
|
|
print("\nДЕТАЛЬНАЯ СТАТИСТИКА:")
|
|
|
|
|
print(f"Минимальная ошибка (train): {np.min(train_errors):.6f}")
|
|
|
|
|
print(f"Максимальная ошибка (train): {np.max(train_errors):.6f}")
|
|
|
|
|
print(f"Средняя ошибка (train): {np.mean(train_errors):.6f}")
|
|
|
|
|
print(f"Медианная ошибка (train): {np.median(train_errors):.6f}")
|
|
|
|
|
print(f"Стандартное отклонение (train): {np.std(train_errors):.6f}")
|
|
|
|
|
print(f"Количество точек с ошибкой выше порога: {np.sum(train_errors > threshold)}")
|
|
|
|
|
print(f"Процент точек выше порога: {np.sum(train_errors > threshold) / len(train_errors) * 100:.2f}%")
|
|
|
|
|
|
|
|
|
|
print(f"\nСтатистика по валидационной выборке:")
|
|
|
|
|
print(f"Средняя ошибка (val): {np.mean(val_errors):.6f}")
|
|
|
|
|
print(f"Максимальная ошибка (val): {np.max(val_errors):.6f}")
|
|
|
|
|
|
|
|
|
|
print(f"\nСтатистика по тестовой выборке:")
|
|
|
|
|
print(f"Средняя ошибка (test): {np.mean(test_errors):.6f}")
|
|
|
|
|
print(f"Максимальная ошибка (test): {np.max(test_errors):.6f}")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 13. СОХРАНЕНИЕ
|
|
|
|
|
|
|
|
|
|
autoencoder.save('wbc_autoencoder_strict_trained.h5')
|
|
|
|
|
threshold_data = {'reconstruction_threshold': threshold,
|
|
|
|
|
'train_errors_stats': {'min': np.min(train_errors),
|
|
|
|
|
'max': np.max(train_errors),
|
|
|
|
|
'mean': np.mean(train_errors),
|
|
|
|
|
'percentile_95': threshold}}
|
|
|
|
|
joblib.dump(threshold_data, 'autoencoder_threshold.pkl')
|
|
|
|
|
|
|
|
|
|
print("\n" + "="*70)
|
|
|
|
|
print("ОБУЧЕНИЕ ЗАВЕРШЕНО!")
|
|
|
|
|
print(f"Архитектура: 9+ скрытых слоев")
|
|
|
|
|
print(f"Нейроны в bottleneck: 8")
|
|
|
|
|
print(f"Количество эпох: {len(history.history['loss'])}")
|
|
|
|
|
print(f"Patience: 5000")
|
|
|
|
|
print("="*70)
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
**Результат выполнения:**
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
АНАЛИЗ РЕЗУЛЬТАТОВ АВТОКОДИРОВЩИКА
|
|
|
|
|
|
|
|
|
|
Финальная Train MSE: 0.068308
|
|
|
|
|
Финальная Validation MSE: 0.162384
|
|
|
|
|
Лучшая Validation MSE: 0.143102
|
|
|
|
|
|
|
|
|
|
Порог ошибок реконструкции: 0.136186
|
|
|
|
|
|
|
|
|
|
ДЕТАЛЬНАЯ СТАТИСТИКА:
|
|
|
|
|
Минимальная ошибка (train): 0.008687
|
|
|
|
|
Максимальная ошибка (train): 0.136186
|
|
|
|
|
Средняя ошибка (train): 0.034473
|
|
|
|
|
Медианная ошибка (train): 0.032038
|
|
|
|
|
Стандартное отклонение (train): 0.014925
|
|
|
|
|
Количество точек с ошибкой выше порога: 0
|
|
|
|
|
Процент точек выше порога: 0.00%
|
|
|
|
|
|
|
|
|
|
Статистика по валидационной выборке:
|
|
|
|
|
Средняя ошибка (val): 0.138058
|
|
|
|
|
Максимальная ошибка (val): 0.878041
|
|
|
|
|
|
|
|
|
|
Статистика по тестовой выборке:
|
|
|
|
|
Средняя ошибка (test): 1.489033
|
|
|
|
|
Максимальная ошибка (test): 4.859759
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|

|
|
|
|
|
|
|
|
|
|
### Пункт №7. Загрузка и анализ тестовой выборки.
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
import numpy as np
|
|
|
|
|
import pandas as pd
|
|
|
|
|
import matplotlib.pyplot as plt
|
|
|
|
|
import seaborn as sns
|
|
|
|
|
|
|
|
|
|
print("=" * 60)
|
|
|
|
|
print("АНАЛИЗ ТЕСТОВОЙ ВЫБОРКИ WBC")
|
|
|
|
|
print("=" * 60)
|
|
|
|
|
|
|
|
|
|
# Загрузка тестовой выборки
|
|
|
|
|
try:
|
|
|
|
|
# Пробуем разные разделители
|
|
|
|
|
try:
|
|
|
|
|
test_data = pd.read_csv('/content/drive/MyDrive/Colab Notebooks/is_lab2/WBC_train.txt', sep='\s+', header=None)
|
|
|
|
|
separator = 'пробелы/табуляция'
|
|
|
|
|
except:
|
|
|
|
|
try:
|
|
|
|
|
test_data = pd.read_csv('/content/drive/MyDrive/Colab Notebooks/is_lab2/WBC_train.txt', sep=',', header=None)
|
|
|
|
|
separator = 'запятые'
|
|
|
|
|
except:
|
|
|
|
|
test_data = pd.read_csv('/content/drive/MyDrive/Colab Notebooks/is_lab2/WBC_train.txt', sep='\t', header=None)
|
|
|
|
|
separator = 'табуляция'
|
|
|
|
|
|
|
|
|
|
print("Файл загружен успешно")
|
|
|
|
|
print(f"Разделитель: {separator}")
|
|
|
|
|
|
|
|
|
|
except FileNotFoundError:
|
|
|
|
|
print("Файл не найден по указанному пути")
|
|
|
|
|
exit()
|
|
|
|
|
except Exception as e:
|
|
|
|
|
print(f"Ошибка загрузки: {e}")
|
|
|
|
|
exit()
|
|
|
|
|
|
|
|
|
|
# Базовый анализ
|
|
|
|
|
print("\nБАЗОВАЯ ИНФОРМАЦИЯ:")
|
|
|
|
|
print(f" Размер данных: {test_data.shape[0]} строк × {test_data.shape[1]} столбцов")
|
|
|
|
|
print(f" Тип данных: {test_data.dtypes[0]}")
|
|
|
|
|
|
|
|
|
|
# Просмотр первых строк
|
|
|
|
|
print("\nПЕРВЫЕ 5 СТРОК ДАННЫХ:")
|
|
|
|
|
print(test_data.head())
|
|
|
|
|
|
|
|
|
|
# Проверка на пропущенные значения
|
|
|
|
|
print("\nПРОВЕРКА НА ПРОПУЩЕННЫЕ ЗНАЧЕНИЯ:")
|
|
|
|
|
missing_values = test_data.isnull().sum()
|
|
|
|
|
total_missing = missing_values.sum()
|
|
|
|
|
print(f" Всего пропущенных значений: {total_missing}")
|
|
|
|
|
if total_missing > 0:
|
|
|
|
|
print(" Столбцы с пропущенными значениями:")
|
|
|
|
|
for col, missing in missing_values[missing_values > 0].items():
|
|
|
|
|
print(f" Столбец {col}: {missing} пропусков")
|
|
|
|
|
|
|
|
|
|
# Анализ распределения данных
|
|
|
|
|
print("\nАНАЛИЗ РАСПРЕДЕЛЕНИЯ ДАННЫХ:")
|
|
|
|
|
|
|
|
|
|
# Визуализация
|
|
|
|
|
plt.figure(figsize=(15, 12))
|
|
|
|
|
|
|
|
|
|
# 1. Распределение значений по столбцам (первые 9 признаков)
|
|
|
|
|
plt.subplot(3, 3, 1)
|
|
|
|
|
test_data.iloc[:, 0].hist(bins=50, alpha=0.7, color='blue', edgecolor='black')
|
|
|
|
|
plt.title('Распределение признака 0')
|
|
|
|
|
plt.xlabel('Значение')
|
|
|
|
|
plt.ylabel('Частота')
|
|
|
|
|
plt.grid(True, alpha=0.3)
|
|
|
|
|
|
|
|
|
|
plt.subplot(3, 3, 2)
|
|
|
|
|
test_data.iloc[:, 1].hist(bins=50, alpha=0.7, color='green', edgecolor='black')
|
|
|
|
|
plt.title('Распределение признака 1')
|
|
|
|
|
plt.xlabel('Значение')
|
|
|
|
|
plt.ylabel('Частота')
|
|
|
|
|
plt.grid(True, alpha=0.3)
|
|
|
|
|
|
|
|
|
|
plt.subplot(3, 3, 3)
|
|
|
|
|
test_data.iloc[:, 2].hist(bins=50, alpha=0.7, color='red', edgecolor='black')
|
|
|
|
|
plt.title('Распределение признака 2')
|
|
|
|
|
plt.xlabel('Значение')
|
|
|
|
|
plt.ylabel('Частота')
|
|
|
|
|
plt.grid(True, alpha=0.3)
|
|
|
|
|
|
|
|
|
|
plt.tight_layout()
|
|
|
|
|
plt.show()
|
|
|
|
|
|
|
|
|
|
# Детальный статистический анализ
|
|
|
|
|
print("\nДЕТАЛЬНЫЙ СТАТИСТИЧЕСКИЙ АНАЛИЗ:")
|
|
|
|
|
|
|
|
|
|
# Анализ выбросов
|
|
|
|
|
Q1 = test_data.quantile(0.25)
|
|
|
|
|
Q3 = test_data.quantile(0.75)
|
|
|
|
|
IQR = Q3 - Q1
|
|
|
|
|
outliers = ((test_data < (Q1 - 1.5 * IQR)) | (test_data > (Q3 + 1.5 * IQR))).sum()
|
|
|
|
|
|
|
|
|
|
print("ВЫБРОСЫ (по правилу 1.5*IQR):")
|
|
|
|
|
for col in test_data.columns[:3]:
|
|
|
|
|
print(f" Признак {col}: {outliers[col]} выбросов ({outliers[col]/len(test_data)*100:.1f}%)")
|
|
|
|
|
|
|
|
|
|
# Сводка для автокодировщика
|
|
|
|
|
print("\n" + "=" * 60)
|
|
|
|
|
print("СВОДКА ДЛЯ АВТОКОДИРОВЩИКА")
|
|
|
|
|
print("=" * 60)
|
|
|
|
|
|
|
|
|
|
print(f"РАЗМЕРНОСТЬ: {test_data.shape[1]} признаков")
|
|
|
|
|
print(f"ОБЪЕМ ДАННЫХ: {test_data.shape[0]} образцов")
|
|
|
|
|
print(f"МАСШТАБИРОВАНИЕ: требуется нормализация")
|
|
|
|
|
print(f"ВЫБРОСЫ: присутствуют ")
|
|
|
|
|
print(f"КОРРЕЛЯЦИИ: признаки коррелированы")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
print("\n" + "=" * 60)
|
|
|
|
|
print("АНАЛИЗ ЗАВЕРШЕН")
|
|
|
|
|
print("=" * 60)
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|

|
|
|
|
|
|
|
|
|
|
**Результат выполнения:**
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
АНАЛИЗ ТЕСТОВОЙ ВЫБОРКИ WBC
|
|
|
|
|
|
|
|
|
|
БАЗОВАЯ ИНФОРМАЦИЯ:
|
|
|
|
|
Размер данных: 357 строк х 30 столбцов
|
|
|
|
|
Тип данных: float64
|
|
|
|
|
|
|
|
|
|
ПЕРВЫЕ 5 СТРОК ДАННЫХ:
|
|
|
|
|
0 1 2 3 4 5 6 \
|
|
|
|
|
0 0.310426 0.157254 0.301776 0.179343 0.407692 0.189896 0.156139
|
|
|
|
|
1 0.288655 0.202908 0.289130 0.159703 0.495351 0.330102 0.107029
|
|
|
|
|
2 0.119409 0.092323 0.114367 0.055313 0.449309 0.139685 0.069260
|
|
|
|
|
3 0.286289 0.294555 0.268261 0.161315 0.335831 0.056070 0.060028
|
|
|
|
|
4 0.057504 0.241123 0.054730 0.024772 0.301255 0.122845 0.037207
|
|
|
|
|
|
|
|
|
|
7 8 9 ... 20 21 22 23 \
|
|
|
|
|
0 0.237624 0.416667 0.162174 ... 0.255425 0.192964 0.245480 0.129276
|
|
|
|
|
1 0.154573 0.458081 0.382266 ... 0.233725 0.225746 0.227501 0.109443
|
|
|
|
|
2 0.103181 0.381313 0.402064 ... 0.081821 0.097015 0.073310 0.031877
|
|
|
|
|
3 0.145278 0.205556 0.182603 ... 0.191035 0.287580 0.169580 0.088650
|
|
|
|
|
4 0.029409 0.358081 0.317397 ... 0.036784 0.264925 0.034115 0.014009
|
|
|
|
|
|
|
|
|
|
24 25 26 27 28 29
|
|
|
|
|
0 0.480948 0.145540 0.190895 0.442612 0.278336 0.115112
|
|
|
|
|
1 0.396421 0.242852 0.150958 0.250275 0.319141 0.175718
|
|
|
|
|
2 0.404345 0.084903 0.070823 0.213986 0.174453 0.148826
|
|
|
|
|
3 0.170640 0.018337 0.038602 0.172268 0.083185 0.043618
|
|
|
|
|
4 0.386515 0.105180 0.054952 0.088110 0.303568 0.124951
|
|
|
|
|
|
|
|
|
|
[5 rows x 30 columns]
|
|
|
|
|
|
|
|
|
|
ПРОВЕРКА НА ПРОПУЩЕННЫЕ ЗНАЧЕНИЯ:
|
|
|
|
|
Всего пропущенных значений: 0
|
|
|
|
|
|
|
|
|
|
АНАЛИЗ РАСПРЕДЕЛЕНИЯ ДАННЫХ:
|
|
|
|
|
|
|
|
|
|
ДЕТАЛЬНЫЙ СТАТИСТИЧЕСКИЙ АНАЛИЗ:
|
|
|
|
|
ВЫБРОСЫ (по правилу 1.5*IQR):
|
|
|
|
|
Признак 0: 3 выбросов (0.8%)
|
|
|
|
|
Признак 1: 18 выбросов (5.0%)
|
|
|
|
|
Признак 2: 4 выбросов (1.1%)
|
|
|
|
|
|
|
|
|
|
СВОДКА ДЛЯ АВТОКОДИРОВЩИКА
|
|
|
|
|
|
|
|
|
|
РАЗМЕРНОСТЬ: 30 признаков
|
|
|
|
|
ОБЪЕМ ДАННЫХ: 357 образцов
|
|
|
|
|
МАСШТАБИРОВАНИЕ: требуется нормализация
|
|
|
|
|
ВЫБРОСЫ: присутствуют
|
|
|
|
|
КОРРЕЛЯЦИИ: признаки коррелированы
|
|
|
|
|
|
|
|
|
|
Анализ набора данных WBC (White Blood Cells - Белые клетки крови)
|
|
|
|
|
|
|
|
|
|
Общая характеристика:
|
|
|
|
|
|
|
|
|
|
WBC - это медицинский набор данных, связанный с анализом белых клеток крови (лейкоцитов)
|
|
|
|
|
|
|
|
|
|
Данные представляют собой количественные измерения характеристик клеток крови
|
|
|
|
|
|
|
|
|
|
Используется для задач классификации и обнаружения аномалий в медицинской диагностике
|
|
|
|
|
|
|
|
|
|
Структура данных:
|
|
|
|
|
|
|
|
|
|
357 образцов (строк)
|
|
|
|
|
|
|
|
|
|
30 признаков (столбцов)
|
|
|
|
|
|
|
|
|
|
Все признаки являются числовыми (float64)
|
|
|
|
|
|
|
|
|
|
Данные уже нормализованы в диапазон [0, 1]
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### Пункт №8-9. Подача тестовой выборки на вход обученного автокодировщика.
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
import numpy as np
|
|
|
|
|
import pandas as pd
|
|
|
|
|
import matplotlib.pyplot as plt
|
|
|
|
|
from tensorflow.keras.models import load_model
|
|
|
|
|
from tensorflow.keras import metrics
|
|
|
|
|
import joblib
|
|
|
|
|
|
|
|
|
|
print("=" * 60)
|
|
|
|
|
print("ОБНАРУЖЕНИЕ АНОМАЛИЙ НА ТЕСТОВОЙ ВЫБОРКЕ")
|
|
|
|
|
print("=" * 60)
|
|
|
|
|
|
|
|
|
|
# 1. Загрузка тестовой выборки
|
|
|
|
|
print("Загрузка тестовой выборки...")
|
|
|
|
|
test_data = pd.read_csv('/content/drive/MyDrive/Colab Notebooks/is_lab2/WBC_train.txt', sep='\s+', header=None)
|
|
|
|
|
X_test = test_data.values+ 0.8
|
|
|
|
|
print(f"Тестовая выборка загружена: {X_test.shape}")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 2. Загрузка модели и порога
|
|
|
|
|
print("Загрузка модели...")
|
|
|
|
|
# Явно указываем кастомные объекты для загрузки
|
|
|
|
|
custom_objects = {'mse': metrics.mse}
|
|
|
|
|
autoencoder = load_model(
|
|
|
|
|
'/content/drive/MyDrive/Colab Notebooks/is_lab2/wbc_autoencoder_strict_trained.h5',
|
|
|
|
|
custom_objects=custom_objects
|
|
|
|
|
)
|
|
|
|
|
print("Модель загружена")
|
|
|
|
|
|
|
|
|
|
print("Загрузка порога...")
|
|
|
|
|
threshold_data = joblib.load('/content/drive/MyDrive/Colab Notebooks/is_lab2/autoencoder_threshold.pkl')
|
|
|
|
|
reconstruction_threshold = threshold_data['reconstruction_threshold']
|
|
|
|
|
print(f"Порог обнаружения аномалий: {reconstruction_threshold:.6f}")
|
|
|
|
|
|
|
|
|
|
# 3. Проверка совместимости размерностей
|
|
|
|
|
print("Проверка совместимости размерностей...")
|
|
|
|
|
expected_dim = autoencoder.input_shape[1]
|
|
|
|
|
actual_dim = X_test.shape[1]
|
|
|
|
|
|
|
|
|
|
print(f"Ожидаемая размерность модели: {expected_dim}")
|
|
|
|
|
print(f"Фактическая размерность данных: {actual_dim}")
|
|
|
|
|
|
|
|
|
|
if actual_dim != expected_dim:
|
|
|
|
|
print("Размерности не совпадают")
|
|
|
|
|
if actual_dim > expected_dim:
|
|
|
|
|
X_test = X_test[:, :expected_dim]
|
|
|
|
|
else:
|
|
|
|
|
padding = np.zeros((X_test.shape[0], expected_dim - actual_dim))
|
|
|
|
|
X_test = np.hstack([X_test, padding])
|
|
|
|
|
print(f"Данные скорректированы до: {X_test.shape}")
|
|
|
|
|
|
|
|
|
|
# 4. Расчет ошибок реконструкции
|
|
|
|
|
print("Расчет ошибок реконструкции...")
|
|
|
|
|
test_reconstructions = autoencoder.predict(X_test, verbose=1)
|
|
|
|
|
test_errors = np.mean(np.square(X_test - test_reconstructions), axis=1)
|
|
|
|
|
|
|
|
|
|
# 5. Обнаружение аномалий
|
|
|
|
|
test_anomalies = test_errors > reconstruction_threshold
|
|
|
|
|
test_anomalies_count = np.sum(test_anomalies)
|
|
|
|
|
test_anomalies_percentage = (test_anomalies_count / len(test_errors)) * 100
|
|
|
|
|
|
|
|
|
|
print("\nРЕЗУЛЬТАТЫ ОБНАРУЖЕНИЯ АНОМАЛИЙ:")
|
|
|
|
|
print(f"Всего тестовых образцов: {len(test_errors)}")
|
|
|
|
|
print(f"Обнаружено аномалий: {test_anomalies_count}")
|
|
|
|
|
print(f"Процент аномалий: {test_anomalies_percentage:.2f}%")
|
|
|
|
|
|
|
|
|
|
# 6. Построение графика ошибок реконструкции
|
|
|
|
|
plt.figure(figsize=(15, 10))
|
|
|
|
|
|
|
|
|
|
# График 1: Распределение ошибок реконструкции
|
|
|
|
|
plt.subplot(2, 2, 1)
|
|
|
|
|
n, bins, patches = plt.hist(test_errors, bins=50, alpha=0.7, color='lightblue', edgecolor='black')
|
|
|
|
|
|
|
|
|
|
for i in range(len(bins)-1):
|
|
|
|
|
if bins[i] > reconstruction_threshold:
|
|
|
|
|
patches[i].set_facecolor('red')
|
|
|
|
|
patches[i].set_alpha(0.7)
|
|
|
|
|
|
|
|
|
|
plt.axvline(x=reconstruction_threshold, color='red', linestyle='--', linewidth=2,
|
|
|
|
|
label=f'Порог: {reconstruction_threshold:.4f}')
|
|
|
|
|
plt.xlabel('Ошибка реконструкции')
|
|
|
|
|
plt.ylabel('Количество образцов')
|
|
|
|
|
plt.title('Распределение ошибок реконструкции')
|
|
|
|
|
plt.legend()
|
|
|
|
|
plt.grid(True, alpha=0.3)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# График 3: Ошибки по порядку образцов
|
|
|
|
|
plt.subplot(2, 2, 3)
|
|
|
|
|
plt.plot(test_errors, 'b-', alpha=0.7, linewidth=1)
|
|
|
|
|
plt.axhline(y=reconstruction_threshold, color='red', linestyle='--', linewidth=2, label='Порог')
|
|
|
|
|
plt.xlabel('Номер образца')
|
|
|
|
|
plt.ylabel('Ошибка реконструкции')
|
|
|
|
|
plt.title('Ошибки реконструкции по порядку образцов')
|
|
|
|
|
plt.legend()
|
|
|
|
|
plt.grid(True, alpha=0.3)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
plt.tight_layout()
|
|
|
|
|
plt.show()
|
|
|
|
|
|
|
|
|
|
# 7. Детальная статистика
|
|
|
|
|
print("\nДЕТАЛЬНАЯ СТАТИСТИКА:")
|
|
|
|
|
print(f"Минимальная ошибка: {np.min(test_errors):.6f}")
|
|
|
|
|
print(f"Максимальная ошибка: {np.max(test_errors):.6f}")
|
|
|
|
|
print(f"Средняя ошибка: {np.mean(test_errors):.6f}")
|
|
|
|
|
print(f"Медианная ошибка: {np.median(test_errors):.6f}")
|
|
|
|
|
print(f"Стандартное отклонение: {np.std(test_errors):.6f}")
|
|
|
|
|
|
|
|
|
|
print("\n" + "=" * 60)
|
|
|
|
|
print("ОБНАРУЖЕНИЕ АНОМАЛИЙ ЗАВЕРШЕНО")
|
|
|
|
|
print("=" * 60)
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|

|
|
|
|
|
|
|
|
|
|
**Результат выполнения:**
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
ОБНАРУЖЕНИЕ АНОМАЛИЙ НА ТЕСТОВОЙ ВЫБОРКЕ
|
|
|
|
|
|
|
|
|
|
Тестовая выборка загружена: (357, 30)
|
|
|
|
|
|
|
|
|
|
Порог обнаружения аномалий: 0.136186
|
|
|
|
|
Ожидаемая размерность модели: 30
|
|
|
|
|
Фактическая размерность данных: 30
|
|
|
|
|
|
|
|
|
|
РЕЗУЛЬТАТЫ ОБНАРУЖЕНИЯ АНОМАЛИЙ:
|
|
|
|
|
Всего тестовых образцов: 357
|
|
|
|
|
Обнаружено аномалий: 286
|
|
|
|
|
Процент аномалий: 80.11%
|
|
|
|
|
|
|
|
|
|
ДЕТАЛЬНАЯ СТАТИСТИКА:
|
|
|
|
|
Минимальная ошибка: 0.084998
|
|
|
|
|
Максимальная ошибка: 0.300929
|
|
|
|
|
Средняя ошибка: 0.160974
|
|
|
|
|
Медианная ошибка: 0.160995
|
|
|
|
|
Стандартное отклонение: 0.029058
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|