Spaces:
Sleeping
Sleeping
| import pandas as pd | |
| import matplotlib.pyplot as plt | |
| from collections import Counter | |
| import numpy as np | |
| import os | |
| import warnings | |
| warnings.filterwarnings('ignore') | |
| # Настройка отображения | |
| plt.style.use('default') | |
| plt.rcParams['font.family'] = 'DejaVu Sans' # Для поддержки кириллицы | |
| def load_and_analyze_data(): | |
| """Загрузка и базовый анализ данных""" | |
| # Загрузка данных с правильным разделителем | |
| file_path = 'small.csv' # или полный путь к файлу | |
| # Пробуем разные разделители и кодировки | |
| try: | |
| # Сначала пробуем с разделителем точка с запятой | |
| df = pd.read_csv(file_path, encoding='utf-8', delimiter=';') | |
| print("✅ Файл загружен с разделителем ';' и кодировкой utf-8") | |
| except: | |
| try: | |
| df = pd.read_csv(file_path, encoding='cp1251', delimiter=';') | |
| print("✅ Файл загружен с разделителем ';' и кодировкой cp1251") | |
| except: | |
| try: | |
| df = pd.read_csv(file_path, encoding='utf-8', delimiter=',') | |
| print("✅ Файл загружен с разделителем ',' и кодировкой utf-8") | |
| except: | |
| try: | |
| df = pd.read_csv(file_path, encoding='cp1251', delimiter=',') | |
| print("✅ Файл загружен с разделителем ',' и кодировкой cp1251") | |
| except Exception as e: | |
| print(f"❌ Ошибка загрузки файла: {e}") | |
| return None | |
| print("=" * 60) | |
| print("АНАЛИЗ РЕЗУЛЬТАТОВ АВТОМАТИЧЕСКОЙ ОЦЕНКИ") | |
| print("=" * 60) | |
| # Базовая информация о данных | |
| print(f"Размер данных: {df.shape[0]} строк, {df.shape[1]} колонок") | |
| print(f"\nВсе колонки: {list(df.columns)}") | |
| # Показываем первые несколько строк для проверки | |
| print(f"\nПервые 3 строки данных:") | |
| print(df.head(3)) | |
| return df | |
| def check_and_rename_columns(df): | |
| """Проверка и переименование колонок если нужно""" | |
| print("\n" + "=" * 40) | |
| print("ПРОВЕРКА СТРУКТУРЫ ДАННЫХ") | |
| print("=" * 40) | |
| # Если есть только одна колонка, возможно данные объединены | |
| if df.shape[1] == 1: | |
| first_column = df.columns[0] | |
| print(f"Обнаружена одна колонка: '{first_column}'") | |
| # Проверяем, содержит ли она все данные | |
| sample_value = str(df.iloc[0, 0]) | |
| if ';' in sample_value: | |
| print("⚠️ Данные объединены в одну колонку, разделяем...") | |
| # Разделяем данные по точке с запятой | |
| split_data = df[first_column].str.split(';', expand=True) | |
| # Берем первую строку как заголовки | |
| if split_data.shape[0] > 1: | |
| new_columns = split_data.iloc[0].tolist() | |
| split_data = split_data[1:] # Убираем строку с заголовками | |
| split_data.columns = new_columns | |
| df = split_data.reset_index(drop=True) | |
| print("✅ Данные успешно разделены") | |
| print(f"Новые колонки: {list(df.columns)}") | |
| return df | |
| def basic_statistics(df): | |
| """Базовая статистика по оценкам""" | |
| print("\n" + "=" * 40) | |
| print("БАЗОВАЯ СТАТИСТИКА") | |
| print("=" * 40) | |
| # Проверяем наличие нужных колонок | |
| available_columns = list(df.columns) | |
| print(f"Доступные колонки: {available_columns}") | |
| # Статистика по AI оценкам (pred_score) | |
| if 'pred_score' in df.columns: | |
| print("\nAI оценки (pred_score):") | |
| print(f" Среднее: {df['pred_score'].mean():.3f}") | |
| print(f" Медиана: {df['pred_score'].median():.3f}") | |
| print(f" Стандартное отклонение: {df['pred_score'].std():.3f}") | |
| print(f" Минимум: {df['pred_score'].min():.3f}") | |
| print(f" Максимум: {df['pred_score'].max():.3f}") | |
| else: | |
| print("❌ Колонка 'pred_score' не найдена") | |
| # Статистика по человеческим оценкам | |
| human_score_columns = ['Оценка экзаменатора', 'оценка', 'score', 'human_score'] | |
| human_score_col = None | |
| for col in human_score_columns: | |
| if col in df.columns: | |
| human_score_col = col | |
| break | |
| if human_score_col: | |
| print(f"\nОценки экзаменатора ({human_score_col}):") | |
| print(f" Среднее: {df[human_score_col].mean():.3f}") | |
| print(f" Медиана: {df[human_score_col].median():.3f}") | |
| print(f" Стандартное отклонение: {df[human_score_col].std():.3f}") | |
| # Распределение оценок | |
| print(f"\nРаспределение оценок экзаменатора:") | |
| распределение = df[human_score_col].value_counts().sort_index() | |
| for оценка, count in распределение.items(): | |
| print(f" {оценка}: {count} ответов ({count / len(df) * 100:.1f}%)") | |
| else: | |
| print("❌ Колонка с оценками экзаменатора не найдена") | |
| def calculate_correlations(df): | |
| """Расчет корреляций и разниц""" | |
| print("\n" + "=" * 40) | |
| print("КОРРЕЛЯЦИИ И РАСХОЖДЕНИЯ") | |
| print("=" * 40) | |
| # Проверяем наличие обеих колонок | |
| if 'pred_score' not in df.columns: | |
| print("❌ Колонка 'pred_score' не найдена для расчета корреляций") | |
| return | |
| human_score_columns = ['Оценка экзаменатора', 'оценка', 'score', 'human_score'] | |
| human_score_col = None | |
| for col in human_score_columns: | |
| if col in df.columns: | |
| human_score_col = col | |
| break | |
| if not human_score_col: | |
| print("❌ Колонка с оценками экзаменатора не найдена для расчета корреляций") | |
| return | |
| # Корреляция | |
| correlation = df[[human_score_col, 'pred_score']].corr().iloc[0, 1] | |
| print(f"Корреляция между оценками: {correlation:.3f}") | |
| # Разницы между оценками | |
| df['разница'] = df['pred_score'] - df[human_score_col] | |
| df['abs_разница'] = abs(df['разница']) | |
| print(f"\nСредняя абсолютная разница: {df['abs_разница'].mean():.3f}") | |
| print(f"Максимальная разница: {df['abs_разница'].max():.3f}") | |
| print(f"Минимальная разница: {df['abs_разница'].min():.3f}") | |
| # Анализ согласованности | |
| print("\nСОГЛАСОВАННОСТЬ ОЦЕНОК:") | |
| for порог in [0.1, 0.3, 0.5, 1.0]: | |
| согласованные = df[df['abs_разница'] < порог].shape[0] | |
| процент = (согласованные / len(df)) * 100 | |
| print(f" Разница < {порог}: {согласованные} ответов ({процент:.1f}%)") | |
| # Направление разниц | |
| завышение = len(df[df['разница'] > 0]) | |
| занижение = len(df[df['разница'] < 0]) | |
| совпадение = len(df[df['разница'] == 0]) | |
| print(f"\nНАПРАВЛЕНИЕ РАЗНИЦ:") | |
| print(f" AI завышает: {завышение} ({завышение / len(df) * 100:.1f}%)") | |
| print(f" AI занижает: {занижение} ({занижение / len(df) * 100:.1f}%)") | |
| print(f" Полное совпадение: {совпадение} ({совпадение / len(df) * 100:.1f}%)") | |
| def create_visualizations(df): | |
| """Создание визуализаций""" | |
| print("\n" + "=" * 40) | |
| print("СОЗДАНИЕ ВИЗУАЛИЗАЦИЙ") | |
| print("=" * 40) | |
| # Проверяем наличие нужных колонок | |
| if 'pred_score' not in df.columns: | |
| print("❌ Колонка 'pred_score' не найдена для визуализации") | |
| return | |
| human_score_columns = ['Оценка экзаменатора', 'оценка', 'score', 'human_score'] | |
| human_score_col = None | |
| for col in human_score_columns: | |
| if col in df.columns: | |
| human_score_col = col | |
| break | |
| if not human_score_col: | |
| print("❌ Колонка с оценками экзаменатора не найдена для визуализации") | |
| return | |
| # Создаем папку для графиков | |
| os.makedirs('graphs', exist_ok=True) | |
| # 1. Scatter plot сравнения оценок | |
| plt.figure(figsize=(12, 8)) | |
| scatter = plt.scatter(df[human_score_col], df['pred_score'], | |
| c=df['abs_разница'], cmap='viridis', alpha=0.7, s=80) | |
| plt.colorbar(scatter, label='Абсолютная разница') | |
| # Определяем диапазон для линии идеального соответствия | |
| min_val = min(df[human_score_col].min(), df['pred_score'].min()) | |
| max_val = max(df[human_score_col].max(), df['pred_score'].max()) | |
| plt.plot([min_val, max_val], [min_val, max_val], 'r--', alpha=0.5, label='Идеальное соответствие') | |
| plt.xlabel(f'Оценка экзаменатора ({human_score_col})', fontsize=12) | |
| plt.ylabel('AI оценка (pred_score)', fontsize=12) | |
| plt.title('Сравнение человеческой и AI оценки\n(цвет показывает величину расхождения)', fontsize=14) | |
| plt.legend() | |
| plt.grid(True, alpha=0.3) | |
| plt.savefig('graphs/scatter_comparison.png', dpi=300, bbox_inches='tight') | |
| plt.close() | |
| # 2. Гистограмма разниц | |
| plt.figure(figsize=(12, 6)) | |
| n, bins, patches = plt.hist(df['разница'], bins=30, alpha=0.7, | |
| edgecolor='black', color='skyblue') | |
| plt.xlabel('Разница оценок (AI - Человек)', fontsize=12) | |
| plt.ylabel('Количество ответов', fontsize=12) | |
| plt.title('Распределение разниц между AI и человеческими оценками', fontsize=14) | |
| plt.grid(True, alpha=0.3) | |
| plt.axvline(x=0, color='red', linestyle='--', alpha=0.8, linewidth=2, label='Нулевая разница') | |
| plt.axvline(x=df['разница'].mean(), color='orange', linestyle='--', | |
| alpha=0.8, linewidth=2, label=f'Средняя разница: {df["разница"].mean():.3f}') | |
| plt.legend() | |
| plt.savefig('graphs/difference_histogram.png', dpi=300, bbox_inches='tight') | |
| plt.close() | |
| print("✅ Графики сохранены в папку 'graphs/'") | |
| def analyze_extreme_cases(df): | |
| """Анализ крайних случаев""" | |
| print("\n" + "=" * 40) | |
| print("АНАЛИЗ КРАЙНИХ СЛУЧАЕВ") | |
| print("=" * 40) | |
| if 'abs_разница' not in df.columns: | |
| print("❌ Не найдены данные о разницах оценок") | |
| return | |
| human_score_columns = ['Оценка экзаменатора', 'оценка', 'score', 'human_score'] | |
| human_score_col = None | |
| for col in human_score_columns: | |
| if col in df.columns: | |
| human_score_col = col | |
| break | |
| if not human_score_col: | |
| print("❌ Колонка с оценками экзаменатора не найдена") | |
| return | |
| # Наибольшие расхождения | |
| большие_расхождения = df.nlargest(8, 'abs_разница')[ | |
| [human_score_col, 'pred_score', 'abs_разница', 'разница'] | |
| ] | |
| # Добавляем ID если есть | |
| id_columns = ['Id экзамена', 'id', 'ID', 'exam_id'] | |
| for col in id_columns: | |
| if col in df.columns: | |
| большие_расхождения[col] = df.loc[большие_расхождения.index, col] | |
| break | |
| question_columns = ['№ вопроса', 'question', 'вопрос', 'question_id'] | |
| for col in question_columns: | |
| if col in df.columns: | |
| большие_расхождения[col] = df.loc[большие_расхождения.index, col] | |
| break | |
| print("Топ-8 наибольших расхождений:") | |
| print("-" * 80) | |
| for idx, row in большие_расхождения.iterrows(): | |
| направление = "ЗАВЫШЕНИЕ" if row['разница'] > 0 else "ЗАНИЖЕНИЕ" | |
| # Формируем информацию об ID и вопросе | |
| id_info = "" | |
| if 'Id экзамена' in row: | |
| id_info = f"Экзамен {row['Id экзамена']}" | |
| elif 'id' in row: | |
| id_info = f"ID {row['id']}" | |
| question_info = "" | |
| if '№ вопроса' in row: | |
| question_info = f", Вопрос {row['№ вопроса']}" | |
| elif 'question' in row: | |
| question_info = f", Вопрос {row['question']}" | |
| print(f"\n📊 {id_info}{question_info} ({направление}):") | |
| print(f" 👤 Человек: {row[human_score_col]} | 🤖 AI: {row['pred_score']:.3f}") | |
| print(f" 📏 Разница: {row['abs_разница']:.3f} ({row['разница']:+.3f})") | |
| print("-" * 60) | |
| def analyze_explanations(df): | |
| """Анализ объяснений оценок""" | |
| print("\n" + "=" * 40) | |
| print("АНАЛИЗ ОБЪЯСНЕНИЙ ОЦЕНОК") | |
| print("=" * 40) | |
| explanation_columns = ['объяснение_оценки', 'explanation', 'объяснение', 'комментарий'] | |
| explanation_col = None | |
| for col in explanation_columns: | |
| if col in df.columns: | |
| explanation_col = col | |
| break | |
| if not explanation_col: | |
| print("❌ Колонка с объяснениями оценок не найдена") | |
| return | |
| # Собираем все объяснения | |
| все_объяснения = ' '.join(df[explanation_col].dropna().astype(str)) | |
| # Разбиваем на слова и фильтруем | |
| слова = [word.strip() for word in все_объяснения.split() if len(word.strip()) > 2] | |
| # Анализ частотности | |
| частотность = Counter(слова) | |
| print("Топ-15 наиболее частых характеристик в объяснениях:") | |
| print("-" * 50) | |
| for слово, count in частотность.most_common(15): | |
| print(f" {слово}: {count}") | |
| def save_detailed_analysis(df): | |
| """Сохранение детального анализа в файл""" | |
| print("\n" + "=" * 40) | |
| print("СОХРАНЕНИЕ РЕЗУЛЬТАТОВ") | |
| print("=" * 40) | |
| if 'abs_разница' not in df.columns: | |
| print("❌ Нет данных для детального анализа") | |
| return | |
| # Создаем копию с анализом | |
| df_analysis = df.copy() | |
| human_score_columns = ['Оценка экзаменатора', 'оценка', 'score', 'human_score'] | |
| human_score_col = None | |
| for col in human_score_columns: | |
| if col in df.columns: | |
| human_score_col = col | |
| break | |
| if human_score_col and 'pred_score' in df.columns: | |
| df_analysis['разница_ai_человек'] = df_analysis['pred_score'] - df_analysis[human_score_col] | |
| df_analysis['abs_разница'] = abs(df_analysis['разница_ai_человек']) | |
| # Добавляем категоризацию расхождений | |
| условия = [ | |
| df_analysis['abs_разница'] < 0.1, | |
| df_analysis['abs_разница'] < 0.3, | |
| df_analysis['abs_разница'] < 0.5, | |
| df_analysis['abs_разница'] >= 0.5 | |
| ] | |
| категории = ['Отличное', 'Хорошее', 'Умеренное', 'Низкое'] | |
| df_analysis['качество_согласования'] = np.select(условия, категории, default='Низкое') | |
| # Сортируем по наибольшим расхождениям | |
| df_analysis = df_analysis.sort_values('abs_разница', ascending=False) | |
| try: | |
| # Сохраняем в Excel | |
| with pd.ExcelWriter('detailed_analysis.xlsx', engine='openpyxl') as writer: | |
| # Все данные | |
| df_analysis.to_excel(writer, sheet_name='Все_данные_с_анализом', index=False) | |
| print("✅ Детальный анализ сохранен в 'detailed_analysis.xlsx'") | |
| except Exception as e: | |
| print(f"⚠️ Не удалось сохранить Excel, сохраняем в CSV: {e}") | |
| df_analysis.to_csv('detailed_analysis.csv', index=False, encoding='utf-8') | |
| print("✅ Детальный анализ сохранен в 'detailed_analysis.csv'") | |
| def main(): | |
| """Основная функция""" | |
| try: | |
| # Загрузка данных | |
| df = load_and_analyze_data() | |
| if df is None: | |
| return | |
| # Проверка и корректировка структуры данных | |
| df = check_and_rename_columns(df) | |
| # Выполнение анализа | |
| basic_statistics(df) | |
| calculate_correlations(df) | |
| create_visualizations(df) | |
| analyze_extreme_cases(df) | |
| analyze_explanations(df) | |
| save_detailed_analysis(df) | |
| print("\n" + "=" * 60) | |
| print("✅ АНАЛИЗ ЗАВЕРШЕН!") | |
| print("=" * 60) | |
| except FileNotFoundError: | |
| print("❌ ОШИБКА: Файл 'small.csv' не найден в текущей директории") | |
| print(" Убедитесь, что файл находится в той же папке, что и скрипт") | |
| except Exception as e: | |
| print(f"❌ ОШИБКА при выполнении анализа: {str(e)}") | |
| import traceback | |
| traceback.print_exc() | |
| if __name__ == "__main__": | |
| main() |