# NTO 2025/2026 — "Artificial Intelligence" profile

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

## Team stage

This document is a reference for the data and for the format of the solution file.

---

## 1. Data description

**Main format of the source data:** CSV with a comma (`,`) separator for the processed files. The source metadata use a semicolon (`;`) separator.

### 1.0. Getting the data

The data are on the page https://ods.ai/competitions/nto25-26-2-team/dataset/ as the zip archive "stage2_team_data"

### 1.1. Files provided

| File | Description |
|------|----------|
| `train.csv` | The training history of user interactions with books. Contains data from the chronological slices before the time cut-off T_global, including the flags `has_read=0` ("planned") and `has_read=1` ("read"). **Important:** contains the column `timestamp` for analysing temporal patterns of interactions. |
| `targets.csv` | The list of `user_id` values of the users for whom a prediction must be produced. |
| `candidates.csv` | Candidate pools for ranking. For each user in `targets.csv`, contains a list of comma-separated `book_id` values. The list consists of: (1) all of the user's interactions from the test period (both `has_read=0` and `has_read=1`), (2) "cold" candidates — up to 15 additional books generated by a basic ALS model, with which the user never interacted. **Important:** the number of candidates varies, but does not exceed 20. **Timestamps (`timestamp`) are not provided**.|
| `books.csv` | Book metadata (author, year of publication, average rating, etc.). |
| `users.csv` | User metadata (gender, age). |
| `genres.csv` | Reference table of genres. |
| `book_genres.csv` | Table linking books and genres (many-to-many). |
| `book_descriptions.csv` | Text descriptions of books. Used to extract features via TF-IDF and BERT. |

### 1.2. Principles by which the data were formed

**Temporal split:** The data are split into the training and test sets by a single time cut-off T_global. All interactions in `train.csv` have `timestamp <= T_global`, and all interactions in the test period (used to form `candidates.csv` and `solution.csv`) have `timestamp > T_global`.

**Filtering of "warm" users:** The test set (`targets.csv`) includes only those users who have a sufficient history in the training set: at least 1 book read OR at least 3 planned books in `train.csv`.

**Forming the candidates:** For each user in `targets.csv`, `candidates.csv` includes:
1. All of the user's interactions from the test period (both read and planned)
2. "Cold" candidates — up to 15 additional books generated by a basic recommendation model (ALS), with which the user never interacted

The total number of candidates does not exceed 20. This makes the task harder and more realistic: participants must not only tell the books read from the planned ones, but also filter out the "cold" candidates.

**Forming the solution:** For each user, `solution.csv` gives two lists:
- `book_id_list_read`: Books that the user actually read (`has_read=1`) in the test period
- `book_id_list_planned`: Books that the user added to their plans (`has_read=0`) but did not read

If the user read nothing in the test period, `book_id_list_read` will be an empty string. If the user planned nothing, `book_id_list_planned` will be an empty string.

**Criterion for inclusion in the test set:** `targets.csv`, `candidates.csv` and `solution.csv` include all users who have a sufficient history in the training set (at least 1 book read OR at least 3 planned books in `train.csv`) and have at least one interaction in the test period. This covers both users who read books in the test period and those who only added books to their plans but read nothing.

> **Important:** For each user in `targets.csv`, the interactions from the test period are hidden from their history in `train.csv`. The number of hidden books read (`has_read=1`) varies from user to user: from 0 (if the user read nothing in the test period) to several dozen (depending on the user's real activity).

### 1.3. Description of the fields in the metadata

#### train.csv: Interaction history

| Field | Type | Description |
|------|-----|----------|
| `user_id` | int64 | Unique user identifier. |
| `book_id` | int64 | Unique book identifier. |
| `has_read` | int64 | Read flag: `0` — the book is on the "to read" list, `1` — the book has been read. |
| `rating` | float64 | The user's rating of the book (0-10). For `has_read=0` it is usually 0. |
| `timestamp` | datetime | Timestamp of the interaction. **Provided for analysing the users' interaction history.** |

#### targets.csv: Target users

| Field | Type | Description |
|------|-----|----------|
| `user_id` | int64 | Unique identifier of a user for whom a prediction must be produced. |

#### candidates.csv: Candidate pools

| Field | Type | Description |
|------|-----|----------|
| `user_id` | int64 | Unique user identifier. |
| `book_id_list` | str | A string containing a list of `book_id` values separated by commas (`,`). The list consists of: (1) all books the user interacted with in the test period (both read and planned), (2) "cold" candidates — up to 15 additional books generated by the ALS model. **The number of candidates varies, but does not exceed 20.** |

**Example row in candidates.csv:**
```
user_id,book_id_list
210,"971259,1281035,1673950,2225251,2274394"
```

#### books.csv: Book information

| Field | Type | Description |
|------|-----|----------|
| `book_id` | int64 | Unique book identifier (primary key). |
| `title` | str | Book title. |
| `author_id` | int64 | Unique author identifier. |
| `author_name` | str | Author name. |
| `publication_year` | int64 | Year of publication. |
| `language` | int64 | Numeric code of the book's language. |
| `avg_rating` | float64 | Average rating of the book, computed **only from the training set**. |
| `publisher` | int64 | Numeric code of the publisher. |

#### users.csv: User information

| Field | Type | Description |
|------|-----|----------|
| `user_id` | int64 | Unique user identifier (primary key). |
| `gender` | int64 | User's gender (1 — male, 2 — female). |
| `age` | int64 | User's age. |

#### genres.csv: Reference table of genres

| Field | Type | Description |
|------|-----|----------|
| `genre_id` | int64 | Unique genre identifier (primary key). |
| `genre_name` | str | Genre name. |
| `books_count` | int64 | Total number of books in this genre in the active sample. |

#### book_genres.csv: Link between books and genres

| Field | Type | Description |
|------|-----|----------|
| `book_id` | int64 | Book identifier (foreign key to books.csv). |
| `genre_id` | int64 | Genre identifier (foreign key to genres.csv). |

#### book_descriptions.csv: Book descriptions

| Field | Type | Description |
|------|-----|----------|
| `book_id` | int64 | Book identifier (foreign key to books.csv). |
| `description` | str | Text description of the book. |

---

## 2. Format of the solution file (submission)

The solution file must be in CSV format with a comma (`,`) separator. The file may contain the header `user_id,book_id_list`, which will be ignored during checking.

**Column structure:** `user_id,book_id_list`

**Requirements:**

- `user_id` — the identifier of a user from the file `targets.csv`.
- `book_id_list` — a string containing an ordered list of `book_id` identifiers separated by **commas** (`,`). Number of books in the list: **up to 20 books** (or all available candidates if there are fewer than 20). That is, for each user the top K is submitted, where K = min(20, number of candidates for that user).
- **Order matters:** the books must be ordered by decreasing estimated relevance (the most likely to be read at the start of the list).
- **Uniqueness:** the list must not contain duplicate `book_id` values.
- **Composition:** only `book_id` values from that user's candidate pool (from `candidates.csv`) may be used.

**Example contents of submission.csv:**

```
user_id,book_id_list
201,123,987,42,56,19,301,77,5,444,222,333,12,8,90,61,700,701,702,703,704
202,21,22,23,24,25
203,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119
```

**Explanation of the example:**
- User 201: 20 books (the top 20 of their candidates)
- User 202: 5 books (all available candidates, since there are fewer than 20)
- User 203: 20 books (the top 20 of their candidates)

**Important:** Unlike the `candidates.csv` format, where `book_id_list` may contain a variable number of books, the solution file (`submission.csv`) must contain **up to 20 books** for each user (or all available candidates if there are fewer than 20). This means that if a user has only 5 books in `candidates.csv`, then `submission.csv` must contain 5 books for that user. If a user has more than 20 candidates, then `submission.csv` must contain the 20 most relevant books.

**Ranking order:** The books must be ordered by decreasing relevance. The ideal order:
1. First, all books read (relevance = 2)
2. Then all planned books (relevance = 1)
3. At the end, the "cold" candidates (relevance = 0)

---

## 3. Format of the file with the reference values (solution.csv)

The file `solution.csv` contains the reference values for evaluating a solution. It is kept in a private directory and is not available to participants until the competition ends. However, participants can generate a similar file themselves for checking with `evaluate.py`.

**Column structure:** `user_id,book_id_list_read,book_id_list_planned,stage`

**Field descriptions:**

| Field | Type | Description |
|------|-----|----------|
| `user_id` | int64 | Unique user identifier. |
| `book_id_list_read` | str | A string containing the list of `book_id` values of the books read (`has_read=1`), separated by commas (`,`). If the user read nothing, the string is empty. |
| `book_id_list_planned` | str | A string containing the list of `book_id` values of the planned books (`has_read=0`), separated by commas (`,`). If the user planned nothing, the string is empty. |
| `stage` | str | Indicator of the evaluation stage: `"public"` (public leaderboard) or `"private"` (private leaderboard). |

**Example contents of solution.csv:**

```
user_id,book_id_list_read,book_id_list_planned,stage
210,"971259,1281035,1673950","2225251,2274394,2447113",private
211,"",3015694,public
212,3988468,"",private
```

**Explanation of the example:**
- User 210: read 3 books, planned 3 books
- User 211: read nothing, planned 1 book
- User 212: read 1 book, planned nothing

**Important:** All books in `book_id_list_read` and `book_id_list_planned` are always present in `candidates.csv` for the corresponding user. "Cold" candidates are absent from both lists.
