Spaces:
Sleeping
Sleeping
File size: 7,509 Bytes
bcb314a |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 |
from __future__ import annotations
import re
import pandas as pd
from typing import List
def enhanced_q4_features(df: pd.DataFrame) -> pd.DataFrame:
"""
Улучшенные фичи для вопроса 4 - ВСЯ ЛОГИКА В ОДНОЙ ФУНКЦИИ
"""
out = df.copy()
if "question_number" not in out.columns:
raise ValueError("В датафрейме нет колонки 'question_number'")
for col in ["question_text", "answer_text"]:
if col not in out.columns:
out[col] = ""
mask = out["question_number"] == 4
q = out.loc[mask, "question_text"].fillna("").astype(str)
a = out.loc[mask, "answer_text"].fillna("").astype(str)
# --- БАЗОВЫЕ ФИЧИ ---
PLACE_WORDS = r"(?:кухн|парк|сквер|берег|река|дом|улиц|квартир|комнат|набережн)"
SEASON_WORDS = r"(?:лето|зим|весн|осен|снег|жарко|холодно|листопад|сосулк)"
PEOPLE_WORDS = r"(?:мама|папа|дедушк|бабушк|женщин|мужчин|ребен|дет|сем|дочка|сын|парень|девушк)"
ACTION_WORDS = r"(?:игра|моет|готов|накрыва|бежит|катает|кормит|сидит|спит|несет|перепрыг|гуляет)"
DETAIL_WORDS = r"(?:одет|рост|волос|глаз|характер|возраст|пальто|рубашк|кроссовк|плать|кофт|ботинк)"
PIC_INTRO = r"(?:на картинке|на рисунке|я вижу|изображен)"
CHILDREN_Q = r"(?:сколько детей|детям|о них|как.*играете.*дет(?:ями|ьми))"
FREE_TIME_Q = r"(?:свободн(?:ое|ым)\s+врем|как.*проводите.*время|выходн(?:ой|ые))"
# Базовые детекции
has_place_time = a.str.contains(PLACE_WORDS, case=False, regex=True) | a.str.contains(SEASON_WORDS, case=False,
regex=True)
has_people = a.str.contains(PEOPLE_WORDS, case=False, regex=True)
has_actions = a.str.contains(ACTION_WORDS, case=False, regex=True)
has_detail = a.str.contains(DETAIL_WORDS, case=False, regex=True)
expects_children = q.str.contains(CHILDREN_Q, case=False, regex=True)
expects_free = q.str.contains(FREE_TIME_Q, case=False, regex=True)
answered_children = a.str.contains(r"(?:у меня.*дет(?:и|ей)|в моей семье.*дет|сын|дочк|мы.*играем)", case=False,
regex=True)
answered_free = a.str.contains(
r"(?:свободн.*врем|обычно.*(?:в выходн|по выходн)|люблю|занимаюсь|хожу|смотрю|рисую|спорт|танц)", case=False,
regex=True)
non_cyr_ratio = a.apply(lambda t: (len(re.findall(r"[A-Za-z]", t)) / max(1, len(t))))
non_cyr_ratio = pd.to_numeric(non_cyr_ratio, errors="coerce").fillna(0.0).astype(float)
picture_first = a.str.contains(PIC_INTRO, case=False, regex=True)
dont_know = a.str.contains(r"(?:не знаю|не понимаю|трудно сказать|не могу описать)", case=False, regex=True)
# --- УЛУЧШЕННЫЕ ФИЧИ ---
# 1. Детекция всех подвопросов
subquestion_patterns = {
'place_time': r'(место|время|сезон|лето|зима|весна|осень|кухня|парк|улица)',
'people': r'(люди|человек|мужчина|женщина|ребенок|дети|семья|бабушка|дедушка)',
'actions': r'(делает|стоит|сидит|играет|готовит|моет|читает|смотрит)',
'person_detail': r'(одет|носит|платье|рубашка|брюки|волосы|глаза)',
'family_children': r'(дет[еи]|семь[яеи]|сын|дочь|брат|сестра)',
'playing': r'(игра[ею]|играем|гуля[ею]|занимаюсь)'
}
for name, pattern in subquestion_patterns.items():
out.loc[mask, f'q4_has_{name}'] = a.str.contains(pattern, case=False, regex=True).astype(int)
# 2. Структура ответа
def analyze_structure(text: str) -> dict:
text_lower = text.lower()
has_intro = any(marker in text_lower for marker in [
'на картинке', 'на рисунке', 'изображен', 'вижу', 'показан'
])
has_personal = any(marker in text_lower for marker in [
'у меня', 'в моей', 'мои', 'я ', 'мы ', 'наш'
])
sentences = re.split(r'[.!?]+', text)
num_sentences = len([s for s in sentences if len(s.strip()) > 10])
return {
'has_intro': has_intro,
'has_personal': has_personal,
'num_sentences': num_sentences
}
structure_features = a.apply(analyze_structure).apply(pd.Series)
out.loc[mask, 'q4_has_intro'] = structure_features['has_intro'].astype(int)
out.loc[mask, 'q4_has_personal'] = structure_features['has_personal'].astype(int)
out.loc[mask, 'q4_num_sentences'] = structure_features['num_sentences']
# 3. Полнота ответа
subq_columns = [f'q4_has_{name}' for name in subquestion_patterns.keys()]
out.loc[mask, 'q4_coverage_ratio'] = out.loc[mask, subq_columns].sum(axis=1) / len(subq_columns)
# 4. Базовые слоты (оригинальные фичи)
slots = (has_place_time.astype(int) + has_people.astype(int) + has_actions.astype(int) + has_detail.astype(int))
slots_covered = (slots / 4.0).clip(0, 1)
personal_ok = (
(expects_children & answered_children) |
(expects_free & answered_free) |
(~expects_children & ~expects_free)
)
# Заполняем базовые фичи
float_cols = ["q4_slots_covered", "q4_non_cyr_ratio"]
int_cols = [
"q4_has_place_time", "q4_has_people", "q4_has_actions", "q4_has_detail",
"q4_expects_children", "q4_expects_free", "q4_answered_personal",
"q4_picture_first", "q4_dont_know"
]
for name in float_cols:
out[name] = 0.0
for name in int_cols:
out[name] = 0
out.loc[mask, "q4_slots_covered"] = slots_covered.astype(float).to_numpy()
out.loc[mask, "q4_has_place_time"] = has_place_time.astype(int).to_numpy()
out.loc[mask, "q4_has_people"] = has_people.astype(int).to_numpy()
out.loc[mask, "q4_has_actions"] = has_actions.astype(int).to_numpy()
out.loc[mask, "q4_has_detail"] = has_detail.astype(int).to_numpy()
out.loc[mask, "q4_expects_children"] = expects_children.astype(int).to_numpy()
out.loc[mask, "q4_expects_free"] = expects_free.astype(int).to_numpy()
out.loc[mask, "q4_answered_personal"] = personal_ok.astype(int).to_numpy()
out.loc[mask, "q4_non_cyr_ratio"] = non_cyr_ratio.astype(float).to_numpy()
out.loc[mask, "q4_picture_first"] = picture_first.astype(int).to_numpy()
out.loc[mask, "q4_dont_know"] = dont_know.astype(int).to_numpy()
return out
# Совместимость с существующим кодом
def add_q4_features(df: pd.DataFrame) -> pd.DataFrame:
"""Совместимое имя функции для predict.py"""
return enhanced_q4_features(df) |