exam-evaluator / create_and_analyze.py
KarmanovaLidiia
Initial clean commit for HF Space (models via Git LFS)
bcb314a
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 create_test_data():
"""Создание тестовых данных"""
test_data = """Id экзамена;Id вопроса;№ вопроса;Текст вопроса;Оценка экзаменатора;Транскрибация ответа;pred_score;объяснение_оценки
3373871;30625752;1;"<p>Добро пожаловать на экзамен!</p>";1;"Экзаменатор: Начните диалог. Тестируемый: Здравствуйте, я хотел бы извиниться, что не смогу прийти на день рождения. Что бы вы хотели в подарок?";0.99;"🟢 Развернутый ответ | ✅ Высокое смысловое соответствие | 📊 Хорошая структура ответа | 💬 Разнообразная лексика | ⭐ Высокий балл"
3373871;30625753;2;"<p>Расскажите о вашем жилье</p>";2;"Экзаменатор: Вы живёте в квартире или доме? Тестируемый: Я живу в квартире в центре города. Это трёхкомнатная квартира с балконом. Квартира новая, построена в 2020 году.";1.62;"🟢 Развернутый ответ | ✅ Высокое смысловое соответствие | 📊 Хорошая структура ответа | 🏠 Подробное описание | ⭐ Высокий балл"
3373872;30625790;1;"<p>Начните диалог о работе</p>";1;"Экзаменатор: Узнайте о требованиях к работе. Тестируемый: Здравствуйте, я увидел ваше объявление о вакансии. Какие требования к соискателю? Какие документы нужны?";0.87;"🟢 Развернутый ответ | ⚠️ Умеренное смысловое соответствие | 📊 Хорошая структура ответа | 💬 Разнообразная лексика | ⭐ Высокий балл"
3373872;30625791;2;"<p>Опишите ваше жилье</p>";1;"Экзаменатор: Расскажите о вашей квартире. Тестируемый: У меня квартира. Она хорошая. Три комнаты.";0.45;"📉 Мало предложений | ❌ Низкое смысловое соответствие | 📊 Хорошая структура ответа"
3373873;30625828;1;"<p>Оформление документов</p>";2;"Экзаменатор: Объясните ситуацию в миграционной службе. Тестируемый: Здравствуйте, мне нужно оформить миграционную карту. Я приехал две недели назад. Можете дать мне бланк для заполнения?";1.85;"🟢 Развернутый ответ | ✅ Высокое смысловое соответствие | 📊 Хорошая структура ответа | 💬 Разнообразная лексика | ⭐ Высокий балл"
3373873;30625829;2;"<p>Ваши любимые фильмы</p>";1;"Экзаменатор: Какие фильмы вы любите? Тестируемый: Я смотрю фантастику и детективы. Люблю новые цветные фильмы. Мой любимый фильм - Интерстеллар, он о космосе и времени.";1.15;"🟢 Развернутый ответ | ⚠️ Умеренное смысловое соответствие | 📊 Хорошая структура ответа | 💬 Разнообразная лексика"
3373874;30625866;3;"<p>Опишите картинку</p>";2;"Экзаменатор: Что изображено на картинке? Тестируемый: На картинке изображена семья в парке. Дети играют в мяч, родители сидят на скамейке. Яркий солнечный день, лето.";1.92;"🟢 Развернутый ответ | ✅ Высокое смысловое соответствие | 🎨 Есть вступление с описанием картинки | 👤 Есть личный опыт | ⭐ Высокий балл"
3373874;30625867;4;"<p>Расскажите о хобби</p>";1;"Экзаменатор: Чем увлекаетесь? Тестируемый: Я читаю книги. Иногда смотрю фильмы.";0.35;"📉 Мало предложений | ❌ Низкое смысловое соответствие | 📊 Хорошая структура ответа"
3373875;30625904;1;"<p>Ситуация в больнице</p>";1;"Экзаменатор: Узнайте о приеме врача. Тестируемый: Здравствуйте, мне нужно записаться к терапевту на обследование. Когда принимает врач и какие документы нужны?";0.95;"🟢 Развернутый ответ | ✅ Высокое смысловое соответствие | 📊 Хорошая структура ответа | 💬 Разнообразная лексика | ⭐ Высокий балл"
3373875;30625905;2;"<p>Кулинарные предпочтения</p>";2;"Экзаменатор: Какая ваша любимая кухня? Тестируемый: Я очень люблю итальянскую кухню, особенно пасту и пиццу. Также нравится японская кухня - суши и роллы. Люблю готовить сам, особенно выпечку.";1.78;"🟢 Развернутый ответ | ✅ Высокое смысловое соответствие | 📊 Хорошая структура ответа | 🏠 Подробное описание | ⭐ Высокий балл"
"""
# Сохраняем тестовые данные в файл
with open('test_data.csv', 'w', encoding='utf-8') as f:
f.write(test_data)
print("✅ Тестовый файл 'test_data.csv' создан успешно")
return True
def load_and_analyze_data():
"""Загрузка тестовых данных"""
file_path = 'test_data.csv'
try:
df = pd.read_csv(file_path, encoding='utf-8', delimiter=';')
print("✅ Тестовый файл загружен успешно")
except Exception as e:
print(f"❌ Ошибка загрузки: {e}")
return None
print("=" * 60)
print("ТЕСТОВЫЙ АНАЛИЗ AI-ОЦЕНОК")
print("=" * 60)
print(f"Размер данных: {df.shape[0]} строк, {df.shape[1]} колонок")
print(f"Колонки: {list(df.columns)}")
print(f"\nПервые 3 строки:")
print(df.head(3))
return df
def basic_statistics(df):
"""Базовая статистика"""
print("\n" + "=" * 40)
print("БАЗОВАЯ СТАТИСТИКА")
print("=" * 40)
print("AI оценки (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}")
print("\nОценки экзаменатора:")
print(f" Среднее: {df['Оценка экзаменатора'].mean():.3f}")
print(f" Медиана: {df['Оценка экзаменатора'].median():.3f}")
print(f" Стандартное отклонение: {df['Оценка экзаменатора'].std():.3f}")
print("\nРаспределение оценок экзаменатора:")
распределение = df['Оценка экзаменатора'].value_counts().sort_index()
for оценка, count in распределение.items():
print(f" {оценка}: {count} ответов ({count / len(df) * 100:.1f}%)")
def calculate_correlations(df):
"""Расчет корреляций"""
print("\n" + "=" * 40)
print("КОРРЕЛЯЦИИ И РАСХОЖДЕНИЯ")
print("=" * 40)
correlation = df[['Оценка экзаменатора', 'pred_score']].corr().iloc[0, 1]
print(f"Корреляция между оценками: {correlation:.3f}")
df['разница'] = df['pred_score'] - df['Оценка экзаменатора']
df['abs_разница'] = abs(df['разница'])
print(f"Средняя абсолютная разница: {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)
os.makedirs('graphs', exist_ok=True)
# 1. Scatter plot
plt.figure(figsize=(12, 8))
scatter = plt.scatter(df['Оценка экзаменатора'], df['pred_score'],
c=df['abs_разница'], cmap='viridis', alpha=0.7, s=80)
plt.colorbar(scatter, label='Абсолютная разница')
plt.plot([0, 2], [0, 2], 'r--', alpha=0.5, label='Идеальное соответствие')
plt.xlabel('Оценка экзаменатора', fontsize=12)
plt.ylabel('AI оценка (pred_score)', fontsize=12)
plt.title('Сравнение человеческой и AI оценки\n(цвет показывает величину расхождения)', fontsize=14)
plt.legend()
plt.grid(True, alpha=0.3)
plt.xticks([1, 2])
plt.savefig('graphs/test_scatter.png', dpi=300, bbox_inches='tight')
plt.close()
# 2. Гистограмма разниц
plt.figure(figsize=(12, 6))
plt.hist(df['разница'], bins=15, 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, label='Нулевая разница')
plt.axvline(x=df['разница'].mean(), color='orange', linestyle='--',
alpha=0.8, label=f'Средняя разница: {df["разница"].mean():.3f}')
plt.legend()
plt.savefig('graphs/test_histogram.png', dpi=300, bbox_inches='tight')
plt.close()
# 3. Box plot по вопросам
plt.figure(figsize=(12, 6))
box_data = [df[df['№ вопроса'] == question]['pred_score'].values
for question in sorted(df['№ вопроса'].unique())]
box_plot = plt.boxplot(box_data, labels=sorted(df['№ вопроса'].unique()),
patch_artist=True)
# Раскрашиваем boxplot
colors = ['lightblue', 'lightgreen', 'lightcoral', 'lightyellow', 'lightpink']
for patch, color in zip(box_plot['boxes'], colors):
patch.set_facecolor(color)
plt.title('Распределение AI оценок по номерам вопросов', fontsize=14)
plt.xlabel('Номер вопроса', fontsize=12)
plt.ylabel('AI оценка (pred_score)', fontsize=12)
plt.grid(True, alpha=0.3)
plt.savefig('graphs/test_boxplot.png', dpi=300, bbox_inches='tight')
plt.close()
print("✅ Графики сохранены в папку 'graphs/'")
def analyze_explanations(df):
"""Анализ объяснений"""
print("\n" + "=" * 40)
print("АНАЛИЗ ОБЪЯСНЕНИЙ")
print("=" * 40)
все_объяснения = ' '.join(df['объяснение_оценки'].dropna().astype(str))
слова = [word.strip() for word in все_объяснения.split() if len(word.strip()) > 2]
частотность = Counter(слова)
print("Топ-10 характеристик в объяснениях:")
for слово, count in частотность.most_common(10):
print(f" {слово}: {count}")
def save_detailed_analysis(df):
"""Сохранение детального анализа"""
print("\n" + "=" * 40)
print("СОХРАНЕНИЕ РЕЗУЛЬТАТОВ")
print("=" * 40)
# Создаем копию с анализом
df_analysis = df.copy()
# Добавляем категоризацию расхождений
условия = [
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: {e}")
def main():
"""Основная функция"""
print("Создание тестовых данных...")
if not create_test_data():
return
df = load_and_analyze_data()
if df is None:
return
basic_statistics(df)
calculate_correlations(df)
create_visualizations(df)
analyze_explanations(df)
save_detailed_analysis(df)
print("\n" + "=" * 60)
print("✅ ТЕСТОВЫЙ АНАЛИЗ ЗАВЕРШЕН!")
print("=" * 60)
print("📊 Созданные файлы:")
print(" • test_data.csv - тестовые данные")
print(" • graphs/test_scatter.png - сравнение оценок")
print(" • graphs/test_histogram.png - распределение разниц")
print(" • graphs/test_boxplot.png - оценки по вопросам")
print(" • detailed_analysis.xlsx - детальный отчет")
if __name__ == "__main__":
main()