Бесплатный урок с нашим репетитором!

Узнать подробнее

Новая Школа - онлайн-школа подготовки к ЕГЭ
При поддержке
Посмотреть все вопросы нейросети
Бесплатный пробный урок с репетитором

Узнай больше про репетиторов Новой Школы и запишись на бесплатный пробный урок. Мы проверим твой уровень знаний и составим план обучения по любому предмету и классу

Вопрос от Анонимного юзера 03 октября 2025 11:36

Вам предстоит работать над каталогом мобильных приложений RuStore. В день на модерацию попадают сотни новых приложений. Чтобы пользователи могли легко находить нужное, каждое приложение должно быть привязано к одной или нескольким категориям — например, finance, tools, children, arcade. Сейчас модераторы тратят часы, вручную читая описание и определяя, куда отнести каждое приложение. Это долго, скучно и дорого. Ваша задача — автоматизировать этот процесс: научиться по тексту описания приложения определять его категории. Что дано Вам предоставлены тексты приложений в двух вариантах: full_description — полное описание приложения (если есть); shortDescription — краткое описание (если есть). app_name — название приложения; labels_str — целевые категории, перечисленные через “|”. Что нужно сделать По app_name и описаниям для приложений из тестового набора предсказать до трёх категорий, упорядоченных по убыванию уверенности. Формат ответа Файл TSV с колонками: app_name labels_str Метрика Hitrate@3 — если хотя бы одна правильная категория попала в топ-3 предсказаний, считаем это попаданием. H@3 = (# приложений с попаданием) / (# всех приложений) - Если приложение имеет 1 правильную метку, и она в топ-3 предсказаний → +1 - Если приложение имеет 2 правильные метки, и хотя бы одна в топ-3 → +1 - Усредняем по всем объектам теста. Учебный ноутбук: Это учебный ноутбук с кратким вводом в практику ML и базовым (бейзлайн) решением задания. Подходит для первого старта: используйте как отправную точку и улучшайте. Система оценки Количество баллов за задание определяется по формуле: Points = 300 ⋅ percentileofscore(H@3s, H@3), где Points – количество баллов, percentileofscore – функция, вычисляющая процентильное место участника, H@3s – значения метрики H@3 всех участников, H@3 – значение метрики данного участника.

Ответ нейросети

03 октября 2025 11:36

Ниже — подробное решение бейзлайна для задачи автоматического привязывания приложений RuStore к топ-3 категорий по текстам описаний. Цель: понять, как построить рабочий baseline, который можно легко улучшать.

Цель задачи

  • Понять: построить простую, воспроизводимую модель на основе текста, которая для каждого приложения предсказывает до трех категорий (упорядоченных по уверенности).
  • Метрика: Hitrate@3. для каждого приложения принимаем 1, если хотя бы одна из истинных меток попала в топ-3 предсказаний, иначе 0. Метрика в отчете рассчитывается как среднее по всем объектам.

Исходные данные (что нужно иметь)

  • app_name: название приложения
  • full_description: полное описание (если есть)
  • shortDescription: краткое описание (если есть)
  • labels_str: целевые категории, разделенные символом "|"

Формат вывода ( TSV)

  • Колонки: app_name labels_str Метрика Hitrate@3
  • Третья колонка — 0 или 1 для каждого приложения: 1, если intersection(true_labels, top3_pred) не пустое; 0 иначе.
  • Пример строки: UberWallet finance|tools 1

Подход (бейзлайн)

  • Комбинированный текстовый признак: объединяем app_name + full_description + shortDescription в один текстовый документ для каждого приложения.
  • Векторизация текста: TF-IDF (униграммы и биграммы, 1-2 граммы) с ограничением на число признаков (например, 50k–100k).
  • Модель: бинарная смесь "один против остальных" (OneVsRest) с логистической регрессией. Такой подход хорошо работает как базовый линейный метод на текстовых данных.
  • Формирование предсказаний: для каждого приложения получить предсказания вероятностей по всем классам, выбрать top-3 меток по вероятностям.
  • Привязка к тесту: сравнить top-3 с истинными метками (из labels_str). Если хотя бы одна совпадает — считать попаданием (1), иначе (0).

Пошаговый план реализации

  1. Подготовка данных

    • Объединить текст: text = app_name + " " + (full_description or "") + " " + (shortDescription or "")
    • Разделить метки: true_labels = labels_str.split("|") (убрать пустые)
  2. Разметка и разбиение

    • Собрать набор классов (которые встречаются в обучении):.classes
    • Преобразовать Y в бинарную матрицу MultiLabel (например, через MultiLabelBinarizer)
  3. Векторизация и обучение

    • Создать пайплайн: TfidfVectorizer(ngram_range=(1,2), max_features=100000) → OneVsRestClassifier(LogisticRegression(...))
    • Разделить данные на трейн/валидацию (например, train_test_split) для настройки гиперпараметров (C, max_features)
  4. Прогнозы для теста

    • Векторизовать тексты тестового набора
    • Получить предсказания вероятностей по всем классам (predict_proba)
    • Для каждого примера выбрать топ-3 метки по вероятностям (сохранить их в виде списка или строки с разделителем "|")
  5. Оценка Hitrate@3

    • Для каждого примера проверить пересечение true_labels и топ-3_pred
    • Если пересечение непустое — попадание (1), иначе 0
    • Среднее по всем примерам — значение Hitrate@3
  6. Экспорт результатов

    • Для каждого примента записать: app_name, labels_str, 0/1 (хитрейт@3)
    • Сохранить в TSV файл

Базовый код (Python, scikit-learn) Ниже приведен рабочий каркас, который можно адаптировать под ваши файлы. Обязательно подставьте пути к вашим данным и названия колонок в DataFrame.

  • Импорт нужных библиотек
  • Загрузка данных
  • Подготовка данных
  • Обучение baseline
  • Генерация предсказаний Top-3
  • Вычисление 0/1 для Hitrate@3 на тесте
  • Экспорт TSV

Пример кода (псевдо-реализация, пригодна для запуска после адаптации под ваши файлы)

  • Примечание: этот блок кода написан в виде последовательных инструкций на Python без использования сторонних ноутбуков. Его можно копировать в файл .py и запускать.

Импорт

import pandas as pd from sklearn.model_selection import train_test_split from sklearn.feature_extraction.text import TfidfVectorizer from sklearn.linear_model import LogisticRegression from sklearn.pipeline import Pipeline from sklearn.preprocessing import MultiLabelBinarizer from sklearn.multiclass import OneVsRestClassifier import numpy as np

Загрузка данных

Предположим, у вас есть train.csv и test.csv с колонками:

app_name, full_description, shortDescription, labels_str

train_path = "train.csv" test_path = "test.csv"

train_df = pd.read_csv(train_path) test_df = pd.read_csv(test_path)

Подготовка текста

def build_text(row): parts = [str(row.get("app_name", ""))] if "full_description" in row and pd.notnull(row["full_description"]): parts.append(str(row["full_description"])) if "shortDescription" in row and pd.notnull(row["shortDescription"]): parts.append(str(row["shortDescription"])) return " ".join(parts)

train_df["text"] = train_df.apply(build_text, axis=1) test_df["text"] = test_df.apply(build_text, axis=1)

Разделение признаков и целей

X = train_df["text"].fillna("").values y_true_str = train_df["labels_str"].fillna("").values # строки вида "finance|tools"

Преобразование меток в бинарную матрицу

Получаем полный набор классов из обучающих данных

all_labels = set() for s in y_true_str: if s: all_labels.update(s.split("|")) all_labels = sorted(list(all_labels))

Векторизация меток

mlb = MultiLabelBinarizer(classes=all_labels) y_true = mlb.fit_transform([l.split("|") if isinstance(l, str) and l else [] for l in y_true_str])

Разделение на трейн/валидацию (для бейзлайна можно использовать весь набор)

X_train, X_val, y_train, y_val = train_test_split(X, y_true, test_size=0.2, random_state=42)

Модель: TF-IDF + OneVsRest LogisticRegression

tfidf = TfidfVectorizer(max_features=100000, ngram_range=(1, 2), stop_words=None) clf = OneVsRestClassifier(LogisticRegression(max_iter=1000, solver="liblinear", C=1.0))

pipeline = Pipeline([ ("tfidf", tfidf), ("clf", clf) ])

Обучение

pipeline.fit(X_train, y_train)

Валидация (для понимания качества)

y_val_pred_proba = pipeline.predict_proba(X_val) # не всегда доступно напрямую в Pipeline

Если используем OneVsRestClassifier, predict_proba доступен

val_proba = pipeline.predict_proba(X_val)

val_top3 = np.argsort(-val_proba, axis=1)[:, :3]

Валидация может быть добавлена по желанию

Подготовка функций для предсказаний Top-3 и расчета попадания

def predict_top_k(texts, k=3): proba = pipeline.predict_proba(texts) # shape: [n_samples, n_classes] topk_indices = np.argsort(-proba, axis=1)[:, :k] # Преобразование индексов в имена меток topk_labels = [] for idxs in topk_indices: labels = [mlb.classes_[i] for i in idxs] topk_labels.append(labels) return topk_labels

def bool_hit(true_label_str, topk_labels): true_labels = set([t for t in (true_label_str.split("|") if isinstance(true_label_str, str) and true_label_str else [])]) pred_labels = set(topk_labels) return int(len(true_labels & pred_labels) > 0)

Прогнозы на тесте

test_texts = test_df["text"].fillna("").values top3_test = predict_top_k(test_texts, k=3)

Преобразование true_labels для тестового набора (если labels_str есть в тестовом наборе)

Если в тестовом наборе есть истинные метки, можно их считать; иначе заполняем пустые

test_true_label_strs = test_df.get("labels_str", pd.Series([""] * len(test_df))).fillna("").values

Рассчитываем попадания на тесте (0/1)

hits = [] for i in range(len(test_true_label_strs)): true_str = test_true_label_strs[i] hit = 0 if true_str: true_labels = set([t for t in true_str.split("|") if t]) pred_labels = set(top3_test[i]) if len(true_labels & pred_labels) > 0: hit = 1 else: # если нет истинных меток в тестовом наборе, считаем как 0 попаданий hit = 0 hits.append(hit)

Формируем TSV-вывод

app_name labels_str Метрика Hitrate@3

out_rows = [] for idx, row in test_df.iterrows(): app_name = str(row.get("app_name", "")) true_labels = row.get("labels_str", "") top3_labels = "|".join(top3_test[idx]) # Для файла TSV третья колонка — 0 или 1 hit_value = hits[idx] out_rows.append({"app_name": app_name, "labels_str": true_labels, "Метрика Hitrate@3": hit_value})

out_df = pd.DataFrame(out_rows) out_df.to_csv("predictions_hitrate3.tsv", sep="\t", index=False)

Примечания по коду

- В pipeline используется TF-IDF векторизация с ngram (1,2).

- OneVsRestClassifier обеспечивает мультилейбл-совмещение; для каждого класса обучается отдельный бинарный логистический регрессор.

- predict_proba возвращает вероятности для каждого класса; топ-3 выбираются по убыванию вероятности.

- Границы и параметры (max_features, C, solver) можно подбирать по валидации.

- В реальном проекте стоит вычислять Hitrate@3 на валидационном наборе до финальной сдачи, чтобы понять качество baseline.

Пояснения по вариациям и улучшениям

  • Варианты моделей:
    • LogisticRegression (как сейчас) — база. Можно сменить на LinearSVC с калибровкой вероятностей (CalibratedClassifierCV) для более устойчивого поведения на редких классах.
    • Binary Relevance (OneVsRest) уже реализован в базовом варианте. Можно рассмотреть ClassifierChain или metadata-обучение.
  • Векторизация:
    • Можно попробовать их/без остановочных слов (stop_words=None). Добавить character-level TF-IDF (ngram_range=(3,5)) для уловления специфических словоупотреблений.
  • Обработка данных:
    • Упростить обработку пустых полей; нормализовать текст (lowercase, удаление лишних символов).
  • Расширения:
    • Добавить контекст из описаний, использовать смещение по частоте слов.
    • Пробовать более продвинутые модели (LightGBM, CatBoost) на эмбеддингах слов, если есть достаточные данные.
    • Применять Label Powerset или Dependency-aware подходы, если множество категорий велико.

Что если у вас другие требования

  • Если цель состоит в максимально точном попадании в топ-3 на вашем наборе, можно адаптировать метрику на границе: попробовать разные k (например, 2 или 4) и сравнить результаты.
  • Если вы хотите, чтобы в TSV попадали именно три категории даже при меньшем числе кандидатных категорий, можно дополнить топ-3 фиктивными пустыми значениями, но обычно лучше вернуть реальный top-3 и оставить третий элемент как реальную метку.

Готов адаптировать под ваши данные

  • Сообщите, пожалуйста, форматы ваших файлов (названия колонок в train.csv и test.csv, наличие labels_str в тестовом наборе, и т.д.). Я могу подготовить конкретный скрипт под ваш набор данных и вычислить Hitrate@3 прямо локально на вашем примере.

Задай свой вопрос

Напиши любую задачу или вопрос, а нейросеть её решит

Похожие вопросы 15

Бесплатно Мобильное приложение ГДЗ
Мобильное приложение ГДЗ

Задавай вопросы искуcственному интеллекту текстом или фотографиями в приложении на iPhone или Android

qr-codegoogle-playapp-store

Саша — ассистент в телеграмме

Вам предстоит работать над каталогом мобильных приложений RuStore. В день на модерацию попадают сотни новых приложений. Чтобы пользователи могли легко находить нужное, каждое приложение должно быть привязано к одной или нескольким категориям — например, finance, tools, children, arcade. Сейчас модераторы тратят часы, вручную читая описание и определяя, куда отнести каждое приложение. Это долго, скучно и дорого. Ваша задача — автоматизировать этот процесс: научиться по тексту описания приложения определять его категории. Что дано Вам предоставлены тексты приложений в двух вариантах: full_description — полное описание приложения (если есть); shortDescription — краткое описание (если есть). app_name — название приложения; labels_str — целевые категории, перечисленные через “|”. Что нужно сделать По app_name и описаниям для приложений из тестового набора предсказать до трёх категорий, упорядоченных по убыванию уверенности. Формат ответа Файл TSV с колонками: app_name labels_str Метрика Hitrate@3 — если хотя бы одна правильная категория попала в топ-3 предсказаний, считаем это попаданием. H@3 = (# приложений с попаданием) / (# всех приложений) - Если приложение имеет 1 правильную метку, и она в топ-3 предсказаний → +1 - Если приложение имеет 2 правильные метки, и хотя бы одна в топ-3 → +1 - Усредняем по всем объектам теста. Учебный ноутбук: Это учебный ноутбук с кратким вводом в практику ML и базовым (бейзлайн) решением задания. Подходит для первого старта: используйте как отправную точку и улучшайте. Система оценки Количество баллов за задание определяется по формуле: Points = 300 ⋅ percentileofscore(H@3s, H@3), где Points – количество баллов, percentileofscore – функция, вычисляющая процентильное место участника, H@3s – значения метрики H@3 всех участников, H@3 – значение метрики данного участника.
Ниже — подробное решение бейзлайна для задачи автоматического привязывания приложений RuStore к топ-3 категорий по текстам описаний. Цель: понять, как построить рабочий baseline, который можно легко улучшать. Цель задачи - Понять: построить простую, воспроизводимую модель на основе текста, которая для каждого приложения предсказывает до трех категорий (упорядоченных по уверенности). - Метрика: Hitrate@3. для каждого приложения принимаем 1, если хотя бы одна из истинных меток попала в топ-3 предсказаний, иначе 0. Метрика в отчете рассчитывается как среднее по всем объектам. Исходные данные (что нужно иметь) - app_name: название приложения - full_description: полное описание (если есть) - shortDescription: краткое описание (если есть) - labels_str: целевые категории, разделенные символом "|" Формат вывода ( TSV) - Колонки: app_name labels_str Метрика Hitrate@3 - Третья колонка — 0 или 1 для каждого приложения: 1, если intersection(true_labels, top3_pred) не пустое; 0 иначе. - Пример строки: UberWallet finance|tools 1 Подход (бейзлайн) - Комбинированный текстовый признак: объединяем app_name + full_description + shortDescription в один текстовый документ для каждого приложения. - Векторизация текста: TF-IDF (униграммы и биграммы, 1-2 граммы) с ограничением на число признаков (например, 50k–100k). - Модель: бинарная смесь "один против остальных" (OneVsRest) с логистической регрессией. Такой подход хорошо работает как базовый линейный метод на текстовых данных. - Формирование предсказаний: для каждого приложения получить предсказания вероятностей по всем классам, выбрать top-3 меток по вероятностям. - Привязка к тесту: сравнить top-3 с истинными метками (из labels_str). Если хотя бы одна совпадает — считать попаданием (1), иначе (0). Пошаговый план реализации 1) Подготовка данных - Объединить текст: text = app_name + " " + (full_description or "") + " " + (shortDescription or "") - Разделить метки: true_labels = labels_str.split("|") (убрать пустые) 2) Разметка и разбиение - Собрать набор классов (которые встречаются в обучении):.classes - Преобразовать Y в бинарную матрицу MultiLabel (например, через MultiLabelBinarizer) 3) Векторизация и обучение - Создать пайплайн: TfidfVectorizer(ngram_range=(1,2), max_features=100000) → OneVsRestClassifier(LogisticRegression(...)) - Разделить данные на трейн/валидацию (например, train_test_split) для настройки гиперпараметров (C, max_features) 4) Прогнозы для теста - Векторизовать тексты тестового набора - Получить предсказания вероятностей по всем классам (predict_proba) - Для каждого примера выбрать топ-3 метки по вероятностям (сохранить их в виде списка или строки с разделителем "|") 5) Оценка Hitrate@3 - Для каждого примера проверить пересечение true_labels и топ-3_pred - Если пересечение непустое — попадание (1), иначе 0 - Среднее по всем примерам — значение Hitrate@3 6) Экспорт результатов - Для каждого примента записать: app_name, labels_str, 0/1 (хитрейт@3) - Сохранить в TSV файл Базовый код (Python, scikit-learn) Ниже приведен рабочий каркас, который можно адаптировать под ваши файлы. Обязательно подставьте пути к вашим данным и названия колонок в DataFrame. - Импорт нужных библиотек - Загрузка данных - Подготовка данных - Обучение baseline - Генерация предсказаний Top-3 - Вычисление 0/1 для Hitrate@3 на тесте - Экспорт TSV Пример кода (псевдо-реализация, пригодна для запуска после адаптации под ваши файлы) - Примечание: этот блок кода написан в виде последовательных инструкций на Python без использования сторонних ноутбуков. Его можно копировать в файл .py и запускать. # Импорт import pandas as pd from sklearn.model_selection import train_test_split from sklearn.feature_extraction.text import TfidfVectorizer from sklearn.linear_model import LogisticRegression from sklearn.pipeline import Pipeline from sklearn.preprocessing import MultiLabelBinarizer from sklearn.multiclass import OneVsRestClassifier import numpy as np # Загрузка данных # Предположим, у вас есть train.csv и test.csv с колонками: # app_name, full_description, shortDescription, labels_str train_path = "train.csv" test_path = "test.csv" train_df = pd.read_csv(train_path) test_df = pd.read_csv(test_path) # Подготовка текста def build_text(row): parts = [str(row.get("app_name", ""))] if "full_description" in row and pd.notnull(row["full_description"]): parts.append(str(row["full_description"])) if "shortDescription" in row and pd.notnull(row["shortDescription"]): parts.append(str(row["shortDescription"])) return " ".join(parts) train_df["text"] = train_df.apply(build_text, axis=1) test_df["text"] = test_df.apply(build_text, axis=1) # Разделение признаков и целей X = train_df["text"].fillna("").values y_true_str = train_df["labels_str"].fillna("").values # строки вида "finance|tools" # Преобразование меток в бинарную матрицу # Получаем полный набор классов из обучающих данных all_labels = set() for s in y_true_str: if s: all_labels.update(s.split("|")) all_labels = sorted(list(all_labels)) # Векторизация меток mlb = MultiLabelBinarizer(classes=all_labels) y_true = mlb.fit_transform([l.split("|") if isinstance(l, str) and l else [] for l in y_true_str]) # Разделение на трейн/валидацию (для бейзлайна можно использовать весь набор) X_train, X_val, y_train, y_val = train_test_split(X, y_true, test_size=0.2, random_state=42) # Модель: TF-IDF + OneVsRest LogisticRegression tfidf = TfidfVectorizer(max_features=100000, ngram_range=(1, 2), stop_words=None) clf = OneVsRestClassifier(LogisticRegression(max_iter=1000, solver="liblinear", C=1.0)) pipeline = Pipeline([ ("tfidf", tfidf), ("clf", clf) ]) # Обучение pipeline.fit(X_train, y_train) # Валидация (для понимания качества) # y_val_pred_proba = pipeline.predict_proba(X_val) # не всегда доступно напрямую в Pipeline # Если используем OneVsRestClassifier, predict_proba доступен # val_proba = pipeline.predict_proba(X_val) # val_top3 = np.argsort(-val_proba, axis=1)[:, :3] # Валидация может быть добавлена по желанию # Подготовка функций для предсказаний Top-3 и расчета попадания def predict_top_k(texts, k=3): proba = pipeline.predict_proba(texts) # shape: [n_samples, n_classes] topk_indices = np.argsort(-proba, axis=1)[:, :k] # Преобразование индексов в имена меток topk_labels = [] for idxs in topk_indices: labels = [mlb.classes_[i] for i in idxs] topk_labels.append(labels) return topk_labels def bool_hit(true_label_str, topk_labels): true_labels = set([t for t in (true_label_str.split("|") if isinstance(true_label_str, str) and true_label_str else [])]) pred_labels = set(topk_labels) return int(len(true_labels & pred_labels) > 0) # Прогнозы на тесте test_texts = test_df["text"].fillna("").values top3_test = predict_top_k(test_texts, k=3) # Преобразование true_labels для тестового набора (если labels_str есть в тестовом наборе) # Если в тестовом наборе есть истинные метки, можно их считать; иначе заполняем пустые test_true_label_strs = test_df.get("labels_str", pd.Series([""] * len(test_df))).fillna("").values # Рассчитываем попадания на тесте (0/1) hits = [] for i in range(len(test_true_label_strs)): true_str = test_true_label_strs[i] hit = 0 if true_str: true_labels = set([t for t in true_str.split("|") if t]) pred_labels = set(top3_test[i]) if len(true_labels & pred_labels) > 0: hit = 1 else: # если нет истинных меток в тестовом наборе, считаем как 0 попаданий hit = 0 hits.append(hit) # Формируем TSV-вывод # app_name labels_str Метрика Hitrate@3 out_rows = [] for idx, row in test_df.iterrows(): app_name = str(row.get("app_name", "")) true_labels = row.get("labels_str", "") top3_labels = "|".join(top3_test[idx]) # Для файла TSV третья колонка — 0 или 1 hit_value = hits[idx] out_rows.append({"app_name": app_name, "labels_str": true_labels, "Метрика Hitrate@3": hit_value}) out_df = pd.DataFrame(out_rows) out_df.to_csv("predictions_hitrate3.tsv", sep="\t", index=False) # Примечания по коду # - В pipeline используется TF-IDF векторизация с ngram (1,2). # - OneVsRestClassifier обеспечивает мультилейбл-совмещение; для каждого класса обучается отдельный бинарный логистический регрессор. # - predict_proba возвращает вероятности для каждого класса; топ-3 выбираются по убыванию вероятности. # - Границы и параметры (max_features, C, solver) можно подбирать по валидации. # - В реальном проекте стоит вычислять Hitrate@3 на валидационном наборе до финальной сдачи, чтобы понять качество baseline. Пояснения по вариациям и улучшениям - Варианты моделей: - LogisticRegression (как сейчас) — база. Можно сменить на LinearSVC с калибровкой вероятностей (CalibratedClassifierCV) для более устойчивого поведения на редких классах. - Binary Relevance (OneVsRest) уже реализован в базовом варианте. Можно рассмотреть ClassifierChain или metadata-обучение. - Векторизация: - Можно попробовать их/без остановочных слов (stop_words=None). Добавить character-level TF-IDF (ngram_range=(3,5)) для уловления специфических словоупотреблений. - Обработка данных: - Упростить обработку пустых полей; нормализовать текст (lowercase, удаление лишних символов). - Расширения: - Добавить контекст из описаний, использовать смещение по частоте слов. - Пробовать более продвинутые модели (LightGBM, CatBoost) на эмбеддингах слов, если есть достаточные данные. - Применять Label Powerset или Dependency-aware подходы, если множество категорий велико. Что если у вас другие требования - Если цель состоит в максимально точном попадании в топ-3 на вашем наборе, можно адаптировать метрику на границе: попробовать разные k (например, 2 или 4) и сравнить результаты. - Если вы хотите, чтобы в TSV попадали именно три категории даже при меньшем числе кандидатных категорий, можно дополнить топ-3 фиктивными пустыми значениями, но обычно лучше вернуть реальный top-3 и оставить третий элемент как реальную метку. Готов адаптировать под ваши данные - Сообщите, пожалуйста, форматы ваших файлов (названия колонок в train.csv и test.csv, наличие labels_str в тестовом наборе, и т.д.). Я могу подготовить конкретный скрипт под ваш набор данных и вычислить Hitrate@3 прямо локально на вашем примере.