/
urfu_itis_limits
/
code-review-101-sofiet
Обзор
Документация
Войти
/
urfu_itis_limits
/
code-review-101-sofiet
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
master
assignment.py
312 строк
13 KB
IlyaKonovalov
update assignment.py
11 дек 2025, 21:21
11 дек 2025, 21:21
2f16d76
Код
Авторство
О чём код?
import pandas as pd import numpy as np import matplotlib.pyplot as plt import seaborn as sns from sklearn.datasets import load_breast_cancer # Настройки шрифтов plt.rcParams['font.sans-serif'] = ['DejaVu Sans'] plt.rcParams['axes.unicode_minus'] = False def load_data(): """Загрузить датасет Breast Cancer и конвертировать в DataFrame""" try: # ИСПРАВЛЕНИЕ: Добавлена обработка ошибок и валидация данных data = load_breast_cancer() # Проверка загруженных данных if data is None: raise ValueError("Не удалось загрузить данные") df = pd.DataFrame(data.data, columns=data.feature_names) df['diagnosis'] = data.target # Валидация данных if df.empty: raise ValueError("Созданный DataFrame пуст") if df.isnull().sum().sum() > 0: print("⚠️ В данных обнаружены пропущенные значения") # Автоматическое заполнение пропущенных значений numeric_cols = df.select_dtypes(include=[np.number]).columns df[numeric_cols] = df[numeric_cols].fillna(df[numeric_cols].median()) # Заменяем 0 -> 'benign', 1 -> 'malignant' df['diagnosis'] = df['diagnosis'].map({0: 'benign', 1: 'malignant'}) # Проверка преобразования целевой переменной if df['diagnosis'].isnull().sum() > 0: raise ValueError("Ошибка при преобразовании целевой переменной") print("✅ Данные успешно загружены и проверены") return df except Exception as e: print(f"❌ Ошибка при загрузке данных: {e}") return None def target_analysis(df): """Анализ целевой переменной (тип опухоли)""" if df is None: print("❌ Нет данных для анализа") return counts = df['diagnosis'].value_counts() total = len(df) print("\nРаспределение диагнозов:") for cls, cnt in counts.items(): percent = (cnt / total) * 100 print(f" {cls}: {cnt} ({percent:.2f}%)") print(f"Доброкачественные: {counts.get('benign', 0)}") print(f"Злокачественные: {counts.get('malignant', 0)}") def feature_statistics(df): """Вычислить статистику по признакам""" if df is None: print("❌ Нет данных для анализа") return feature_cols = df.columns[:-1] # все кроме 'diagnosis' # ИСПРАВЛЕНИЕ: Устранение дублирования и улучшение анализа признаков print("\n" + "="*50) print("СТАТИСТИЧЕСКИЙ АНАЛИЗ ПРИЗНАКОВ") print("="*50) # Общая статистика по всем числовым признакам numeric_stats = df[feature_cols].describe() print(f"\nОбщая статистика по {len(feature_cols)} признакам:") print(f"Средние значения: от {numeric_stats.loc['mean'].min():.4f} до {numeric_stats.loc['mean'].max():.4f}") print(f"Стандартные отклонения: от {numeric_stats.loc['std'].min():.4f} до {numeric_stats.loc['std'].max():.4f}") # Анализ по группам признаков (mean, error, worst) mean_features = [col for col in feature_cols if 'mean' in col] error_features = [col for col in feature_cols if 'error' in col] worst_features = [col for col in feature_cols if 'worst' in col] print(f"\nГруппы признаков:") print(f" Mean features: {len(mean_features)}") print(f" Error features: {len(error_features)}") print(f" Worst features: {len(worst_features)}") # Детальная статистика по первым 5 признакам print("\nДетальная статистика по первым 5 признакам:") for col in feature_cols[:5]: stats = df[col].describe() print(f"\n📊 {col}:") print(f" Среднее: {stats['mean']:.4f} ± {stats['std']:.4f}") print(f" Диапазон: [{stats['min']:.4f}, {stats['max']:.4f}]") print(f" Медиана: {stats['50%']:.4f}") print(f" IQR: {stats['75%'] - stats['25%']:.4f}") def visualize_target(df): """Визуализировать распределение целевой переменной""" if df is None: print("❌ Нет данных для визуализации") return fig, axes = plt.subplots(1, 2, figsize=(12, 5)) # Столбчатая диаграмма counts = df['diagnosis'].value_counts() colors = ['skyblue', 'salmon'] labels = ['benign', 'malignant'] bars = axes[0].bar(labels, counts.values, color=colors, alpha=0.7) axes[0].set_title('Распределение диагнозов', fontweight='bold') axes[0].set_ylabel('Количество') axes[0].grid(axis='y', alpha=0.3) # Добавляем значения на столбцы for bar, count in zip(bars, counts.values): axes[0].text(bar.get_x() + bar.get_width()/2, bar.get_height() + 5, str(count), ha='center', va='bottom', fontweight='bold') # Круговая диаграмма axes[1].pie(counts.values, labels=labels, autopct='%1.1f%%', colors=colors, startangle=90, explode=(0.05, 0)) axes[1].set_title('Процентное соотношение диагнозов', fontweight='bold') plt.tight_layout() plt.savefig('04_cancer_target_distribution.png', dpi=300, bbox_inches='tight') plt.show() plt.close() def visualize_features(df): """Визуализировать распределение первых 6 признаков""" if df is None: print("❌ Нет данных для визуализации") return feature_cols = df.columns[:-1][:6] fig, axes = plt.subplots(3, 2, figsize=(12, 12)) axes = axes.flatten() for i, col in enumerate(feature_cols): axes[i].hist(df[col], bins=30, color='lightgreen', alpha=0.7, edgecolor='black') axes[i].set_title(f'{col}', fontweight='bold') axes[i].set_xlabel('Значение') axes[i].set_ylabel('Частота') axes[i].grid(alpha=0.3) plt.suptitle('Распределение медицинских показателей', fontsize=16, fontweight='bold') plt.tight_layout() plt.savefig('04_cancer_features_distribution.png', dpi=300, bbox_inches='tight') plt.show() plt.close() def features_by_diagnosis(df): """Boxplot признаков по диагнозам""" if df is None: print("❌ Нет данных для визуализации") return feature_cols = df.columns[:-1][:6] fig, axes = plt.subplots(3, 2, figsize=(12, 12)) axes = axes.flatten() for i, col in enumerate(feature_cols): # Группируем по диагнозу data_to_plot = [df[df['diagnosis'] == 'benign'][col], df[df['diagnosis'] == 'malignant'][col]] axes[i].boxplot(data_to_plot, labels=['benign', 'malignant'], patch_artist=True, boxprops=dict(facecolor='lightblue', alpha=0.7), medianprops=dict(color='red', linewidth=2)) axes[i].set_title(f'{col}', fontweight='bold') axes[i].set_ylabel('Значение') axes[i].grid(alpha=0.3) plt.suptitle('Сравнение признаков по диагнозам', fontsize=16, fontweight='bold') plt.tight_layout() plt.savefig('04_cancer_features_by_diagnosis.png', dpi=300, bbox_inches='tight') plt.show() plt.close() def correlation_analysis(df): """Анализ корреляций""" if df is None: print("❌ Нет данных для анализа") return # Преобразуем диагноз обратно в числа для корреляции df_numeric = df.copy() df_numeric['diagnosis'] = df_numeric['diagnosis'].map({'benign': 0, 'malignant': 1}) # Корреляция с целевой переменной corr_with_target = df_numeric.corr()['diagnosis'].drop('diagnosis') corr_with_target_abs = corr_with_target.abs().sort_values(ascending=False) print("\n" + "="*50) print("АНАЛИЗ КОРРЕЛЯЦИЙ") print("="*50) # ИСПРАВЛЕНИЕ: Улучшенный анализ корреляций print("\nТоп-10 признаков по абсолютной корреляции с диагнозом:") for i, (feature, corr) in enumerate(corr_with_target_abs.head(10).items(), 1): original_corr = corr_with_target[feature] direction = "положительная" if original_corr > 0 else "отрицательная" print(f" {i:2d}. {feature:30}: {original_corr:7.4f} ({direction})") # Анализ сильных корреляций strong_positive = corr_with_target[corr_with_target > 0.7] strong_negative = corr_with_target[corr_with_target < -0.7] print(f"\nСильные корреляции:") print(f" Положительные (>0.7): {len(strong_positive)} признаков") print(f" Отрицательные (<-0.7): {len(strong_negative)} признаков") # Горизонтальная диаграмма топ-15 top15 = corr_with_target_abs.head(15) plt.figure(figsize=(12, 8)) colors = ['red' if corr_with_target[feature] > 0 else 'blue' for feature in top15.index] bars = plt.barh(range(len(top15)), top15.values, color=colors, alpha=0.7) plt.yticks(range(len(top15)), top15.index) plt.xlabel('Абсолютная корреляция с диагнозом', fontweight='bold') plt.title('Топ-15 признаков по корреляции с диагнозом', fontsize=14, fontweight='bold') plt.grid(axis='x', alpha=0.3) # Добавляем значения на столбцы for i, (bar, feature) in enumerate(zip(bars, top15.index)): corr_value = corr_with_target[feature] plt.text(bar.get_width() + 0.01, bar.get_y() + bar.get_height()/2, f'{corr_value:.3f}', va='center', ha='left', fontweight='bold') plt.gca().invert_yaxis() plt.tight_layout() plt.savefig('04_cancer_correlation_top.png', dpi=300, bbox_inches='tight') plt.show() # ИСПРАВЛЕНИЕ: Добавлена heatmap корреляций print("\nПостроение heatmap корреляций...") # Выбираем топ-15 признаков для heatmap top_features = corr_with_target_abs.head(15).index.tolist() top_features.append('diagnosis') # Создаем матрицу корреляций для топ признаков corr_matrix = df_numeric[top_features].corr() # Создаем heatmap plt.figure(figsize=(12, 10)) mask = np.triu(np.ones_like(corr_matrix, dtype=bool)) # Маска для верхнего треугольника sns.heatmap(corr_matrix, mask=mask, annot=True, fmt='.2f', cmap='RdBu_r', center=0, square=True, cbar_kws={'shrink': 0.8}) plt.title('Матрица корреляций (топ-15 признаков)', fontsize=16, fontweight='bold') plt.xticks(rotation=45, ha='right') plt.yticks(rotation=0) plt.tight_layout() plt.savefig('04_cancer_correlation_heatmap.png', dpi=300, bbox_inches='tight') plt.show() print("✅ Heatmap корреляций сохранена как '04_cancer_correlation_heatmap.png'") plt.close() def main(): """Главная функция""" print("=" * 60) print("ЗАДАНИЕ 4: EXPLORATORY DATA ANALYSIS - BREAST CANCER DATASET") print("=" * 60) df = load_data() if df is None: print("❌ Не удалось загрузить данные. Завершение работы.") return print(f"\nДатасет загружен. Размер: {df.shape}") print("\nПервые 5 строк:") print(df.head()) target_analysis(df) feature_statistics(df) visualize_target(df) visualize_features(df) features_by_diagnosis(df) correlation_analysis(df) print("\n" + "=" * 60) print("Анализ завершен!") print("=" * 60) if __name__ == "__main__": main()