/
urfu_itis_limits
/
code-review-101-gnida
Обзор
Документация
Войти
/
urfu_itis_limits
/
code-review-101-gnida
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
master
assignment.py
293 строки
13 KB
gnida
update assignment.py
20 ноя 2025, 13:40
20 ноя 2025, 13:40
9d250ea
Код
Авторство
О чём код?
""" Задание 10: Анализ датасета Digits - ИСПРАВЛЕННАЯ ВЕРСИЯ Цель: Анализ данных рукописных цифр - многоклассовая классификация """ import pandas as pd import numpy as np import matplotlib.pyplot as plt import matplotlib.cm as cm from sklearn.datasets import load_digits import os plt.rcParams['font.sans-serif'] = ['DejaVu Sans'] plt.rcParams['axes.unicode_minus'] = False def load_data(): """Загрузить датасет Digits и конвертировать в DataFrame""" digits = load_digits() # Создаем DataFrame с пиксельными признаками df = pd.DataFrame(digits.data) # Добавляем целевую переменную (цифры) df['target'] = digits.target # Динамически формируем названия столбцов на основе формы данных n_features = digits.data.shape[1] df.columns = [f'pixel_{i}' for i in range(n_features)] + ['target'] return df, digits def target_analysis(df): """Анализ целевой переменной (цифры 0-9)""" print("\n" + "="*50) print("АНАЛИЗ ЦЕЛЕВОЙ ПЕРЕМЕННОЙ") print("="*50) # Распределение цифр target_counts = df['target'].value_counts().sort_index() print("Распределение цифр:") for digit, count in target_counts.items(): percentage = (count / len(df)) * 100 print(f"Цифра {digit}: {count} примеров ({percentage:.1f}%)") # Общая статистика print(f"\nВсего примеров: {len(df)}") print(f"Количество классов: {len(target_counts)}") print(f"Сбалансированность: {target_counts.std():.2f} (стандартное отклонение)") def feature_statistics(df): """Вычислить статистику по пиксельным значениям""" print("\n" + "="*50) print("СТАТИСТИКА ПИКСЕЛЕЙ") print("="*50) # Выбираем только пиксельные колонки pixel_columns = [col for col in df.columns if col.startswith('pixel_')] pixel_data = df[pixel_columns] # Основные статистики print("Общая статистика пиксельных значений:") print(f"Среднее значение: {pixel_data.values.mean():.2f}") print(f"Минимальное значение: {pixel_data.values.min()}") print(f"Максимальное значение: {pixel_data.values.max()}") print(f"Стандартное отклонение: {pixel_data.values.std():.2f}") print(f"Медиана: {np.median(pixel_data.values):.2f}") # Статистика по ненулевым пикселям non_zero_pixels = pixel_data.values[pixel_data.values > 0] print(f"\nНенулевые пиксели ({len(non_zero_pixels)}):") print(f"Среднее: {non_zero_pixels.mean():.2f}") print(f"Максимум: {non_zero_pixels.max()}") def visualize_target(df): """Визуализировать распределение цифр""" fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(15, 6)) # Столбчатая диаграмма target_counts = df['target'].value_counts().sort_index() bars = ax1.bar(target_counts.index, target_counts.values, color='skyblue', edgecolor='navy', alpha=0.7) ax1.set_title('Распределение цифр в датасете', fontsize=14, fontweight='bold') ax1.set_xlabel('Цифра') ax1.set_ylabel('Количество примеров') ax1.grid(axis='y', alpha=0.3) # Добавляем значения на столбцы for bar, count in zip(bars, target_counts.values): height = bar.get_height() ax1.text(bar.get_x() + bar.get_width()/2., height + 0.5, f'{count}', ha='center', va='bottom') # Круговая диаграмма colors = cm.Set3(np.linspace(0, 1, len(target_counts))) wedges, texts, autotexts = ax2.pie(target_counts.values, labels=target_counts.index, autopct='%1.1f%%', startangle=90, colors=colors) ax2.set_title('Процентное распределение цифр', fontsize=14, fontweight='bold') # Улучшаем читаемость for autotext in autotexts: autotext.set_color('black') autotext.set_fontweight('bold') plt.tight_layout() plt.savefig('10_digits_target_distribution.png', dpi=300, bbox_inches='tight') plt.close() print("Создан файл: 10_digits_target_distribution.png") def sample_digit_images(df): """Визуализировать примеры цифр""" fig, axes = plt.subplots(2, 5, figsize=(15, 6)) axes = axes.ravel() pixel_columns = [col for col in df.columns if col.startswith('pixel_')] # Определяем размер изображения из количества пикселей n_pixels = len(pixel_columns) img_size = int(np.sqrt(n_pixels)) # предполагаем квадратное изображение for digit in range(10): # Находим примеры для текущей цифры digit_samples = df[df['target'] == digit] # Проверяем, есть ли примеры для этой цифры if len(digit_samples) == 0: print(f"Предупреждение: нет примеров для цифры {digit}") # Создаем пустое изображение image_data = np.zeros((img_size, img_size)) axes[digit].imshow(image_data, cmap='gray', interpolation='nearest') axes[digit].set_title(f'Цифра: {digit} (нет данных)', fontsize=12, fontweight='bold') else: # Берем первый пример digit_sample = digit_samples.iloc[0] # Извлекаем пиксели и преобразуем в матрицу image_data = digit_sample[pixel_columns].values.reshape(img_size, img_size) # Отображаем изображение axes[digit].imshow(image_data, cmap='gray', interpolation='nearest') axes[digit].set_title(f'Цифра: {digit}', fontsize=12, fontweight='bold') axes[digit].set_xticks([]) axes[digit].set_yticks([]) plt.suptitle('Примеры рукописных цифр из датасета', fontsize=16, fontweight='bold') plt.tight_layout() plt.savefig('10_digits_sample_images.png', dpi=300, bbox_inches='tight') plt.close() print("Создан файл: 10_digits_sample_images.png") def pixel_intensity_analysis(df): """Анализ интенсивности пикселей""" fig, axes = plt.subplots(2, 2, figsize=(15, 12)) pixel_columns = [col for col in df.columns if col.startswith('pixel_')] pixel_data = df[pixel_columns] # 1. Гистограмма всех пиксельных значений axes[0, 0].hist(pixel_data.values.ravel(), bins=30, color='lightcoral', alpha=0.7, edgecolor='darkred') axes[0, 0].set_title('Распределение значений пикселей', fontweight='bold') axes[0, 0].set_xlabel('Значение пикселя') axes[0, 0].set_ylabel('Частота') axes[0, 0].grid(alpha=0.3) # 2. Средняя интенсивность по цифрам mean_intensity_by_digit = df.groupby('target')[pixel_columns].mean().mean(axis=1) axes[0, 1].bar(mean_intensity_by_digit.index, mean_intensity_by_digit.values, color='lightgreen', alpha=0.7, edgecolor='darkgreen') axes[0, 1].set_title('Средняя интенсивность пикселей по цифрам', fontweight='bold') axes[0, 1].set_xlabel('Цифра') axes[0, 1].set_ylabel('Средняя интенсивность') axes[0, 1].grid(axis='y', alpha=0.3) # 3. Дисперсия пикселей по цифрам variance_by_digit = df.groupby('target')[pixel_columns].var().mean(axis=1) axes[1, 0].bar(variance_by_digit.index, variance_by_digit.values, color='lightblue', alpha=0.7, edgecolor='darkblue') axes[1, 0].set_title('Средняя дисперсия пикселей по цифрам', fontweight='bold') axes[1, 0].set_xlabel('Цифра') axes[1, 0].set_ylabel('Средняя дисперсия') axes[1, 0].grid(axis='y', alpha=0.3) # 4. Среднее количество ненулевых пикселей по цифрам non_zero_count_by_digit = df.groupby('target')[pixel_columns].apply( lambda x: (x > 0).sum(axis=1).mean()) axes[1, 1].bar(non_zero_count_by_digit.index, non_zero_count_by_digit.values, color='gold', alpha=0.7, edgecolor='darkorange') axes[1, 1].set_title('Среднее количество ненулевых пикселей', fontweight='bold') axes[1, 1].set_xlabel('Цифра') axes[1, 1].set_ylabel('Количество ненулевых пикселей') axes[1, 1].grid(axis='y', alpha=0.3) plt.suptitle('Анализ интенсивности пикселей', fontsize=16, fontweight='bold') plt.tight_layout() plt.savefig('10_digits_pixel_analysis.png', dpi=300, bbox_inches='tight') plt.close() print("Создан файл: 10_digits_pixel_analysis.png") def heatmap_mean_images(df): """Тепловые карты средних изображений для каждой цифры""" fig, axes = plt.subplots(2, 5, figsize=(15, 6)) axes = axes.ravel() pixel_columns = [col for col in df.columns if col.startswith('pixel_')] # Определяем размер изображения из количества пикселей n_pixels = len(pixel_columns) img_size = int(np.sqrt(n_pixels)) # предполагаем квадратное изображение for digit in range(10): # Выбираем данные для текущей цифры digit_data = df[df['target'] == digit][pixel_columns] # Проверяем, есть ли примеры для этой цифры if len(digit_data) == 0: print(f"Предупреждение: нет примеров для цифры {digit} при создании тепловой карты") mean_image = np.zeros((img_size, img_size)) axes[digit].set_title(f'Цифра: {digit} (нет данных)', fontweight='bold') else: # Вычисляем среднее изображение mean_image = digit_data.mean().values.reshape(img_size, img_size) axes[digit].set_title(f'Средняя цифра: {digit}', fontweight='bold') # Создаем тепловую карту im = axes[digit].imshow(mean_image, cmap='hot', interpolation='nearest') axes[digit].set_xticks([]) axes[digit].set_yticks([]) # Добавляем цветовую шкалу для каждого subplot plt.colorbar(im, ax=axes[digit], fraction=0.046, pad=0.04) plt.suptitle('Тепловые карты средних изображений цифр', fontsize=16, fontweight='bold') plt.tight_layout() plt.savefig('10_digits_mean_heatmaps.png', dpi=300, bbox_inches='tight') plt.close() print("Создан файл: 10_digits_mean_heatmaps.png") def check_files_created(): """Проверить, что все файлы созданы""" expected_files = [ '10_digits_target_distribution.png', '10_digits_sample_images.png', '10_digits_pixel_analysis.png', '10_digits_mean_heatmaps.png' ] print("\n" + "="*50) print("ПРОВЕРКА СОЗДАННЫХ ФАЙЛОВ") print("="*50) for file in expected_files: if os.path.exists(file): file_size = os.path.getsize(file) print(f"✓ {file} - {file_size} байт") else: print(f"✗ {file} - ФАЙЛ НЕ НАЙДЕН!") def main(): """Главная функция""" print("=" * 60) print("ЗАДАНИЕ 10: EXPLORATORY DATA ANALYSIS - DIGITS DATASET") print("=" * 60) df, digits = load_data() print(f"\nДатасет загружен. Размер: {df.shape}") print(f"Количество пиксельных признаков: {digits.data.shape[1]}") print(f"Размер изображения: {int(np.sqrt(digits.data.shape[1]))}x{int(np.sqrt(digits.data.shape[1]))}") print("\nПервые 5 строк:") print(df.head()) target_analysis(df) feature_statistics(df) visualize_target(df) sample_digit_images(df) pixel_intensity_analysis(df) heatmap_mean_images(df) check_files_created() print("\n" + "=" * 60) print("Анализ завершен! Все графики сохранены в PNG файлы.") print("=" * 60) if __name__ == "__main__": main()