# NTO AI 2025-2026: Baseline for the individual stage

*English translation by SOTA – AI Community of the Russian original. Organisers who would like this translation removed can email sota.ai.community@gmail.com.*

> **Disclaimer:** This baseline is only a starting point for your own solution. Participants can and should modify it as they see fit. We strongly recommend experimenting: trying different models and validation approaches, creating new features and building ensembles. This code is not a mandatory part of your final solution; it only helps you get started faster.

Baseline solution for the task of predicting users' book ratings in the NTO 2025/2026 competition ("Artificial Intelligence" profile).

## Description

The model predicts the rating (`rating`) from 0 to 10 that a user will give to a book.

**Model**: the gradient boosting library `LightGBM` is used

**Validation**: a methodologically correct split by time (`temporal split`) is applied. Training is done on earlier data and validation on later data, which simulates the real task

**Features**:

- Aggregated: mean ratings and numbers of ratings for users, books and authors.
- Metadata: gender, age, year of publication, language, publisher.
- Text (TF-IDF): features based on bigrams from the book descriptions.
- Text (BERT): embeddings from the Russian-language model `DeepPavlov/rubert-base-cased`.

## Quick start

### Virtual environment

Before installing the dependencies, it is recommended to create and activate a virtual environment to isolate the project's dependencies.

```bash
# Create the virtual environment
python -m venv .venv

# Activate (Linux/macOS)
source .venv/bin/activate

# Activate (Windows, PowerShell)
.venv\\Scripts\\Activate.ps1
```

### Installing Poetry

Poetry is used to manage the project's dependencies. If you do not have Poetry installed yet, use the official installation method.

**Linux / macOS / WSL (Windows)**

```bash
curl -sSL https://install.python-poetry.org | python3 -
```

After installation, you may need to add Poetry to `PATH`. Follow the instructions in the terminal.

**Windows (PowerShell)**

```powershell
(Invoke-WebRequest -Uri https://install.python-poetry.org -UseBasicParsing).Content | py -
```

Once `Poetry` has been installed successfully, you can move on to installing the project's dependencies.

### Installing the dependencies

```bash
poetry install
```

### Data structure

Make sure that the directory `data/raw/` contains the following files:

```
data/raw/
├── book_descriptions.csv
├── book_genres.csv
├── books.csv
├── genres.csv
├── sample_submission.csv
├── test.csv
├── train.csv
└── users.csv
```

### Running the pipeline

The pipeline is split into separate stages for efficiency and so that processed data can be reused:

```bash
# 1. Data preparation (loading, filtering, feature engineering)
poetry run python -m src.baseline.prepare_data

# 2. Model training (uses the prepared data)
poetry run python -m src.baseline.train

# 3. Prediction (uses the prepared data and the trained models)
poetry run python -m src.baseline.predict

# 4. Submission validation
poetry run python -m src.baseline.validate
```

Or via the Makefile:

```bash
make prepare-data  # Data preparation
make train         # Training
make predict       # Prediction
make validate      # Validation
make run           # Full cycle (prepare-data + train + predict + validate)
make clean         # Delete all generated files (data, models, submissions)
```

**Note:** Data preparation (`prepare-data`) must be run before training and prediction. The prepared data are saved in `data/processed/` and reused without recomputing the features.

## Project structure

```
.
├── data/
│   ├── raw/              # Source CSV files
│   ├── interim/          # Intermediate data (if needed)
│   └── processed/        # Processed data with features (parquet)
├── output/
│   ├── models/           # Trained models and the TF-IDF vectoriser
│   └── submissions/      # Submission files
├── src/baseline/
│   ├── config.py         # Configuration and model parameters
│   ├── constants.py      # Project constants (file and column names)
│   ├── data_processing.py # Loading and merging the raw data
│   ├── features.py       # Feature engineering (aggregates, genres, TF-IDF, BERT)
│   ├── prepare_data.py   # Data preparation (loading, processing, saving)
│   ├── temporal_split.py # Utilities for a correct temporal split of the data
│   ├── train.py          # Model training (uses the prepared data)
│   ├── predict.py        # Generating predictions (uses the prepared data)
│   ├── validate.py       # Checking the submission format
│   └── evaluate.py       # Evaluating prediction quality (metrics)
└── Makefile              # Convenient commands
```

## Implementation details

**Correct temporal validation**. The cut-off date is determined by the parameter `TEMPORAL_SPLIT_RATIO` in `config.py`. All interactions before this date are used for training and those after it for validation, which simulates the real task of predicting the future.

**Preventing data leaks**. Aggregate features (mean ratings, etc.) are computed *after* the temporal split. For the validation set, the aggregates are computed only from the data in the training part. When generating predictions for the test, the aggregates are computed over the whole training set.

**Split pipeline**. The process is split into three stages for efficiency:

1. `prepare-data`: creating *static* features (genres, text) without computing aggregates.
2. `train`: performing the temporal split, computing the dynamic aggregate features and training a single model.
3. `predict`: computing the aggregate features on the *entire* training dataset and generating predictions.

**Filtering of the training data**. Only records in which the book was read and rated (`has_read=1`) are used.

**Caching**. BERT embeddings and processed data are saved in `output/models/` and `data/processed/` to speed up repeated runs.

**Code quality**. `ruff` is used for linting and formatting, and the code is fully type-annotated.

## Model evaluation

The script `evaluate.py` is used to evaluate the quality of the predictions. This very script is located on the server and tests your solution. You can create your own test set and simulate the evaluation process on the server.

```
poetry run python -m src.baseline.evaluate --submission output/submissions/submission.csv --solution data/processed/custom_test_solution.csv
```

## Metric

Score is computed from RMSE and MAE:

```
Score = 1 - (0.5 * RMSE/10 + 0.5 * MAE/10)
```

Predictions are automatically clipped to the range [0, 10].

## Dependencies

- Python >= 3.10
- pandas, scikit-learn, lightgbm, joblib
- transformers, torch, sentencepiece
- ruff, pre-commit (dev)
