File size: 14,992 Bytes
172ee17 53fe915 172ee17 5071500 172ee17 53fe915 172ee17 53fe915 172ee17 53fe915 172ee17 53fe915 172ee17 53fe915 5071500 172ee17 53fe915 172ee17 53fe915 172ee17 53fe915 172ee17 53fe915 172ee17 53fe915 172ee17 53fe915 172ee17 53fe915 172ee17 53fe915 172ee17 53fe915 172ee17 53fe915 172ee17 53fe915 172ee17 53fe915 172ee17 53fe915 172ee17 53fe915 172ee17 53fe915 172ee17 53fe915 172ee17 53fe915 172ee17 53fe915 172ee17 53fe915 172ee17 53fe915 172ee17 53fe915 172ee17 53fe915 172ee17 53fe915 172ee17 53fe915 172ee17 |
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 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 |
import re
import hashlib
from typing import List, Dict
class DataNormalizer:
def __init__(self):
self.tag_keywords = {
'ml': ['машинное обучение', 'machine learning', 'ml', 'алгоритм', 'модель', 'классификация', 'регрессия'],
'dl': ['глубокое обучение', 'deep learning', 'нейронная сеть', 'cnn', 'rnn', 'transformer', 'нейросеть'],
'nlp': ['nlp', 'обработка естественного языка', 'natural language', 'текст', 'язык', 'токенизация'],
'cv': ['компьютерное зрение', 'computer vision', 'cv', 'изображение', 'видео', 'детекция', 'сегментация'],
'math': ['математика', 'математический', 'алгебра', 'геометрия', 'анализ', 'линейная алгебра', 'статистика'],
'stats': ['статистика', 'вероятность', 'статистический', 'probability', 'теория вероятностей'],
'product': ['продукт', 'product', 'разработка продукта', 'продуктовая', 'аналитика'],
'business': ['бизнес', 'business', 'менеджмент', 'управление', 'экономика', 'маркетинг'],
'pm': ['project management', 'управление проектами', 'pm', 'проект', 'agile', 'scrum'],
'systems': ['система', 'system', 'архитектура', 'инфраструктура', 'разработка'],
'data': ['данные', 'data', 'анализ данных', 'big data', 'база данных', 'sql', 'nosql'],
'research': ['исследование', 'research', 'наука', 'научный', 'диссертация', 'магистерская'],
'python': ['python', 'питон', 'программирование'],
'java': ['java', 'джава', 'программирование'],
'sql': ['sql', 'база данных', 'database'],
'git': ['git', 'версионирование', 'контроль версий'],
'docker': ['docker', 'контейнеризация', 'контейнер'],
'aws': ['aws', 'amazon', 'облако', 'cloud'],
'tensorflow': ['tensorflow', 'tf', 'фреймворк'],
'pytorch': ['pytorch', 'torch', 'фреймворк'],
'scikit-learn': ['scikit-learn', 'sklearn', 'библиотека']
}
def normalize_courses(self, courses: List[Dict]) -> List[Dict]:
"""Нормализует список курсов"""
normalized_courses = []
seen_hashes = set()
for course in courses:
normalized = self._normalize_course(course)
if normalized:
course_hash = self._calculate_course_hash(normalized)
if course_hash not in seen_hashes:
seen_hashes.add(course_hash)
normalized_courses.append(normalized)
return normalized_courses
def _normalize_course(self, course: Dict) -> Dict:
"""Нормализует отдельный курс"""
if not course.get('name'):
return None
normalized = course.copy()
# Нормализация названия
normalized['name'] = self._normalize_name(course['name'])
# Генерация короткого описания
normalized['short_desc'] = self._generate_short_desc(course)
# Генерация тегов
normalized['tags'] = self._generate_tags(course)
# Нормализация числовых полей
normalized['semester'] = self._normalize_semester(course.get('semester', 1))
normalized['credits'] = self._normalize_credits(course.get('credits', 0))
normalized['hours'] = self._normalize_hours(course.get('hours', 0))
normalized['type'] = self._normalize_type(course.get('type', 'required'))
return normalized
def _normalize_name(self, name: str) -> str:
"""Нормализует название курса"""
if not name:
return ''
name = str(name).strip()
# Удаляем лишние пробелы и символы
name = re.sub(r'\s+', ' ', name)
name = name.replace('"', '').replace('"', '').replace('«', '').replace('»', '')
# Убираем лишние скобки и символы
name = re.sub(r'^\s*[\(\)\[\]\-\s]+', '', name)
name = re.sub(r'[\(\)\[\]\-\s]+\s*$', '', name)
return name
def _generate_short_desc(self, course: Dict) -> str:
"""Генерирует короткое описание курса"""
name = course.get('name', '')
desc = course.get('description', '')
# Если есть описание, используем его
if desc:
desc = str(desc).strip()
if len(desc) > 220:
desc = desc[:220] + '...'
return desc
# Если название длинное, используем его как описание
if name and len(name) > 50:
return name[:220]
# Генерируем базовое описание
program_id = course.get('program_id', '')
semester = course.get('semester', 1)
if program_id == 'ai':
return f'Курс программы "Искусственный интеллект" ({semester} семестр)'
elif program_id == 'ai_product':
return f'Курс программы "AI Product Management" ({semester} семестр)'
else:
return f'Курс из учебного плана программы ({semester} семестр)'
def _generate_tags(self, course: Dict) -> List[str]:
"""Генерирует теги для курса"""
text = f"{course.get('name', '')} {course.get('short_desc', '')}".lower()
tags = []
for tag, keywords in self.tag_keywords.items():
if any(keyword in text for keyword in keywords):
tags.append(tag)
# Добавляем теги на основе программы
program_id = course.get('program_id', '')
if program_id == 'ai':
if 'ml' not in tags:
tags.append('ml')
elif program_id == 'ai_product':
if 'product' not in tags:
tags.append('product')
return list(set(tags)) # Убираем дубликаты
def _normalize_semester(self, semester) -> int:
"""Нормализует номер семестра"""
try:
semester = int(semester)
if 1 <= semester <= 4:
return semester
except (ValueError, TypeError):
pass
return 1
def _normalize_credits(self, credits) -> int:
"""Нормализует количество кредитов"""
try:
credits = int(credits)
if credits >= 0:
return credits
except (ValueError, TypeError):
pass
return 0
def _normalize_hours(self, hours) -> int:
"""Нормализует количество часов"""
try:
hours = int(hours)
if hours >= 0:
return hours
except (ValueError, TypeError):
pass
return 0
def _normalize_type(self, course_type: str) -> str:
"""Нормализует тип курса"""
if not course_type:
return 'required'
type_lower = str(course_type).lower()
if any(word in type_lower for word in ['обязательная', 'required', 'обяз', 'базовая']):
return 'required'
elif any(word in type_lower for word in ['по выбору', 'elective', 'выбор', 'электив', 'факультатив']):
return 'elective'
return 'required'
def _calculate_course_hash(self, course: Dict) -> str:
"""Вычисляет хэш курса для дедупликации"""
text = f"{course.get('name', '')}{course.get('program_id', '')}{course.get('semester', '')}"
return hashlib.md5(text.encode()).hexdigest()
def merge_courses(self, courses_list: List[List[Dict]]) -> List[Dict]:
"""Объединяет несколько списков курсов"""
all_courses = []
for courses in courses_list:
all_courses.extend(courses)
return self.normalize_courses(all_courses)
def validate_course(self, course: Dict) -> bool:
"""Проверяет валидность курса"""
required_fields = ['name', 'program_id', 'semester']
for field in required_fields:
if not course.get(field):
return False
if len(course.get('name', '')) < 3:
return False
return True
def get_statistics(self, courses: List[Dict]) -> Dict:
"""Получает статистику по курсам"""
stats = {
'total_courses': len(courses),
'by_program': {},
'by_semester': {},
'by_type': {},
'by_tags': {}
}
for course in courses:
program_id = course.get('program_id', 'unknown')
semester = course.get('semester', 1)
course_type = course.get('type', 'required')
tags = course.get('tags', [])
stats['by_program'][program_id] = stats['by_program'].get(program_id, 0) + 1
stats['by_semester'][semester] = stats['by_semester'].get(semester, 0) + 1
stats['by_type'][course_type] = stats['by_type'].get(course_type, 0) + 1
for tag in tags:
stats['by_tags'][tag] = stats['by_tags'].get(tag, 0) + 1
return stats
def enrich_courses(self, courses: List[Dict]) -> List[Dict]:
"""Обогащает курсы дополнительной информацией"""
for course in courses:
# Добавляем сложность курса
course['difficulty'] = self._calculate_difficulty(course)
# Добавляем рекомендуемый опыт
course['recommended_experience'] = self._calculate_recommended_experience(course)
# Добавляем категорию
course['category'] = self._determine_category(course)
return courses
def _calculate_difficulty(self, course: Dict) -> str:
"""Вычисляет сложность курса"""
name = course.get('name', '').lower()
credits = course.get('credits', 0)
semester = course.get('semester', 1)
# По ключевым словам
if any(word in name for word in ['продвинутый', 'advanced', 'углубленный']):
return 'advanced'
elif any(word in name for word in ['базовый', 'basic', 'введение', 'вводный']):
return 'beginner'
# По кредитам и семестру
if credits >= 6 or semester >= 3:
return 'intermediate'
elif credits <= 3 and semester <= 2:
return 'beginner'
else:
return 'intermediate'
def _calculate_recommended_experience(self, course: Dict) -> Dict:
"""Вычисляет рекомендуемый опыт для курса"""
difficulty = course.get('difficulty', 'intermediate')
tags = course.get('tags', [])
experience = {
'programming': 1,
'math': 1,
'ml': 0
}
if difficulty == 'advanced':
experience['programming'] = 4
experience['math'] = 3
elif difficulty == 'intermediate':
experience['programming'] = 2
experience['math'] = 2
else: # beginner
experience['programming'] = 1
experience['math'] = 1
# Корректировка по тегам
if 'ml' in tags or 'dl' in tags:
experience['ml'] = max(experience['ml'], 1)
if 'math' in tags or 'stats' in tags:
experience['math'] = max(experience['math'], 2)
if 'python' in tags or 'java' in tags:
experience['programming'] = max(experience['programming'], 2)
return experience
def _determine_category(self, course: Dict) -> str:
"""Определяет категорию курса"""
tags = course.get('tags', [])
name = course.get('name', '').lower()
if any(tag in tags for tag in ['ml', 'dl', 'nlp', 'cv']):
return 'ai_core'
elif any(tag in tags for tag in ['product', 'business', 'pm']):
return 'product_management'
elif any(tag in tags for tag in ['math', 'stats']):
return 'mathematics'
elif any(tag in tags for tag in ['systems', 'data']):
return 'systems_data'
elif 'research' in tags or 'диссертация' in name:
return 'research'
else:
return 'general'
def main():
normalizer = DataNormalizer()
# Тестовые курсы
test_courses = [
{
'id': 'test_1',
'program_id': 'ai',
'name': 'Машинное обучение',
'semester': 1,
'credits': 6,
'type': 'required'
},
{
'id': 'test_2',
'program_id': 'ai_product',
'name': 'Глубокое обучение',
'semester': 2,
'credits': 4,
'type': 'elective'
}
]
normalized = normalizer.normalize_courses(test_courses)
enriched = normalizer.enrich_courses(normalized)
stats = normalizer.get_statistics(enriched)
print(f'Нормализовано курсов: {len(normalized)}')
print(f'Статистика: {stats}')
for course in enriched:
print(f"- {course['name']}: {course['tags']} (сложность: {course['difficulty']})")
if __name__ == '__main__':
main()
|