diff --git a/mypy.ini b/mypy.ini index 3e6252bc..eb9d0f09 100644 --- a/mypy.ini +++ b/mypy.ini @@ -1,2 +1,3 @@ [mypy] allow_untyped_calls = true +ignore_missing_imports = True diff --git a/notebooks/ALS_LightFM_MF.ipynb b/notebooks/ALS_LightFM_MF.ipynb new file mode 100644 index 00000000..fdb48263 --- /dev/null +++ b/notebooks/ALS_LightFM_MF.ipynb @@ -0,0 +1,4890 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "collapsed": false + }, + "source": [ + "# Домашнее задание\n", + "\n", + "Домашнее задание состоит из нескольких блоков.\n", + "\n", + "\n", + "## Эксперименты в ipynb ноутбуках (15 баллов)\n", + "- Необходимо будет перебрать $N$ моделей $(N \\geq 2)$ матричной факторизации и перебрать у них $K$ гиперпараметров $(K \\geq 2)$ **(6 баллов)**\n", + " - Для перебора гиперпараметров можно использовать [`Optuna`](https://github.com/optuna/optuna), [`Hyperopt`](https://github.com/hyperopt/hyperopt)\n", + "- Воспользоваться методом приближенного поиска соседей для выдачи рекомендаций. **(3 балла)**\n", + " - Можно использовать любые удобные: [`Annoy`](https://github.com/spotify/annoy), [`nmslib`](https://github.com/nmslib/nmslib) и.т.д\n", + "- Добавить 3 \"аватаров\" (искусственных пользователей) и посмотреть рекомендации итоговой модели на них. Объяснить почему добавили именно таких пользователей. **(3 балла)**\n", + "- Придумать как можно обработать рекомендации для холодных пользователей. **(3 балла)**\n", + "\n", + "Примечание: за невоспроизводимый код в ноутбуках (например, нарушен порядок выполнения ячеек, вызываются переменные, которые нигде не были объявлены ранее и.т.п) будут штрафы на усмотрение проверяющего.\n", + "\n", + "\n", + "## Реализация итоговой модели в сервисе (10 баллов)\n", + "- Пробитие бейзлайна $MAP@10 \\geq 0.074921$ **(6 баллов)**\n", + "- Код сервиса соответствует критериям читаемости и воспроизводимости **(4 балла)**" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import warnings\n", + "warnings.filterwarnings('ignore')" + ] + }, + { + "cell_type": "code", + "execution_count": 246, + "id": "e42a5585", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import time\n", + "import random\n", + "from pathlib import Path\n", + "\n", + "import numpy as np\n", + "import optuna\n", + "import pandas as pd\n", + "\n", + "import nmslib\n", + "from implicit.als import AlternatingLeastSquares\n", + "from lightfm import LightFM\n", + "from rectools import Columns\n", + "from rectools.dataset import Dataset\n", + "from rectools.metrics import MAP, Precision, Recall, calc_metrics\n", + "from rectools.models import ImplicitALSWrapperModel, LightFMWrapperModel" + ] + }, + { + "cell_type": "code", + "execution_count": 180, + "id": "8cd36e1a", + "metadata": {}, + "outputs": [], + "source": [ + "os.environ['OPENBLAS_NUM_THREADS'] = \"1\"" + ] + }, + { + "cell_type": "code", + "execution_count": 185, + "id": "4cb722c3", + "metadata": {}, + "outputs": [], + "source": [ + "DATA_PATH = Path(\"../data/kion_train/\")" + ] + }, + { + "cell_type": "code", + "execution_count": 186, + "id": "8195e56b", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 2.61 s, sys: 924 ms, total: 3.53 s\n", + "Wall time: 5.74 s\n" + ] + } + ], + "source": [ + "%%time\n", + "users = pd.read_csv(DATA_PATH / 'users.csv')\n", + "items = pd.read_csv(DATA_PATH / 'items.csv')\n", + "interactions = pd.read_csv(DATA_PATH / 'interactions.csv')" + ] + }, + { + "cell_type": "code", + "execution_count": 187, + "id": "01c2bdef", + "metadata": {}, + "outputs": [], + "source": [ + "Columns.Datetime = 'last_watch_dt'" + ] + }, + { + "cell_type": "markdown", + "id": "00b5584e", + "metadata": {}, + "source": [ + "# Preprocess Interactions" + ] + }, + { + "cell_type": "code", + "execution_count": 188, + "id": "0a3b4b12", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
user_iditem_idlast_watch_dttotal_durwatched_pct
017654995062021-05-11425072.0
169931716592021-05-298317100.0
265668371072021-05-09100.0
386461376382021-07-0514483100.0
496486895062021-04-306725100.0
\n", + "
" + ], + "text/plain": [ + " user_id item_id last_watch_dt total_dur watched_pct\n", + "0 176549 9506 2021-05-11 4250 72.0\n", + "1 699317 1659 2021-05-29 8317 100.0\n", + "2 656683 7107 2021-05-09 10 0.0\n", + "3 864613 7638 2021-07-05 14483 100.0\n", + "4 964868 9506 2021-04-30 6725 100.0" + ] + }, + "execution_count": 188, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "interactions.head()" + ] + }, + { + "cell_type": "code", + "execution_count": 189, + "id": "260b1c48", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "user_id int64\n", + "item_id int64\n", + "last_watch_dt object\n", + "total_dur int64\n", + "watched_pct float64\n", + "dtype: object" + ] + }, + "execution_count": 189, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "interactions.dtypes" + ] + }, + { + "cell_type": "code", + "execution_count": 190, + "id": "fe2dbc06", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "user_id 0\n", + "item_id 0\n", + "last_watch_dt 0\n", + "total_dur 0\n", + "watched_pct 828\n", + "dtype: int64" + ] + }, + "execution_count": 190, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "interactions.isna().sum()" + ] + }, + { + "cell_type": "code", + "execution_count": 191, + "id": "71f61e81", + "metadata": {}, + "outputs": [], + "source": [ + "interactions[Columns.Datetime] = \\\n", + " pd.to_datetime(interactions[Columns.Datetime], format='%Y-%m-%d')" + ] + }, + { + "cell_type": "code", + "execution_count": 192, + "id": "39646cb5", + "metadata": {}, + "outputs": [], + "source": [ + "interactions.dropna(inplace=True)" + ] + }, + { + "cell_type": "code", + "execution_count": 193, + "id": "f98ae95d", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "interactions['watched_pct'].hist(bins=20);" + ] + }, + { + "cell_type": "markdown", + "id": "1a0ad9f8", + "metadata": {}, + "source": [ + "Делю график просмотра на 5 категорий, где:\n", + "от 0% до 20% = 1,\n", + "от 21% до 40% = 2,\n", + "... ,\n", + "от 80% до 100% = 5" + ] + }, + { + "cell_type": "code", + "execution_count": 194, + "id": "1424e744", + "metadata": {}, + "outputs": [], + "source": [ + "interactions[Columns.Weight] = pd.cut(\n", + " x=interactions['watched_pct'],\n", + " bins=5,\n", + " labels=[1, 2, 3, 4, 5]\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 196, + "id": "052d2fb0", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "interactions[Columns.Datetime].hist(bins=20);" + ] + }, + { + "cell_type": "markdown", + "id": "5adb80ee", + "metadata": {}, + "source": [ + "Вообще, видно, что кол-во пользователей растет" + ] + }, + { + "cell_type": "code", + "execution_count": 197, + "id": "0fbd2bbc", + "metadata": {}, + "outputs": [], + "source": [ + "cold_users = \\\n", + " interactions[Columns.User].value_counts()[interactions[Columns.User].value_counts() == 1].index" + ] + }, + { + "cell_type": "code", + "execution_count": 198, + "id": "150e1593", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "interactions[interactions[Columns.User].isin(cold_users)]['watched_pct'\n", + " ].hist(bins=20);" + ] + }, + { + "cell_type": "markdown", + "id": "b5fa83eb", + "metadata": {}, + "source": [ + "Для холодных пользователей, я бы рекомендовал айтемы с самый высоким просмотром в среднем по холодным пользователям" + ] + }, + { + "cell_type": "code", + "execution_count": 199, + "id": "cca06e3f", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
user_iditem_idlast_watch_dttotal_durwatched_pctweight
1079146681992021-07-277139.01
26181144104402021-08-082740840.02
37161176104402021-07-29220.01
382172318192021-04-118535100.05
607721681432021-05-0866011.01
.....................
5476222100790097282021-08-124166.01
547622588213847162021-05-2115942.01
5476238805174131252021-06-2710.01
5476246648596122252021-08-13760.01
5476248697262152972021-08-201830763.04
\n", + "

355162 rows × 6 columns

\n", + "
" + ], + "text/plain": [ + " user_id item_id last_watch_dt total_dur watched_pct weight\n", + "10 791466 8199 2021-07-27 713 9.0 1\n", + "26 181144 10440 2021-08-08 27408 40.0 2\n", + "37 161176 10440 2021-07-29 22 0.0 1\n", + "38 21723 1819 2021-04-11 8535 100.0 5\n", + "60 77216 8143 2021-05-08 660 11.0 1\n", + "... ... ... ... ... ... ...\n", + "5476222 1007900 9728 2021-08-12 416 6.0 1\n", + "5476225 882138 4716 2021-05-21 1594 2.0 1\n", + "5476238 805174 13125 2021-06-27 1 0.0 1\n", + "5476246 648596 12225 2021-08-13 76 0.0 1\n", + "5476248 697262 15297 2021-08-20 18307 63.0 4\n", + "\n", + "[355162 rows x 6 columns]" + ] + }, + "execution_count": 199, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "cold_users = interactions[interactions[Columns.User].isin(cold_users)]\n", + "hot_users = interactions[~interactions[Columns.User].isin(cold_users)]\n", + "cold_users" + ] + }, + { + "cell_type": "code", + "execution_count": 200, + "id": "a691676f", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
user_iditem_idlast_watch_dttotal_durwatched_pctweight
017654995062021-05-11425072.04
169931716592021-05-298317100.05
265668371072021-05-09100.01
386461376382021-07-0514483100.05
496486895062021-04-306725100.05
.....................
5476246648596122252021-08-13760.01
547624754686296732021-04-13230849.03
5476248697262152972021-08-201830763.04
5476249384202161972021-04-196203100.05
547625031970944362021-08-15392145.03
\n", + "

5475423 rows × 6 columns

\n", + "
" + ], + "text/plain": [ + " user_id item_id last_watch_dt total_dur watched_pct weight\n", + "0 176549 9506 2021-05-11 4250 72.0 4\n", + "1 699317 1659 2021-05-29 8317 100.0 5\n", + "2 656683 7107 2021-05-09 10 0.0 1\n", + "3 864613 7638 2021-07-05 14483 100.0 5\n", + "4 964868 9506 2021-04-30 6725 100.0 5\n", + "... ... ... ... ... ... ...\n", + "5476246 648596 12225 2021-08-13 76 0.0 1\n", + "5476247 546862 9673 2021-04-13 2308 49.0 3\n", + "5476248 697262 15297 2021-08-20 18307 63.0 4\n", + "5476249 384202 16197 2021-04-19 6203 100.0 5\n", + "5476250 319709 4436 2021-08-15 3921 45.0 3\n", + "\n", + "[5475423 rows x 6 columns]" + ] + }, + "execution_count": 200, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "hot_users" + ] + }, + { + "cell_type": "code", + "execution_count": 201, + "id": "a64701c2", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
item_id
1044045695
1529739309
265720474
972815140
474011455
......
19461
138861
140901
57301
131251
\n", + "

6440 rows × 1 columns

\n", + "
" + ], + "text/plain": [ + " item_id\n", + "10440 45695\n", + "15297 39309\n", + "2657 20474\n", + "9728 15140\n", + "4740 11455\n", + "... ...\n", + "1946 1\n", + "13886 1\n", + "14090 1\n", + "5730 1\n", + "13125 1\n", + "\n", + "[6440 rows x 1 columns]" + ] + }, + "execution_count": 201, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "cold_users['item_id'].value_counts().to_frame()" + ] + }, + { + "cell_type": "code", + "execution_count": 202, + "id": "cef9cfa6", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Int64Index([609, 4895, 3825, 5069, 14092, 12593, 7142, 2271, 13673, 11566], dtype='int64', name='item_id')" + ] + }, + "execution_count": 202, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "cold_users[['item_id', 'total_dur']].groupby('item_id').mean().sort_values(by='total_dur', ascending=False).head(10).index" + ] + }, + { + "cell_type": "markdown", + "id": "a52f311b", + "metadata": {}, + "source": [ + "# Делим на train и test" + ] + }, + { + "cell_type": "code", + "execution_count": 203, + "id": "bd68d3fe", + "metadata": {}, + "outputs": [], + "source": [ + "max_date = interactions[Columns.Datetime].max()" + ] + }, + { + "cell_type": "code", + "execution_count": 204, + "id": "3092fe4b", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "train: (4984443, 6)\n", + "test: (490980, 6)\n" + ] + } + ], + "source": [ + "train = interactions[interactions[Columns.Datetime] < max_date\n", + " - pd.Timedelta(days=7)].copy()\n", + "test = interactions[interactions[Columns.Datetime] >= max_date\n", + " - pd.Timedelta(days=7)].copy()\n", + "\n", + "print(f\"train: {train.shape}\")\n", + "print(f\"test: {test.shape}\")" + ] + }, + { + "cell_type": "code", + "execution_count": 205, + "id": "ec286bdc", + "metadata": {}, + "outputs": [], + "source": [ + "train.drop(train.query(\"total_dur < 300\").index, inplace=True)" + ] + }, + { + "cell_type": "code", + "execution_count": 206, + "id": "52241fed", + "metadata": {}, + "outputs": [], + "source": [ + "drop_user = set(test[Columns.User]) - set(train[Columns.User])\n", + "test.drop(test[test[Columns.User].isin(drop_user)].index, inplace=True)" + ] + }, + { + "cell_type": "markdown", + "id": "b5eec6da", + "metadata": {}, + "source": [ + "## User preprocess" + ] + }, + { + "cell_type": "code", + "execution_count": 207, + "id": "c57e2b2f", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
user_idageincomesexkids_flg
0973171age_25_34income_60_90М1
1962099age_18_24income_20_40М0
21047345age_45_54income_40_60Ж0
3721985age_45_54income_20_40Ж0
4704055age_35_44income_60_90Ж0
..................
840192339025age_65_infincome_0_20Ж0
840193983617age_18_24income_20_40Ж1
840194251008NaNNaNNaN0
840195590706NaNNaNЖ0
840196166555age_65_infincome_20_40Ж0
\n", + "

840197 rows × 5 columns

\n", + "
" + ], + "text/plain": [ + " user_id age income sex kids_flg\n", + "0 973171 age_25_34 income_60_90 М 1\n", + "1 962099 age_18_24 income_20_40 М 0\n", + "2 1047345 age_45_54 income_40_60 Ж 0\n", + "3 721985 age_45_54 income_20_40 Ж 0\n", + "4 704055 age_35_44 income_60_90 Ж 0\n", + "... ... ... ... ... ...\n", + "840192 339025 age_65_inf income_0_20 Ж 0\n", + "840193 983617 age_18_24 income_20_40 Ж 1\n", + "840194 251008 NaN NaN NaN 0\n", + "840195 590706 NaN NaN Ж 0\n", + "840196 166555 age_65_inf income_20_40 Ж 0\n", + "\n", + "[840197 rows x 5 columns]" + ] + }, + "execution_count": 207, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "users" + ] + }, + { + "cell_type": "code", + "execution_count": 208, + "id": "24cc138a", + "metadata": {}, + "outputs": [], + "source": [ + "users = users.loc[users[Columns.User].isin(train[Columns.User])].copy()" + ] + }, + { + "cell_type": "code", + "execution_count": 209, + "id": "6e5e2d92", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
user_idageincomesexkids_flg
0973171age_25_34income_60_90М1
1962099age_18_24income_20_40М0
3721985age_45_54income_20_40Ж0
4704055age_35_44income_60_90Ж0
51037719age_45_54income_60_90М0
..................
840184529394age_25_34income_40_60Ж0
84018680113age_25_34income_40_60Ж0
840188312839age_65_infincome_60_90Ж0
840189191349age_45_54income_40_60М1
840190393868age_25_34income_20_40М0
\n", + "

586653 rows × 5 columns

\n", + "
" + ], + "text/plain": [ + " user_id age income sex kids_flg\n", + "0 973171 age_25_34 income_60_90 М 1\n", + "1 962099 age_18_24 income_20_40 М 0\n", + "3 721985 age_45_54 income_20_40 Ж 0\n", + "4 704055 age_35_44 income_60_90 Ж 0\n", + "5 1037719 age_45_54 income_60_90 М 0\n", + "... ... ... ... .. ...\n", + "840184 529394 age_25_34 income_40_60 Ж 0\n", + "840186 80113 age_25_34 income_40_60 Ж 0\n", + "840188 312839 age_65_inf income_60_90 Ж 0\n", + "840189 191349 age_45_54 income_40_60 М 1\n", + "840190 393868 age_25_34 income_20_40 М 0\n", + "\n", + "[586653 rows x 5 columns]" + ] + }, + "execution_count": 209, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "users" + ] + }, + { + "cell_type": "markdown", + "id": "c7f9a6e7", + "metadata": {}, + "source": [ + "Заменяю Nan'ы на Unknown" + ] + }, + { + "cell_type": "code", + "execution_count": 210, + "id": "1286eb60", + "metadata": {}, + "outputs": [], + "source": [ + "users.fillna('Unknown', inplace=True)" + ] + }, + { + "cell_type": "code", + "execution_count": 211, + "id": "1ccccf0f", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
idvaluefeature
0973171Мsex
1962099Мsex
3721985Жsex
4704055Жsex
51037719Мsex
\n", + "
" + ], + "text/plain": [ + " id value feature\n", + "0 973171 М sex\n", + "1 962099 М sex\n", + "3 721985 Ж sex\n", + "4 704055 Ж sex\n", + "5 1037719 М sex" + ] + }, + "execution_count": 211, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "user_features_frames = []\n", + "for feature in ['sex', 'age', 'income']:\n", + " feature_frame = users.reindex(columns=[Columns.User, feature])\n", + " feature_frame.columns = ['id', 'value']\n", + " feature_frame['feature'] = feature\n", + " user_features_frames.append(feature_frame)\n", + "user_features = pd.concat(user_features_frames)\n", + "user_features.head()" + ] + }, + { + "cell_type": "markdown", + "id": "b9220b0b", + "metadata": {}, + "source": [ + "## Item preprocess" + ] + }, + { + "cell_type": "code", + "execution_count": 213, + "id": "8bbe9ee4", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
item_idcontent_typetitletitle_origrelease_yeargenrescountriesfor_kidsage_ratingstudiosdirectorsactorsdescriptionkeywords
010711filmПоговори с нейHable con ella2002.0драмы, зарубежные, детективы, мелодрамыИспанияNaN16.0NaNПедро АльмодоварАдольфо Фернандес, Ана Фернандес, Дарио Гранди...Мелодрама легендарного Педро Альмодовара «Пого...Поговори, ней, 2002, Испания, друзья, любовь, ...
12508filmГолые перцыSearch Party2014.0зарубежные, приключения, комедииСШАNaN16.0NaNСкот АрмстронгАдам Палли, Брайан Хаски, Дж.Б. Смув, Джейсон ...Уморительная современная комедия на популярную...Голые, перцы, 2014, США, друзья, свадьбы, прео...
210716filmТактическая силаTactical Force2011.0криминал, зарубежные, триллеры, боевики, комедииКанадаNaN16.0NaNАдам П. КалтрароАдриан Холмс, Даррен Шалави, Джерри Вассерман,...Профессиональный рестлер Стив Остин («Все или ...Тактическая, сила, 2011, Канада, бандиты, ганг...
37868film45 лет45 Years2015.0драмы, зарубежные, мелодрамыВеликобританияNaN16.0NaNЭндрю ХэйАлександра Риддлстон-Барретт, Джеральдин Джейм...Шарлотта Рэмплинг, Том Кортни, Джеральдин Джей...45, лет, 2015, Великобритания, брак, жизнь, лю...
416268filmВсе решает мгновениеNaN1978.0драмы, спорт, советские, мелодрамыСССРNaN12.0ЛенфильмВиктор СадовскийАлександр Абдулов, Александр Демьяненко, Алекс...Расчетливая чаровница из советского кинохита «...Все, решает, мгновение, 1978, СССР, сильные, ж...
\n", + "
" + ], + "text/plain": [ + " item_id content_type title title_orig release_year \\\n", + "0 10711 film Поговори с ней Hable con ella 2002.0 \n", + "1 2508 film Голые перцы Search Party 2014.0 \n", + "2 10716 film Тактическая сила Tactical Force 2011.0 \n", + "3 7868 film 45 лет 45 Years 2015.0 \n", + "4 16268 film Все решает мгновение NaN 1978.0 \n", + "\n", + " genres countries for_kids \\\n", + "0 драмы, зарубежные, детективы, мелодрамы Испания NaN \n", + "1 зарубежные, приключения, комедии США NaN \n", + "2 криминал, зарубежные, триллеры, боевики, комедии Канада NaN \n", + "3 драмы, зарубежные, мелодрамы Великобритания NaN \n", + "4 драмы, спорт, советские, мелодрамы СССР NaN \n", + "\n", + " age_rating studios directors \\\n", + "0 16.0 NaN Педро Альмодовар \n", + "1 16.0 NaN Скот Армстронг \n", + "2 16.0 NaN Адам П. Калтраро \n", + "3 16.0 NaN Эндрю Хэй \n", + "4 12.0 Ленфильм Виктор Садовский \n", + "\n", + " actors \\\n", + "0 Адольфо Фернандес, Ана Фернандес, Дарио Гранди... \n", + "1 Адам Палли, Брайан Хаски, Дж.Б. Смув, Джейсон ... \n", + "2 Адриан Холмс, Даррен Шалави, Джерри Вассерман,... \n", + "3 Александра Риддлстон-Барретт, Джеральдин Джейм... \n", + "4 Александр Абдулов, Александр Демьяненко, Алекс... \n", + "\n", + " description \\\n", + "0 Мелодрама легендарного Педро Альмодовара «Пого... \n", + "1 Уморительная современная комедия на популярную... \n", + "2 Профессиональный рестлер Стив Остин («Все или ... \n", + "3 Шарлотта Рэмплинг, Том Кортни, Джеральдин Джей... \n", + "4 Расчетливая чаровница из советского кинохита «... \n", + "\n", + " keywords \n", + "0 Поговори, ней, 2002, Испания, друзья, любовь, ... \n", + "1 Голые, перцы, 2014, США, друзья, свадьбы, прео... \n", + "2 Тактическая, сила, 2011, Канада, бандиты, ганг... \n", + "3 45, лет, 2015, Великобритания, брак, жизнь, лю... \n", + "4 Все, решает, мгновение, 1978, СССР, сильные, ж... " + ] + }, + "execution_count": 213, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "items.head()" + ] + }, + { + "cell_type": "code", + "execution_count": 214, + "id": "72fa86a0", + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "data": { + "text/plain": [ + "item_id 0\n", + "content_type 0\n", + "title 0\n", + "title_orig 4745\n", + "release_year 98\n", + "genres 0\n", + "countries 37\n", + "for_kids 15397\n", + "age_rating 2\n", + "studios 14898\n", + "directors 1509\n", + "actors 2619\n", + "description 2\n", + "keywords 423\n", + "dtype: int64" + ] + }, + "execution_count": 214, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "items.isna().sum()" + ] + }, + { + "cell_type": "code", + "execution_count": 215, + "id": "50f0611f", + "metadata": {}, + "outputs": [], + "source": [ + "items = items.loc[items[Columns.Item].isin(train[Columns.Item])].copy()" + ] + }, + { + "cell_type": "code", + "execution_count": 216, + "id": "280cf47d", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "item_id 0\n", + "content_type 0\n", + "title 0\n", + "title_orig 3775\n", + "release_year 31\n", + "genres 0\n", + "countries 14\n", + "for_kids 13415\n", + "age_rating 1\n", + "studios 13047\n", + "directors 939\n", + "actors 1858\n", + "description 0\n", + "keywords 388\n", + "dtype: int64" + ] + }, + "execution_count": 216, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "items.isna().sum()" + ] + }, + { + "cell_type": "markdown", + "id": "eddd93b5", + "metadata": {}, + "source": [ + "## Genre" + ] + }, + { + "cell_type": "code", + "execution_count": 217, + "id": "bf6da75c", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
idvaluefeature
010711драмыgenre
010711зарубежныеgenre
010711детективыgenre
010711мелодрамыgenre
12508зарубежныеgenre
\n", + "
" + ], + "text/plain": [ + " id value feature\n", + "0 10711 драмы genre\n", + "0 10711 зарубежные genre\n", + "0 10711 детективы genre\n", + "0 10711 мелодрамы genre\n", + "1 2508 зарубежные genre" + ] + }, + "execution_count": 217, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Explode genres to flatten table\n", + "items['genre'] = items['genres'].str.lower().str.replace(', ', ',',\n", + " regex=False).str.split(',')\n", + "genre_feature = items[['item_id', 'genre']].explode('genre')\n", + "genre_feature.columns = ['id', 'value']\n", + "genre_feature['feature'] = 'genre'\n", + "genre_feature.head()\n" + ] + }, + { + "cell_type": "code", + "execution_count": 218, + "id": "913b9c27", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
idvaluefeature
010711драмыgenre
010711зарубежныеgenre
010711детективыgenre
010711мелодрамыgenre
12508зарубежныеgenre
............
1596010632криминалgenre
159614538драмыgenre
159614538спортgenre
159614538криминалgenre
159623206комедииgenre
\n", + "

36128 rows × 3 columns

\n", + "
" + ], + "text/plain": [ + " id value feature\n", + "0 10711 драмы genre\n", + "0 10711 зарубежные genre\n", + "0 10711 детективы genre\n", + "0 10711 мелодрамы genre\n", + "1 2508 зарубежные genre\n", + "... ... ... ...\n", + "15960 10632 криминал genre\n", + "15961 4538 драмы genre\n", + "15961 4538 спорт genre\n", + "15961 4538 криминал genre\n", + "15962 3206 комедии genre\n", + "\n", + "[36128 rows x 3 columns]" + ] + }, + "execution_count": 218, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "genre_feature" + ] + }, + { + "cell_type": "markdown", + "id": "478bf1e3", + "metadata": {}, + "source": [ + "## Content" + ] + }, + { + "cell_type": "code", + "execution_count": 220, + "id": "65f8b5d9", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
idvaluefeature
010711filmcontent_type
12508filmcontent_type
210716filmcontent_type
37868filmcontent_type
416268filmcontent_type
\n", + "
" + ], + "text/plain": [ + " id value feature\n", + "0 10711 film content_type\n", + "1 2508 film content_type\n", + "2 10716 film content_type\n", + "3 7868 film content_type\n", + "4 16268 film content_type" + ] + }, + "execution_count": 220, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "content_feature = items.reindex(columns=[Columns.Item, \"content_type\"])\n", + "content_feature.columns = [\"id\", \"value\"]\n", + "content_feature[\"feature\"] = \"content_type\"\n", + "content_feature.head()" + ] + }, + { + "cell_type": "markdown", + "id": "a62ebee4", + "metadata": {}, + "source": [ + "## Actors" + ] + }, + { + "cell_type": "code", + "execution_count": 221, + "id": "fdc43660", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
idvaluefeature
010711адольфо фернандесactors
010711ана фернандесactors
010711дарио грандинеттиactors
010711джеральдин чаплинactors
010711елена анайяactors
\n", + "
" + ], + "text/plain": [ + " id value feature\n", + "0 10711 адольфо фернандес actors\n", + "0 10711 ана фернандес actors\n", + "0 10711 дарио грандинетти actors\n", + "0 10711 джеральдин чаплин actors\n", + "0 10711 елена анайя actors" + ] + }, + "execution_count": 221, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "items['actors'] = items['actors'].str.lower().str.replace(', ', ',',\n", + " regex=False).str.split(',')\n", + "actors_feature = items[['item_id', 'actors']].explode('actors')\n", + "actors_feature.columns = ['id', 'value']\n", + "actors_feature['feature'] = 'actors'\n", + "actors_feature.head()" + ] + }, + { + "cell_type": "markdown", + "id": "73801647", + "metadata": {}, + "source": [ + "## Keywords" + ] + }, + { + "cell_type": "code", + "execution_count": 222, + "id": "594abe5c", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
idvaluefeature
010711поговориkeywords
010711нейkeywords
0107112002keywords
010711испанияkeywords
010711друзьяkeywords
\n", + "
" + ], + "text/plain": [ + " id value feature\n", + "0 10711 поговори keywords\n", + "0 10711 ней keywords\n", + "0 10711 2002 keywords\n", + "0 10711 испания keywords\n", + "0 10711 друзья keywords" + ] + }, + "execution_count": 222, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "items['keywords'] = items['keywords'].str.lower().str.replace(', ', ','\n", + " , regex=False).str.split(',')\n", + "keywords_feature = items[['item_id', 'keywords']].explode('keywords')\n", + "keywords_feature.columns = ['id', 'value']\n", + "keywords_feature['feature'] = 'keywords'\n", + "keywords_feature.head()" + ] + }, + { + "cell_type": "markdown", + "id": "d3eb0a37", + "metadata": {}, + "source": [ + "## Countries" + ] + }, + { + "cell_type": "code", + "execution_count": 223, + "id": "8eb8a621", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
idvaluefeature
010711Испанияcountries
12508СШАcountries
210716Канадаcountries
37868Великобританияcountries
416268СССРcountries
\n", + "
" + ], + "text/plain": [ + " id value feature\n", + "0 10711 Испания countries\n", + "1 2508 США countries\n", + "2 10716 Канада countries\n", + "3 7868 Великобритания countries\n", + "4 16268 СССР countries" + ] + }, + "execution_count": 223, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "country_feature = items.reindex(columns=[Columns.Item, 'countries'])\n", + "country_feature.columns = ['id', 'value']\n", + "country_feature['feature'] = 'countries'\n", + "country_feature.head()" + ] + }, + { + "cell_type": "markdown", + "id": "5e477ee1", + "metadata": {}, + "source": [ + "## Age Rating" + ] + }, + { + "cell_type": "code", + "execution_count": 224, + "id": "0894154a", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
idvaluefeature
01071116.0age_feature
1250816.0age_feature
21071616.0age_feature
3786816.0age_feature
41626812.0age_feature
\n", + "
" + ], + "text/plain": [ + " id value feature\n", + "0 10711 16.0 age_feature\n", + "1 2508 16.0 age_feature\n", + "2 10716 16.0 age_feature\n", + "3 7868 16.0 age_feature\n", + "4 16268 12.0 age_feature" + ] + }, + "execution_count": 224, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "age_feature = items.reindex(columns=[Columns.Item, \"age_rating\"])\n", + "age_feature.columns = [\"id\", \"value\"]\n", + "age_feature[\"feature\"] = \"age_feature\"\n", + "age_feature.head()" + ] + }, + { + "cell_type": "markdown", + "id": "c09df1ec", + "metadata": {}, + "source": [ + "## Studios" + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "id": "ff937b4f", + "metadata": {}, + "outputs": [], + "source": [ + "items.fillna('Unknown', inplace=True)" + ] + }, + { + "cell_type": "code", + "execution_count": 225, + "id": "cee42708", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
idvaluefeature
010711NaNstudios
12508NaNstudios
210716NaNstudios
37868NaNstudios
416268Ленфильмstudios
\n", + "
" + ], + "text/plain": [ + " id value feature\n", + "0 10711 NaN studios\n", + "1 2508 NaN studios\n", + "2 10716 NaN studios\n", + "3 7868 NaN studios\n", + "4 16268 Ленфильм studios" + ] + }, + "execution_count": 225, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "studios_feature = items.reindex(columns=[Columns.Item, \"studios\"])\n", + "studios_feature.columns = [\"id\", \"value\"]\n", + "studios_feature[\"feature\"] = \"studios\"\n", + "studios_feature.head()" + ] + }, + { + "cell_type": "code", + "execution_count": 226, + "id": "7234f13b", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
idvaluefeature
010711драмыgenre
010711зарубежныеgenre
010711детективыgenre
010711мелодрамыgenre
12508зарубежныеgenre
\n", + "
" + ], + "text/plain": [ + " id value feature\n", + "0 10711 драмы genre\n", + "0 10711 зарубежные genre\n", + "0 10711 детективы genre\n", + "0 10711 мелодрамы genre\n", + "1 2508 зарубежные genre" + ] + }, + "execution_count": 226, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# studios_feature, age_feature, country_feature - фичи которые хотелось бы использовать,\n", + "# но длительность обучения \"OPTUNA\" увеличивается в разы\n", + "item_features = pd.concat((genre_feature, content_feature ))\n", + "item_features.head()" + ] + }, + { + "cell_type": "markdown", + "id": "09b8d756", + "metadata": {}, + "source": [ + "## Metrics" + ] + }, + { + "cell_type": "code", + "execution_count": 227, + "id": "b082e667", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'Precision@1': Precision(k=1),\n", + " 'Precision@2': Precision(k=2),\n", + " 'Precision@3': Precision(k=3),\n", + " 'Precision@4': Precision(k=4),\n", + " 'Precision@5': Precision(k=5),\n", + " 'Precision@6': Precision(k=6),\n", + " 'Precision@7': Precision(k=7),\n", + " 'Precision@8': Precision(k=8),\n", + " 'Precision@9': Precision(k=9),\n", + " 'Precision@10': Precision(k=10),\n", + " 'Recall@1': Recall(k=1),\n", + " 'Recall@2': Recall(k=2),\n", + " 'Recall@3': Recall(k=3),\n", + " 'Recall@4': Recall(k=4),\n", + " 'Recall@5': Recall(k=5),\n", + " 'Recall@6': Recall(k=6),\n", + " 'Recall@7': Recall(k=7),\n", + " 'Recall@8': Recall(k=8),\n", + " 'Recall@9': Recall(k=9),\n", + " 'Recall@10': Recall(k=10),\n", + " 'MAP@1': MAP(k=1, divide_by_k=False),\n", + " 'MAP@2': MAP(k=2, divide_by_k=False),\n", + " 'MAP@3': MAP(k=3, divide_by_k=False),\n", + " 'MAP@4': MAP(k=4, divide_by_k=False),\n", + " 'MAP@5': MAP(k=5, divide_by_k=False),\n", + " 'MAP@6': MAP(k=6, divide_by_k=False),\n", + " 'MAP@7': MAP(k=7, divide_by_k=False),\n", + " 'MAP@8': MAP(k=8, divide_by_k=False),\n", + " 'MAP@9': MAP(k=9, divide_by_k=False),\n", + " 'MAP@10': MAP(k=10, divide_by_k=False)}" + ] + }, + "execution_count": 227, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "metrics_name = {\n", + " 'Precision': Precision,\n", + " 'Recall': Recall,\n", + " 'MAP': MAP,\n", + "}\n", + "\n", + "metrics = {}\n", + "for metric_name, metric in metrics_name.items():\n", + " for k in range(1, 11):\n", + " metrics[f'{metric_name}@{k}'] = metric(k=k)\n", + "metrics" + ] + }, + { + "cell_type": "markdown", + "id": "2c603783", + "metadata": {}, + "source": [ + "# Optuna\n", + "\n", + "Необходимо будет перебрать $N$ моделей $(N \\geq 2)$ матричной факторизации и перебрать у них $K$ гиперпараметров $(K \\geq 2)$ **(6 баллов)**\n", + "Для перебора гиперпараметров можно использовать [`Optuna`](https://github.com/optuna/optuna), [`Hyperopt`](https://github.com/hyperopt/hyperopt)" + ] + }, + { + "cell_type": "code", + "execution_count": 229, + "id": "fb193c2f", + "metadata": {}, + "outputs": [], + "source": [ + "NUM_THREADS = 8\n", + "RANDOM_STATE = 42\n", + "K = 5\n", + "NO_COMPONENTS = 32\n", + "N_EPOCHS = 1" + ] + }, + { + "cell_type": "code", + "execution_count": 230, + "id": "3328645d", + "metadata": {}, + "outputs": [], + "source": [ + "USER_ALPHA = 0\n", + "ITEM_ALPHA = 0\n", + "K_RECOS = 10" + ] + }, + { + "cell_type": "code", + "execution_count": 231, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "dataset = Dataset.construct(interactions_df=train,\n", + " user_features_df=user_features,\n", + " cat_user_features=['sex', 'age', 'income'],\n", + " item_features_df=item_features,\n", + " cat_item_features=['content_type', 'genre'])\n", + "TEST_USERS = test[Columns.User].unique()" + ] + }, + { + "cell_type": "code", + "execution_count": 54, + "id": "a17b8b66", + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\u001b[32m[I 2022-12-12 18:32:01,241]\u001b[0m A new study created in memory with name: no-name-d2c12238-d18d-4c6f-bca4-840e7d3f29b0\u001b[0m\n", + "\u001b[32m[I 2022-12-12 18:41:40,178]\u001b[0m Trial 0 finished with value: 0.07156314077881751 and parameters: {'recomender': 'ALS', 'regularization': 0.0035671951579306937}. Best is trial 0 with value: 0.07156314077881751.\u001b[0m\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "MAP@10 0.07156314077881751\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\u001b[32m[I 2022-12-12 18:51:48,671]\u001b[0m Trial 1 finished with value: 0.07241639094290958 and parameters: {'recomender': 'ALS', 'regularization': 0.006724126527816994}. Best is trial 1 with value: 0.07241639094290958.\u001b[0m\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "MAP@10 0.07241639094290958\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\u001b[32m[I 2022-12-12 18:53:18,697]\u001b[0m Trial 2 finished with value: 1.4050149479540313e-07 and parameters: {'recomender': 'LightFM', 'learning_rate': 0.8190152272980945, 'k': 6, 'loss': 'bpr'}. Best is trial 1 with value: 0.07241639094290958.\u001b[0m\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "MAP@10 1.4050149479540313e-07\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\u001b[32m[I 2022-12-12 18:54:36,340]\u001b[0m Trial 3 finished with value: 0.005366068762176463 and parameters: {'recomender': 'LightFM', 'learning_rate': 0.18723291153626603, 'k': 7, 'loss': 'bpr'}. Best is trial 1 with value: 0.07241639094290958.\u001b[0m\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "MAP@10 0.005366068762176463\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\u001b[32m[I 2022-12-12 18:56:21,781]\u001b[0m Trial 4 finished with value: 0.0002205827579874263 and parameters: {'recomender': 'LightFM', 'learning_rate': 0.6560234930178588, 'k': 6, 'loss': 'logistic'}. Best is trial 1 with value: 0.07241639094290958.\u001b[0m\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "MAP@10 0.0002205827579874263\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\u001b[32m[I 2022-12-12 19:05:46,138]\u001b[0m Trial 5 finished with value: 0.07173988822226253 and parameters: {'recomender': 'ALS', 'regularization': 0.009044651486228098}. Best is trial 1 with value: 0.07241639094290958.\u001b[0m\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "MAP@10 0.07173988822226253\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\u001b[32m[I 2022-12-12 19:07:05,748]\u001b[0m Trial 6 finished with value: 3.943062688880311e-06 and parameters: {'recomender': 'LightFM', 'learning_rate': 0.44751878244334975, 'k': 7, 'loss': 'warp'}. Best is trial 1 with value: 0.07241639094290958.\u001b[0m\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "MAP@10 3.943062688880311e-06\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\u001b[32m[I 2022-12-12 19:08:22,099]\u001b[0m Trial 7 finished with value: 0.06793721324055035 and parameters: {'recomender': 'LightFM', 'learning_rate': 0.10438302844592218, 'k': 3, 'loss': 'warp'}. Best is trial 1 with value: 0.07241639094290958.\u001b[0m\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "MAP@10 0.06793721324055035\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\u001b[32m[I 2022-12-12 19:17:32,898]\u001b[0m Trial 8 finished with value: 0.07184311920591484 and parameters: {'recomender': 'ALS', 'regularization': 0.0005806772800434514}. Best is trial 1 with value: 0.07241639094290958.\u001b[0m\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "MAP@10 0.07184311920591484\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\u001b[32m[I 2022-12-12 19:18:59,268]\u001b[0m Trial 9 finished with value: 2.2409988419866796e-06 and parameters: {'recomender': 'LightFM', 'learning_rate': 0.805131840226543, 'k': 7, 'loss': 'bpr'}. Best is trial 1 with value: 0.07241639094290958.\u001b[0m\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "MAP@10 2.2409988419866796e-06\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\u001b[32m[I 2022-12-12 19:28:09,202]\u001b[0m Trial 10 finished with value: 0.07180954187357708 and parameters: {'recomender': 'ALS', 'regularization': 0.008190821633209066}. Best is trial 1 with value: 0.07241639094290958.\u001b[0m\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "MAP@10 0.07180954187357708\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\u001b[32m[I 2022-12-12 19:37:15,147]\u001b[0m Trial 11 finished with value: 0.07244222251339615 and parameters: {'recomender': 'ALS', 'regularization': 0.00026970098377155163}. Best is trial 11 with value: 0.07244222251339615.\u001b[0m\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "MAP@10 0.07244222251339615\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\u001b[32m[I 2022-12-12 19:46:24,260]\u001b[0m Trial 12 finished with value: 0.07202031081710311 and parameters: {'recomender': 'ALS', 'regularization': 0.0066363513358619185}. Best is trial 11 with value: 0.07244222251339615.\u001b[0m\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "MAP@10 0.07202031081710311\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\u001b[32m[I 2022-12-12 19:55:34,176]\u001b[0m Trial 13 finished with value: 0.07199398893026046 and parameters: {'recomender': 'ALS', 'regularization': 0.004156107607150058}. Best is trial 11 with value: 0.07244222251339615.\u001b[0m\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "MAP@10 0.07199398893026046\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\u001b[32m[I 2022-12-12 20:04:42,589]\u001b[0m Trial 14 finished with value: 0.07167963259586223 and parameters: {'recomender': 'ALS', 'regularization': 0.0006228566403390988}. Best is trial 11 with value: 0.07244222251339615.\u001b[0m\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "MAP@10 0.07167963259586223\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\u001b[32m[I 2022-12-12 20:13:49,348]\u001b[0m Trial 15 finished with value: 0.07202106855494453 and parameters: {'recomender': 'ALS', 'regularization': 0.00598705937836684}. Best is trial 11 with value: 0.07244222251339615.\u001b[0m\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "MAP@10 0.07202106855494453\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\u001b[32m[I 2022-12-12 20:22:57,770]\u001b[0m Trial 16 finished with value: 0.07193963920172777 and parameters: {'recomender': 'ALS', 'regularization': 0.0028834604694796696}. Best is trial 11 with value: 0.07244222251339615.\u001b[0m\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "MAP@10 0.07193963920172777\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\u001b[32m[I 2022-12-12 20:32:04,614]\u001b[0m Trial 17 finished with value: 0.07186249836889418 and parameters: {'recomender': 'ALS', 'regularization': 0.007249626991281137}. Best is trial 11 with value: 0.07244222251339615.\u001b[0m\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "MAP@10 0.07186249836889418\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\u001b[32m[I 2022-12-12 20:41:24,258]\u001b[0m Trial 18 finished with value: 0.07164870366757094 and parameters: {'recomender': 'ALS', 'regularization': 0.005115162467576984}. Best is trial 11 with value: 0.07244222251339615.\u001b[0m\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "MAP@10 0.07164870366757094\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\u001b[32m[I 2022-12-12 20:50:49,059]\u001b[0m Trial 19 finished with value: 0.07179004415938793 and parameters: {'recomender': 'ALS', 'regularization': 0.0018963762834092678}. Best is trial 11 with value: 0.07244222251339615.\u001b[0m\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "MAP@10 0.07179004415938793\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\u001b[32m[I 2022-12-12 21:42:16,853]\u001b[0m Trial 20 finished with value: 0.07167129296212232 and parameters: {'recomender': 'ALS', 'regularization': 0.009804091535656343}. Best is trial 11 with value: 0.07244222251339615.\u001b[0m\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "MAP@10 0.07167129296212232\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\u001b[32m[I 2022-12-12 21:52:20,413]\u001b[0m Trial 21 finished with value: 0.07191839766465505 and parameters: {'recomender': 'ALS', 'regularization': 0.005764203522687446}. Best is trial 11 with value: 0.07244222251339615.\u001b[0m\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "MAP@10 0.07191839766465505\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\u001b[32m[I 2022-12-12 22:02:12,773]\u001b[0m Trial 22 finished with value: 0.07159025974450188 and parameters: {'recomender': 'ALS', 'regularization': 0.006209360331833826}. Best is trial 11 with value: 0.07244222251339615.\u001b[0m\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "MAP@10 0.07159025974450188\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\u001b[32m[I 2022-12-12 22:12:55,936]\u001b[0m Trial 23 finished with value: 0.07167021208897958 and parameters: {'recomender': 'ALS', 'regularization': 0.007825089420401029}. Best is trial 11 with value: 0.07244222251339615.\u001b[0m\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "MAP@10 0.07167021208897958\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\u001b[32m[I 2022-12-12 22:23:04,762]\u001b[0m Trial 24 finished with value: 0.07191850988173716 and parameters: {'recomender': 'ALS', 'regularization': 0.004979324924695012}. Best is trial 11 with value: 0.07244222251339615.\u001b[0m\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "MAP@10 0.07191850988173716\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\u001b[32m[I 2022-12-12 22:34:38,654]\u001b[0m Trial 25 finished with value: 0.07178449755342503 and parameters: {'recomender': 'ALS', 'regularization': 0.002381286135370409}. Best is trial 11 with value: 0.07244222251339615.\u001b[0m\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "MAP@10 0.07178449755342503\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\u001b[32m[I 2022-12-12 22:45:43,850]\u001b[0m Trial 26 finished with value: 0.07177449403191542 and parameters: {'recomender': 'ALS', 'regularization': 0.004677821831829}. Best is trial 11 with value: 0.07244222251339615.\u001b[0m\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "MAP@10 0.07177449403191542\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\u001b[32m[I 2022-12-12 22:56:45,636]\u001b[0m Trial 27 finished with value: 0.07214439856613958 and parameters: {'recomender': 'ALS', 'regularization': 0.0069504676367203744}. Best is trial 11 with value: 0.07244222251339615.\u001b[0m\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "MAP@10 0.07214439856613958\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\u001b[32m[I 2022-12-12 23:08:13,361]\u001b[0m Trial 28 finished with value: 0.07237690498752612 and parameters: {'recomender': 'ALS', 'regularization': 0.0074561399301387955}. Best is trial 11 with value: 0.07244222251339615.\u001b[0m\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "MAP@10 0.07237690498752612\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\u001b[32m[I 2022-12-12 23:18:05,878]\u001b[0m Trial 29 finished with value: 0.07173589378156864 and parameters: {'recomender': 'ALS', 'regularization': 0.00848249465326267}. Best is trial 11 with value: 0.07244222251339615.\u001b[0m\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "MAP@10 0.07173589378156864\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\u001b[33m[W 2022-12-12 23:27:26,180]\u001b[0m Trial 30 failed because of the following error: KeyboardInterrupt()\u001b[0m\n", + "Traceback (most recent call last):\n", + " File \"/home/rezarayev/anaconda3/lib/python3.8/site-packages/optuna/study/_optimize.py\", line 196, in _run_trial\n", + " value_or_values = func(trial)\n", + " File \"/tmp/ipykernel_5286/352742220.py\", line 40, in objective\n", + " recos = model.recommend(\n", + " File \"/home/rezarayev/anaconda3/lib/python3.8/site-packages/rectools/models/base.py\", line 132, in recommend\n", + " reco_user_ids, reco_item_ids, reco_scores = self._recommend_u2i(\n", + " File \"/home/rezarayev/anaconda3/lib/python3.8/site-packages/rectools/models/vector.py\", line 141, in _recommend_u2i\n", + " scores = scores_calculator.calc(target_id)\n", + " File \"/home/rezarayev/anaconda3/lib/python3.8/site-packages/rectools/models/vector.py\", line 98, in calc\n", + " scores = self.objects_factors @ subject_factors\n", + "KeyboardInterrupt\n" + ] + }, + { + "ename": "KeyboardInterrupt", + "evalue": "", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mKeyboardInterrupt\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m/tmp/ipykernel_5286/352742220.py\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 48\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 49\u001b[0m \u001b[0mstudy\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0moptuna\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcreate_study\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdirection\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m'maximize'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 50\u001b[0;31m \u001b[0mstudy\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0moptimize\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mobjective\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mn_trials\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;36m100\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m~/anaconda3/lib/python3.8/site-packages/optuna/study/study.py\u001b[0m in \u001b[0;36moptimize\u001b[0;34m(self, func, n_trials, timeout, n_jobs, catch, callbacks, gc_after_trial, show_progress_bar)\u001b[0m\n\u001b[1;32m 417\u001b[0m \"\"\"\n\u001b[1;32m 418\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 419\u001b[0;31m _optimize(\n\u001b[0m\u001b[1;32m 420\u001b[0m \u001b[0mstudy\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 421\u001b[0m \u001b[0mfunc\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mfunc\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/anaconda3/lib/python3.8/site-packages/optuna/study/_optimize.py\u001b[0m in \u001b[0;36m_optimize\u001b[0;34m(study, func, n_trials, timeout, n_jobs, catch, callbacks, gc_after_trial, show_progress_bar)\u001b[0m\n\u001b[1;32m 64\u001b[0m \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 65\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mn_jobs\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 66\u001b[0;31m _optimize_sequential(\n\u001b[0m\u001b[1;32m 67\u001b[0m \u001b[0mstudy\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 68\u001b[0m \u001b[0mfunc\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/anaconda3/lib/python3.8/site-packages/optuna/study/_optimize.py\u001b[0m in \u001b[0;36m_optimize_sequential\u001b[0;34m(study, func, n_trials, timeout, catch, callbacks, gc_after_trial, reseed_sampler_rng, time_start, progress_bar)\u001b[0m\n\u001b[1;32m 158\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 159\u001b[0m \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 160\u001b[0;31m \u001b[0mfrozen_trial\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0m_run_trial\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mstudy\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mfunc\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcatch\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 161\u001b[0m \u001b[0;32mfinally\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 162\u001b[0m \u001b[0;31m# The following line mitigates memory problems that can be occurred in some\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/anaconda3/lib/python3.8/site-packages/optuna/study/_optimize.py\u001b[0m in \u001b[0;36m_run_trial\u001b[0;34m(study, func, catch)\u001b[0m\n\u001b[1;32m 232\u001b[0m \u001b[0;32mand\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0misinstance\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mfunc_err\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcatch\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 233\u001b[0m ):\n\u001b[0;32m--> 234\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mfunc_err\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 235\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mfrozen_trial\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 236\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/anaconda3/lib/python3.8/site-packages/optuna/study/_optimize.py\u001b[0m in \u001b[0;36m_run_trial\u001b[0;34m(study, func, catch)\u001b[0m\n\u001b[1;32m 194\u001b[0m \u001b[0;32mwith\u001b[0m \u001b[0mget_heartbeat_thread\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mtrial\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_trial_id\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mstudy\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_storage\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 195\u001b[0m \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 196\u001b[0;31m \u001b[0mvalue_or_values\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mfunc\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mtrial\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 197\u001b[0m \u001b[0;32mexcept\u001b[0m \u001b[0mexceptions\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mTrialPruned\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0me\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 198\u001b[0m \u001b[0;31m# TODO(mamu): Handle multi-objective cases.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m/tmp/ipykernel_5286/352742220.py\u001b[0m in \u001b[0;36mobjective\u001b[0;34m(trial)\u001b[0m\n\u001b[1;32m 38\u001b[0m fit_features_together=True)\n\u001b[1;32m 39\u001b[0m \u001b[0mmodel\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mfit\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdataset\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 40\u001b[0;31m recos = model.recommend(\n\u001b[0m\u001b[1;32m 41\u001b[0m \u001b[0musers\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mTEST_USERS\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 42\u001b[0m \u001b[0mdataset\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mdataset\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/anaconda3/lib/python3.8/site-packages/rectools/models/base.py\u001b[0m in \u001b[0;36mrecommend\u001b[0;34m(self, users, dataset, k, filter_viewed, items_to_recommend, add_rank_col)\u001b[0m\n\u001b[1;32m 130\u001b[0m \u001b[0msorted_item_ids_to_recommend\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;32mNone\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 131\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 132\u001b[0;31m reco_user_ids, reco_item_ids, reco_scores = self._recommend_u2i(\n\u001b[0m\u001b[1;32m 133\u001b[0m \u001b[0muser_ids\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 134\u001b[0m \u001b[0mdataset\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/anaconda3/lib/python3.8/site-packages/rectools/models/vector.py\u001b[0m in \u001b[0;36m_recommend_u2i\u001b[0;34m(self, user_ids, dataset, k, filter_viewed, sorted_item_ids_to_recommend)\u001b[0m\n\u001b[1;32m 139\u001b[0m \u001b[0mall_scores\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0mtp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mList\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mndarray\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 140\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mtarget_id\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mtqdm\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0muser_ids\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mdisable\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mverbose\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;36m0\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 141\u001b[0;31m \u001b[0mscores\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mscores_calculator\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcalc\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mtarget_id\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 142\u001b[0m reco_ids, reco_scores = recommend_from_scores(\n\u001b[1;32m 143\u001b[0m \u001b[0mscores\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mscores\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/anaconda3/lib/python3.8/site-packages/rectools/models/vector.py\u001b[0m in \u001b[0;36mcalc\u001b[0;34m(self, subject_id)\u001b[0m\n\u001b[1;32m 96\u001b[0m \u001b[0msubject_factors\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msubjects_factors\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0msubject_id\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 97\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdistance\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0mDistance\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mDOT\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 98\u001b[0;31m \u001b[0mscores\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mobjects_factors\u001b[0m \u001b[0;34m@\u001b[0m \u001b[0msubject_factors\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 99\u001b[0m \u001b[0;32melif\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdistance\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0mDistance\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mEUCLIDEAN\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 100\u001b[0m \u001b[0msubject_dot\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msubjects_dots\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0msubject_id\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mKeyboardInterrupt\u001b[0m: " + ] + } + ], + "source": [ + "def objective(trial):\n", + " model_name = trial.suggest_categorical('recomender', ['LightFM',\n", + " 'ALS'])\n", + " if model_name == 'LightFM':\n", + " learning_rate = trial.suggest_float('learning_rate', 1e-10, 1)\n", + " k = trial.suggest_int('k', 2, 10)\n", + " loss = trial.suggest_categorical('loss', ['logistic', 'bpr',\n", + " 'warp'])\n", + " model = LightFMWrapperModel(LightFM(k=k,\n", + " learning_rate=learning_rate,\n", + " loss=loss, no_components=10),\n", + " epochs=N_EPOCHS,\n", + " num_threads=NUM_THREADS)\n", + " else:\n", + " regularization = trial.suggest_float('regularization', 1e-4,\n", + " 1e-2)\n", + " model = \\\n", + " ImplicitALSWrapperModel(model=AlternatingLeastSquares(factors=10,\n", + " random_state=RANDOM_STATE,\n", + " num_threads=NUM_THREADS,\n", + " regularization=regularization),\n", + " fit_features_together=True)\n", + " model.fit(dataset)\n", + " recos = model.recommend(users=TEST_USERS, dataset=dataset,\n", + " k=K_RECOS, filter_viewed=True)\n", + " metric = calc_metrics(metrics, recos, test, train)['MAP@10']\n", + " print ('MAP@10', metric)\n", + " return metric\n", + "\n", + "\n", + "study = optuna.create_study(direction='maximize')\n", + "study.optimize(objective, n_trials=100)" + ] + }, + { + "cell_type": "markdown", + "id": "3989645b", + "metadata": {}, + "source": [ + "## Пришлось остановить обучение, тк эти 30 эпох обучались 6 часов" + ] + }, + { + "cell_type": "code", + "execution_count": 55, + "id": "99aae61e", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'recomender': 'ALS', 'regularization': 0.00026970098377155163}" + ] + }, + "execution_count": 55, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "study.best_params" + ] + }, + { + "cell_type": "code", + "execution_count": 233, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "REGULARIZATION = 0.00026970098377155163" + ] + }, + { + "cell_type": "code", + "execution_count": 234, + "id": "d1f6069a", + "metadata": {}, + "outputs": [], + "source": [ + "# обучаем best model после optuna\n", + "model = ImplicitALSWrapperModel(\n", + " model=AlternatingLeastSquares(\n", + " factors=32,\n", + " random_state=RANDOM_STATE,\n", + " num_threads=NUM_THREADS,\n", + " regularization=REGULARIZATION\n", + " ),\n", + " fit_features_together=True\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 236, + "id": "d3907c1d", + "metadata": {}, + "outputs": [], + "source": [ + "model.fit(dataset)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b2050a6e", + "metadata": {}, + "outputs": [], + "source": [ + "recos = model.recommend(\n", + " users=TEST_USERS,\n", + " dataset=dataset,\n", + " k=K_RECOS,\n", + " filter_viewed=True\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 59, + "id": "6bbe3ff3", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0.07124010116092815" + ] + }, + "execution_count": 59, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "calc_metrics(metrics, recos, test, train)['MAP@10']" + ] + }, + { + "cell_type": "code", + "execution_count": 61, + "id": "d3eead34", + "metadata": {}, + "outputs": [], + "source": [ + "recos = recos[['user_id', 'item_id']]\n", + "recos.to_csv('ALS_after_optuna.csv.gz', index=False, compression='gzip')" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": false + }, + "source": [ + "# Добавление аватаров\n", + "Добавить 3 \"аватаров\" (искусственных пользователей) и посмотреть рекомендации итоговой модели на них. Объяснить почему добавили именно таких пользователей. **(3 балла)**" + ] + }, + { + "cell_type": "code", + "execution_count": 264, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "some_avatars = pd.DataFrame(\n", + " {\n", + " Columns.User: [11111111, 11111112, 11111113],\n", + " Columns.Item: [\n", + " [10732, 3369, 15885], # Аватар, который любит мультики [губка боб, кунг-фу панда, ]\n", + " [3506, 1107, 11235], # Аватар, который любит боевики [форсаж, обитель зла, плохие парни]\n", + " [931, 389, 8315] # Аватар, который любит драмы [после, хатико, сумерки]\n", + " ],\n", + " 'last_watch_dt': [\n", + " [random.choice(sorted(interactions.last_watch_dt.unique())[-10:]) for _ in range(3)] for i in range(3)\n", + " ],\n", + " \"total_dur\": [\n", + " [34343, 6000, 9000],\n", + " [5000, 45452, 9000],\n", + " [5000, 3200, 3232]\n", + " ],\n", + " \"watched_pct\": [\n", + " [100.0, 95.0, 99.0],\n", + " [67.0, 95.0, 99.0],\n", + " [100.0, 53.0, 99.0]\n", + " ],\n", + " Columns.Weight: [\n", + " [5, 5, 5],\n", + " [3, 5, 5],\n", + " [5, 2, 5]\n", + " ]\n", + " }\n", + ")\n", + "\n", + "some_avatars = some_avatars.explode(\n", + " [Columns.Item, Columns.Datetime, \"total_dur\", \"watched_pct\", Columns.Weight]\n", + ").reset_index(drop=True)" + ] + }, + { + "cell_type": "code", + "execution_count": 265, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
user_iditem_idlast_watch_dttotal_durwatched_pctweight
011111111107322021-08-2234343100.05
11111111133692021-08-19600095.05
211111111158852021-08-17900099.05
31111111235062021-08-20500067.03
41111111211072021-08-144545295.05
511111112112352021-08-19900099.05
6111111139312021-08-145000100.05
7111111133892021-08-19320053.02
81111111383152021-08-22323299.05
\n", + "
" + ], + "text/plain": [ + " user_id item_id last_watch_dt total_dur watched_pct weight\n", + "0 11111111 10732 2021-08-22 34343 100.0 5\n", + "1 11111111 3369 2021-08-19 6000 95.0 5\n", + "2 11111111 15885 2021-08-17 9000 99.0 5\n", + "3 11111112 3506 2021-08-20 5000 67.0 3\n", + "4 11111112 1107 2021-08-14 45452 95.0 5\n", + "5 11111112 11235 2021-08-19 9000 99.0 5\n", + "6 11111113 931 2021-08-14 5000 100.0 5\n", + "7 11111113 389 2021-08-19 3200 53.0 2\n", + "8 11111113 8315 2021-08-22 3232 99.0 5" + ] + }, + "execution_count": 265, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "some_avatars" + ] + }, + { + "cell_type": "code", + "execution_count": 266, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "interactions_with_avatars = pd.concat([interactions, some_avatars])\n", + "\n", + "dataset_with_avatars = Dataset.construct(\n", + " interactions_df=interactions_with_avatars,\n", + ")\n", + "\n", + "# обучаем best model после optuna\n", + "model_with_avatars = ImplicitALSWrapperModel(\n", + " model=AlternatingLeastSquares(\n", + " factors=32,\n", + " random_state=RANDOM_STATE,\n", + " num_threads=NUM_THREADS,\n", + " regularization=REGULARIZATION\n", + " ),\n", + " fit_features_together=True\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 267, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 267, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "model_with_avatars.fit(dataset_with_avatars)" + ] + }, + { + "cell_type": "code", + "execution_count": 268, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
user_iditem_idscorerank
011111111119850.0407001
11111111129540.0394662
21111111173100.0365913
31111111131820.0354234
41111111144750.0344225
51111111277930.0356391
61111111247020.0351392
711111112163610.0348573
81111111212870.0343274
911111112110180.0323495
101111111319160.2456551
1111111113144700.2427862
12111111131010.2192313
1311111113124630.2066154
141111111357320.1830125
\n", + "
" + ], + "text/plain": [ + " user_id item_id score rank\n", + "0 11111111 11985 0.040700 1\n", + "1 11111111 2954 0.039466 2\n", + "2 11111111 7310 0.036591 3\n", + "3 11111111 3182 0.035423 4\n", + "4 11111111 4475 0.034422 5\n", + "5 11111112 7793 0.035639 1\n", + "6 11111112 4702 0.035139 2\n", + "7 11111112 16361 0.034857 3\n", + "8 11111112 1287 0.034327 4\n", + "9 11111112 11018 0.032349 5\n", + "10 11111113 1916 0.245655 1\n", + "11 11111113 14470 0.242786 2\n", + "12 11111113 101 0.219231 3\n", + "13 11111113 12463 0.206615 4\n", + "14 11111113 5732 0.183012 5" + ] + }, + "execution_count": 268, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "recos_with_avatars = model_with_avatars.recommend(\n", + " users=[11111111, 11111112, 11111113],\n", + " dataset=dataset_with_avatars,\n", + " k=5,\n", + " filter_viewed=True\n", + ")\n", + "recos_with_avatars" + ] + }, + { + "cell_type": "code", + "execution_count": 269, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
user_iditem_idscorerankcontent_typetitletitle_origrelease_yeargenrescountriesfor_kidsage_ratingstudiosdirectorsactorsdescriptionkeywordsgenre
011111111119850.0407001filmИстория игрушек 4Toy Story 42019.0мультфильм, фэнтези, комедииСШАNaN6.0NaNДжош Кули[том хэнкс, тим аллен, энни поттс, тони хейл, ...Космический рейнджер Баз Лайтер, ковбой Вуди, ...[игрушка, дружба, ковбой, история игрушек 4, ,...[мультфильм, фэнтези, комедии]
11111111129540.0394662filmМиньоныMinions2015.0фантастика, мультфильм, приключения, комедииСШАNaN6.0NaNКайл Балда, Пьер Коффан[сандра буллок, джон хэмм, майкл китон, эллисо...Миньоны живут на планете гораздо дольше нас. У...[помощник, сцена после титров, сцена во время ...[фантастика, мультфильм, приключения, комедии]
21111111173100.0365913filmГадкий я 2Despicable Me 22013.0мультфильм, приключения, фантастика, фэнтези, ...США, Франция, ЯпонияNaN0.0NaNПьер Коффан, Крис Рено[стив карелл, кристен уиг, бенджамин брэтт, ми...В то время как Грю, бывший суперзлодей, приспо...[отношения родитель-ребенок, секретный агент, ...[мультфильм, приключения, фантастика, фэнтези,...
31111111131820.0354234filmРальф против ИнтернетаRalph Breaks the Internet2018.0мультфильм, приключения, фантастика, семейное,...СШАNaN6.0NaNРич Мур, Фил Джонстон[джон си райли, сара силверман, галь гадот, та...На этот раз Ральф и Ванилопа фон Кекс выйдут з...[видеоигра, мультфильм, продолжение, интернет,...[мультфильм, приключения, фантастика, семейное...
41111111144750.0344225filmТачкиCars2006.0спорт, мультфильм, комедииСШАNaN6.0NaNДжон Лассетер, Джо Рэнфт[оуэн уилсон, пол ньюман, бонни хант, ларри-ка...Неукротимый в своем желании всегда и во всем п...[автомобильная гонка, трасса 66, porsche, выхо...[спорт, мультфильм, комедии]
51111111277930.0356391filmРадиовспышкаRadioflash2019.0боевики, драмы, фантастика, триллерыСШАNaN16.0NaNБен Макферсон[брайтон шарбино, доминик монахэн, уилл пэттон...Риз с легкостью проходит виртуальные квесты, н...[2019, соединенные штаты, радиовспышка][боевики, драмы, фантастика, триллеры]
61111111247020.0351392filmХищникPredator1987.0боевики, фантастика, триллеры, приключенияСША, МексикаNaN16.0NaNДжон МакТирнан[арнольд шварценеггер, карл уэзерс, эльпидия к...Американский вертолет был сбит партизанами в Ю...[центральная и южная америка, хищник, иноплане...[боевики, фантастика, триллеры, приключения]
711111112163610.0348573filmDoom: АннигиляцияDoom: Annihilation2019.0боевики, ужасы, фантастика, триллерыСШАNaN18.0NaNТони Гиглио[эми мэнсон, доминик мафэм, люк аллен-гейл, дж...Отряд морпехов прилетает на марсианский спутни...[планета марс, ад, космос, демон, по мотивам в...[боевики, ужасы, фантастика, триллеры]
81111111212870.0343274filmТерминатор: Тёмные судьбыTerminator: Dark Fate2019.0боевики, фантастика, приключенияСША, КитайNaN16.0NaNТим Миллер[линда хэмилтон, арнольд шварценеггер, маккенз...Мексика. Милая девушка Даниэла Рамос, а для др...[искуственный интеллект, киборг, вертолет, мех...[боевики, фантастика, приключения]
911111112110180.0323495filmХищникиPredators2010.0боевики, фантастика, триллеры, приключенияСШАNaN16.0NaNНимрод Антал[эдриан броуди, тофер грейс, алиси брага, уолт...Наемник Ройс невольно вынужден возглавить груп...[охотник, хищник, якудза, охота на людей, иноп...[боевики, фантастика, триллеры, приключения]
101111111319160.2456551filmСекс и ничего лишнегоMy Awkward Sexual Adventure2012.0мелодрамыКанадаNaN18.0NaNШон Гэррити[джонас черник, эмили хэмпшир, сара мэннинен, ...Чтобы вернуть свою неудовлетворенную бывшую де...[нижнее белье, массажистка, секс втроем, фалло...[мелодрамы]
1111111113144700.2427862filmЛюбовьLove2015.0драмы, мелодрамыФранцияNaN18.0NaNГаспар Ноэ[аоми муйок, карл глусман, клара кристин, уго ...Любовь вне добра и зла. Любовь — это генетичес...[париж, франция, секс, сексуальность, галерея,...[драмы, мелодрамы]
12111111131010.2192313filmКуриосаCuriosa2019.0историческое, мелодрамыФранцияNaN18.0NaNЛу Жене[ноэми мерлан, нильс шнайдер, бенжамен лаверн,...Историческая драма про любовный треугольник, к...[, 1890-е, большой пенис, брак без секса, вдох...[историческое, мелодрамы]
1311111113124630.2066154filmСтудентка по вызовуMes chères études2010.0драмы, мелодрамыФранцияNaN18.0NaNЭмманюэль Берко[дебора франсуа, ален коши, матье деми, бенжам...Лаура — 19-летняя первокурсница французского у...[франция, гостиница, по роману или книге, гост...[драмы, мелодрамы]
141111111357320.1830125filmТайное влечениеAdore2013.0драмы, мелодрамыАвстралия, ФранцияNaN16.0NaNАнн Фонтен[наоми уоттс, робин райт, завьер сэмюэл, джейм...Главные героини картины – Лил и Роз — две давн...[пляж, нагота, любовники, месть, лучший друг, ...[драмы, мелодрамы]
\n", + "
" + ], + "text/plain": [ + " user_id item_id score rank content_type title \\\n", + "0 11111111 11985 0.040700 1 film История игрушек 4 \n", + "1 11111111 2954 0.039466 2 film Миньоны \n", + "2 11111111 7310 0.036591 3 film Гадкий я 2 \n", + "3 11111111 3182 0.035423 4 film Ральф против Интернета \n", + "4 11111111 4475 0.034422 5 film Тачки \n", + "5 11111112 7793 0.035639 1 film Радиовспышка \n", + "6 11111112 4702 0.035139 2 film Хищник \n", + "7 11111112 16361 0.034857 3 film Doom: Аннигиляция \n", + "8 11111112 1287 0.034327 4 film Терминатор: Тёмные судьбы \n", + "9 11111112 11018 0.032349 5 film Хищники \n", + "10 11111113 1916 0.245655 1 film Секс и ничего лишнего \n", + "11 11111113 14470 0.242786 2 film Любовь \n", + "12 11111113 101 0.219231 3 film Куриоса \n", + "13 11111113 12463 0.206615 4 film Студентка по вызову \n", + "14 11111113 5732 0.183012 5 film Тайное влечение \n", + "\n", + " title_orig release_year \\\n", + "0 Toy Story 4 2019.0 \n", + "1 Minions 2015.0 \n", + "2 Despicable Me 2 2013.0 \n", + "3 Ralph Breaks the Internet 2018.0 \n", + "4 Cars 2006.0 \n", + "5 Radioflash 2019.0 \n", + "6 Predator 1987.0 \n", + "7 Doom: Annihilation 2019.0 \n", + "8 Terminator: Dark Fate 2019.0 \n", + "9 Predators 2010.0 \n", + "10 My Awkward Sexual Adventure 2012.0 \n", + "11 Love 2015.0 \n", + "12 Curiosa 2019.0 \n", + "13 Mes chères études 2010.0 \n", + "14 Adore 2013.0 \n", + "\n", + " genres countries \\\n", + "0 мультфильм, фэнтези, комедии США \n", + "1 фантастика, мультфильм, приключения, комедии США \n", + "2 мультфильм, приключения, фантастика, фэнтези, ... США, Франция, Япония \n", + "3 мультфильм, приключения, фантастика, семейное,... США \n", + "4 спорт, мультфильм, комедии США \n", + "5 боевики, драмы, фантастика, триллеры США \n", + "6 боевики, фантастика, триллеры, приключения США, Мексика \n", + "7 боевики, ужасы, фантастика, триллеры США \n", + "8 боевики, фантастика, приключения США, Китай \n", + "9 боевики, фантастика, триллеры, приключения США \n", + "10 мелодрамы Канада \n", + "11 драмы, мелодрамы Франция \n", + "12 историческое, мелодрамы Франция \n", + "13 драмы, мелодрамы Франция \n", + "14 драмы, мелодрамы Австралия, Франция \n", + "\n", + " for_kids age_rating studios directors \\\n", + "0 NaN 6.0 NaN Джош Кули \n", + "1 NaN 6.0 NaN Кайл Балда, Пьер Коффан \n", + "2 NaN 0.0 NaN Пьер Коффан, Крис Рено \n", + "3 NaN 6.0 NaN Рич Мур, Фил Джонстон \n", + "4 NaN 6.0 NaN Джон Лассетер, Джо Рэнфт \n", + "5 NaN 16.0 NaN Бен Макферсон \n", + "6 NaN 16.0 NaN Джон МакТирнан \n", + "7 NaN 18.0 NaN Тони Гиглио \n", + "8 NaN 16.0 NaN Тим Миллер \n", + "9 NaN 16.0 NaN Нимрод Антал \n", + "10 NaN 18.0 NaN Шон Гэррити \n", + "11 NaN 18.0 NaN Гаспар Ноэ \n", + "12 NaN 18.0 NaN Лу Жене \n", + "13 NaN 18.0 NaN Эмманюэль Берко \n", + "14 NaN 16.0 NaN Анн Фонтен \n", + "\n", + " actors \\\n", + "0 [том хэнкс, тим аллен, энни поттс, тони хейл, ... \n", + "1 [сандра буллок, джон хэмм, майкл китон, эллисо... \n", + "2 [стив карелл, кристен уиг, бенджамин брэтт, ми... \n", + "3 [джон си райли, сара силверман, галь гадот, та... \n", + "4 [оуэн уилсон, пол ньюман, бонни хант, ларри-ка... \n", + "5 [брайтон шарбино, доминик монахэн, уилл пэттон... \n", + "6 [арнольд шварценеггер, карл уэзерс, эльпидия к... \n", + "7 [эми мэнсон, доминик мафэм, люк аллен-гейл, дж... \n", + "8 [линда хэмилтон, арнольд шварценеггер, маккенз... \n", + "9 [эдриан броуди, тофер грейс, алиси брага, уолт... \n", + "10 [джонас черник, эмили хэмпшир, сара мэннинен, ... \n", + "11 [аоми муйок, карл глусман, клара кристин, уго ... \n", + "12 [ноэми мерлан, нильс шнайдер, бенжамен лаверн,... \n", + "13 [дебора франсуа, ален коши, матье деми, бенжам... \n", + "14 [наоми уоттс, робин райт, завьер сэмюэл, джейм... \n", + "\n", + " description \\\n", + "0 Космический рейнджер Баз Лайтер, ковбой Вуди, ... \n", + "1 Миньоны живут на планете гораздо дольше нас. У... \n", + "2 В то время как Грю, бывший суперзлодей, приспо... \n", + "3 На этот раз Ральф и Ванилопа фон Кекс выйдут з... \n", + "4 Неукротимый в своем желании всегда и во всем п... \n", + "5 Риз с легкостью проходит виртуальные квесты, н... \n", + "6 Американский вертолет был сбит партизанами в Ю... \n", + "7 Отряд морпехов прилетает на марсианский спутни... \n", + "8 Мексика. Милая девушка Даниэла Рамос, а для др... \n", + "9 Наемник Ройс невольно вынужден возглавить груп... \n", + "10 Чтобы вернуть свою неудовлетворенную бывшую де... \n", + "11 Любовь вне добра и зла. Любовь — это генетичес... \n", + "12 Историческая драма про любовный треугольник, к... \n", + "13 Лаура — 19-летняя первокурсница французского у... \n", + "14 Главные героини картины – Лил и Роз — две давн... \n", + "\n", + " keywords \\\n", + "0 [игрушка, дружба, ковбой, история игрушек 4, ,... \n", + "1 [помощник, сцена после титров, сцена во время ... \n", + "2 [отношения родитель-ребенок, секретный агент, ... \n", + "3 [видеоигра, мультфильм, продолжение, интернет,... \n", + "4 [автомобильная гонка, трасса 66, porsche, выхо... \n", + "5 [2019, соединенные штаты, радиовспышка] \n", + "6 [центральная и южная америка, хищник, иноплане... \n", + "7 [планета марс, ад, космос, демон, по мотивам в... \n", + "8 [искуственный интеллект, киборг, вертолет, мех... \n", + "9 [охотник, хищник, якудза, охота на людей, иноп... \n", + "10 [нижнее белье, массажистка, секс втроем, фалло... \n", + "11 [париж, франция, секс, сексуальность, галерея,... \n", + "12 [, 1890-е, большой пенис, брак без секса, вдох... \n", + "13 [франция, гостиница, по роману или книге, гост... \n", + "14 [пляж, нагота, любовники, месть, лучший друг, ... \n", + "\n", + " genre \n", + "0 [мультфильм, фэнтези, комедии] \n", + "1 [фантастика, мультфильм, приключения, комедии] \n", + "2 [мультфильм, приключения, фантастика, фэнтези,... \n", + "3 [мультфильм, приключения, фантастика, семейное... \n", + "4 [спорт, мультфильм, комедии] \n", + "5 [боевики, драмы, фантастика, триллеры] \n", + "6 [боевики, фантастика, триллеры, приключения] \n", + "7 [боевики, ужасы, фантастика, триллеры] \n", + "8 [боевики, фантастика, приключения] \n", + "9 [боевики, фантастика, триллеры, приключения] \n", + "10 [мелодрамы] \n", + "11 [драмы, мелодрамы] \n", + "12 [историческое, мелодрамы] \n", + "13 [драмы, мелодрамы] \n", + "14 [драмы, мелодрамы] " + ] + }, + "execution_count": 269, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "recos_with_avatars.merge(items, on='item_id', how='left')" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": false + }, + "source": [ + "В целом, все рекомендации к каждому аватару получились неплохие" + ] + }, + { + "cell_type": "markdown", + "id": "ab12c89f", + "metadata": {}, + "source": [ + " # Метод приближенного поиска соседей для выдачи рекомендаций.\n", + "\n", + "Воспользоваться методом приближенного поиска соседей для выдачи рекомендаций. **(3 балла)**\n", + "Можно использовать любые удобные: [`Annoy`](https://github.com/spotify/annoy), [`nmslib`](https://github.com/nmslib/nmslib) и.т.д" + ] + }, + { + "cell_type": "code", + "execution_count": 67, + "id": "5d1161b4", + "metadata": {}, + "outputs": [], + "source": [ + "LEARNING_RATE = 0.08165160206425184\n", + "LOSS = 'warp'" + ] + }, + { + "cell_type": "code", + "execution_count": 68, + "id": "9f20ae6e", + "metadata": {}, + "outputs": [], + "source": [ + "# обучаем LightFM, чтобы достать из нее вектора пользователей и айтемов\n", + "model = LightFMWrapperModel(\n", + " LightFM(\n", + " k=K,\n", + " no_components=NO_COMPONENTS,\n", + " loss= LOSS,\n", + " random_state=RANDOM_STATE,\n", + " learning_rate=LEARNING_RATE,\n", + " user_alpha=USER_ALPHA,\n", + " item_alpha=ITEM_ALPHA\n", + " ),\n", + " epochs=N_EPOCHS,\n", + " num_threads=NUM_THREADS\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 69, + "id": "9982d55c", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 69, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "model.fit(dataset)" + ] + }, + { + "cell_type": "code", + "execution_count": 72, + "id": "348b4fd6", + "metadata": {}, + "outputs": [], + "source": [ + "user_embeddings, item_embeddings = model.get_vectors(dataset)" + ] + }, + { + "cell_type": "code", + "execution_count": 73, + "id": "fd296cf4", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "((756545, 34), (13963, 34))" + ] + }, + "execution_count": 73, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "user_embeddings.shape, item_embeddings.shape" + ] + }, + { + "cell_type": "code", + "execution_count": 74, + "id": "d75b4570", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([-2.48910075e+02, 1.00000000e+00, -3.04745167e-01, 1.30259299e-01,\n", + " -1.25937782e-01, 1.32810516e-01, -3.98682870e-01, 2.12211904e-01,\n", + " 3.15063161e-01, 9.48599975e-03, 1.79876286e-01, -1.15210674e-01,\n", + " 3.13044085e-01, 5.25500635e-02, -8.94866249e-02, 6.32450803e-02,\n", + " 3.30464664e-01, -2.79290127e-01, 7.66675368e-02, 2.69704125e-01,\n", + " -2.02872234e-01, 3.65543869e-02, -2.08750917e-01, -7.48397237e-02,\n", + " 2.09714412e-01, 1.28161004e-01, -2.49842146e-01, 7.57336145e-02,\n", + " 6.74582969e-02, 2.03054725e-01, -4.46441335e-02, 1.00222239e-01,\n", + " 3.09746759e-01, 2.26963989e-01])" + ] + }, + "execution_count": 74, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#пользователь со средним значением по каждому признаку\n", + "first_person = user_embeddings.mean(0)\n", + "first_person" + ] + }, + { + "cell_type": "code", + "execution_count": 75, + "id": "88198015", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([-364.41271973, 1. , -2.19337273, -2.05960441,\n", + " -3.03305483, -2.15237951, -3.10027146, -1.44008625,\n", + " -1.55592728, -1.69499218, -1.87335801, -3.19125104,\n", + " -1.8664068 , -2.62357092, -2.23808742, -1.78050435,\n", + " -1.67308342, -2.70261121, -1.94637215, -2.44766903,\n", + " -2.40233946, -1.93648934, -2.32535124, -2.73280096,\n", + " -2.20278382, -1.93085539, -2.29366779, -1.9847883 ,\n", + " -2.619452 , -1.8447926 , -2.03915739, -1.86472845,\n", + " -1.80441463, -1.98137343])" + ] + }, + "execution_count": 75, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#пользователь со минимальным значением по каждому признаку\n", + "second_person = user_embeddings.min(axis=0)\n", + "second_person" + ] + }, + { + "cell_type": "code", + "execution_count": 76, + "id": "4e02dec3", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([0. , 1. , 1.80414879, 2.91568851, 2.57092023,\n", + " 2.49563074, 3.0165813 , 2.02071786, 2.10402703, 1.86775827,\n", + " 1.81193578, 2.3456769 , 2.37611055, 4.0926795 , 1.8776809 ,\n", + " 1.91333187, 2.16625547, 1.76979506, 1.87265527, 2.63360167,\n", + " 1.97114313, 1.88249838, 1.89424872, 2.15507913, 2.38049865,\n", + " 1.99921763, 1.80478072, 1.8311218 , 3.32906055, 2.25318193,\n", + " 2.0245254 , 2.37490654, 2.28989363, 1.97282732])" + ] + }, + "execution_count": 76, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#пользователь со максимальным значением по каждому признаку\n", + "third_person = user_embeddings.max(axis=0)\n", + "third_person" + ] + }, + { + "cell_type": "code", + "execution_count": 77, + "id": "75a314ac", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(756545, 34)" + ] + }, + "execution_count": 77, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "user_embeddings.shape" + ] + }, + { + "cell_type": "code", + "execution_count": 78, + "id": "3cb72431", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(756548, 34)" + ] + }, + "execution_count": 78, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# добавим векотра 3х новых пользователей\n", + "user_embeddings = np.append(user_embeddings, np.array([first_person,\n", + " second_person, third_person]), axis=0)\n", + "user_embeddings.shape\n" + ] + }, + { + "cell_type": "code", + "execution_count": 79, + "id": "db53d401", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Index-time parameters {'M': 50, 'indexThreadQty': 8, 'efConstruction': 150, 'post': 0, 'chunkIndexSize': 10000}\n" + ] + } + ], + "source": [ + "M = 50\n", + "efC = 150\n", + "\n", + "num_threads = 8\n", + "chunkIndexSize = 10000\n", + "\n", + "index_time_params = {\n", + " 'M': M,\n", + " 'indexThreadQty': num_threads,\n", + " 'efConstruction': efC,\n", + " 'post': 0,\n", + " 'chunkIndexSize': chunkIndexSize,\n", + " }\n", + "print ('Index-time parameters', index_time_params)" + ] + }, + { + "cell_type": "code", + "execution_count": 80, + "id": "e09782e5", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "13963" + ] + }, + "execution_count": 80, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "K = 10\n", + "space_name = 'negdotprod'\n", + "index = nmslib.init(method='hnsw', space=space_name,\n", + " data_type=nmslib.DataType.DENSE_VECTOR)\n", + "index.addDataPointBatch(item_embeddings)" + ] + }, + { + "cell_type": "code", + "execution_count": 81, + "id": "209d778e", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Index-time parameters {'M': 50, 'indexThreadQty': 8, 'efConstruction': 150}\n", + "Indexing time = 1.392440\n" + ] + } + ], + "source": [ + "start = time.time()\n", + "index_time_params = {'M': M, 'indexThreadQty': num_threads,\n", + " 'efConstruction': efC}\n", + "index.createIndex(index_time_params)\n", + "end = time.time()\n", + "print('Index-time parameters', index_time_params)\n", + "print('Indexing time = %f' % (end - start))" + ] + }, + { + "cell_type": "code", + "execution_count": 82, + "id": "998dad8b", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Setting query-time parameters {'efSearch': 100}\n" + ] + } + ], + "source": [ + "efS = 100\n", + "query_time_params = {'efSearch': efS}\n", + "print('Setting query-time parameters', query_time_params)\n", + "index.setQueryTimeParams(query_time_params)" + ] + }, + { + "cell_type": "code", + "execution_count": 83, + "id": "6f5cd03c", + "metadata": {}, + "outputs": [], + "source": [ + "query_matrix = user_embeddings" + ] + }, + { + "cell_type": "code", + "execution_count": 84, + "id": "77039943", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "kNN time total=3.962551 (sec), per query=0.000005 (sec), per query adjusted for thread number=0.000042 (sec)\n" + ] + } + ], + "source": [ + "query_qty = query_matrix.shape[0]\n", + "start = time.time()\n", + "nbrs = index.knnQueryBatch(query_matrix, k=K, num_threads=num_threads)\n", + "end = time.time()\n", + "print(\n", + " 'kNN time total=%f (sec), per query=%f (sec), per query adjusted for thread number=%f (sec)' \\\n", + " % (end - start, float(end - start) / query_qty, num_threads * float(end - start) / query_qty)\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 86, + "id": "cac18e0e", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([[ 32, 19, 43, ..., 31, 36, 69],\n", + " [ 31, 262, 62, ..., 32, 121, 735],\n", + " [ 19, 31, 121, ..., 29, 62, 105],\n", + " ...,\n", + " [ 31, 19, 43, ..., 268, 100, 86],\n", + " [ 19, 31, 32, ..., 268, 49, 173],\n", + " [ 19, 31, 32, ..., 100, 105, 268]])" + ] + }, + "execution_count": 86, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# рекомендации для всех пользователей\n", + "recos_old_persons = np.array(nbrs, dtype=int)[:,0][:len(nbrs) - 3]\n", + "recos_old_persons" + ] + }, + { + "cell_type": "code", + "execution_count": 87, + "id": "918c6976", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([[ 31, 19, 32, 43, 62, 121, 173, 268, 100,\n", + " 86],\n", + " [12018, 10998, 7308, 12006, 10159, 10215, 3543, 8118, 8180,\n", + " 11511],\n", + " [ 8453, 6400, 3557, 3945, 6642, 4779, 3583, 2068, 8668,\n", + " 371]])" + ] + }, + "execution_count": 87, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# рекомендации для добавленных пользователей\n", + "recos_new_persons = np.array(nbrs, dtype=int)[:,0][-3:]\n", + "recos_new_persons" + ] + }, + { + "cell_type": "code", + "execution_count": 88, + "id": "c78fbc6a", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
user_iditem_id
0032
1019
2043
3062
40449
.........
756544575654443
756544675654429
7565447756544100
7565448756544105
7565449756544268
\n", + "

7565450 rows × 2 columns

\n", + "
" + ], + "text/plain": [ + " user_id item_id\n", + "0 0 32\n", + "1 0 19\n", + "2 0 43\n", + "3 0 62\n", + "4 0 449\n", + "... ... ...\n", + "7565445 756544 43\n", + "7565446 756544 29\n", + "7565447 756544 100\n", + "7565448 756544 105\n", + "7565449 756544 268\n", + "\n", + "[7565450 rows x 2 columns]" + ] + }, + "execution_count": 88, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df_r = \\\n", + " pd.DataFrame({'user_id': np.repeat(np.arange(len(recos_old_persons)),\n", + " 10), Columns.Item: recos_old_persons.ravel()})\n", + "df_r\n" + ] + }, + { + "cell_type": "code", + "execution_count": 89, + "id": "902cbca6", + "metadata": {}, + "outputs": [], + "source": [ + "df_r.to_csv('nmslib.csv.gz', index=False, compression='gzip')\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": false + }, + "source": [ + "# Холодные пользователи\n", + "Придумать как можно обработать рекомендации для холодных пользователей. **(3 балла)**\n", + "\n", + "В предыдущей домашке, мы выяснили, что на этом датасете лучше всего себя ведет топ за последний месяц. Поэтому каждую модель мы использовали с подобным методом добивки холодных пользователей\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "39d02966", + "metadata": {}, + "source": [ + "# For baseline\n", + "Пробитие бейзлайна MAP@10 >= 0.074921 (6 баллов).\n", + "Чтобы пробить бейзлайн, было принято решение обучиться на всем датасете" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8f6d0f92", + "metadata": {}, + "outputs": [], + "source": [ + "data = Dataset.construct(\n", + " interactions,\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "model = ImplicitALSWrapperModel(\n", + " model=AlternatingLeastSquares(\n", + " factors=32,\n", + " random_state=RANDOM_STATE,\n", + " num_threads=NUM_THREADS,\n", + " regularization=REGULARIZATION\n", + " ),\n", + " fit_features_together=True\n", + ")\n", + "\n", + "model.fit(data)\n", + "recos = model.recommend(\n", + " users=TEST_USERS,\n", + " dataset=data,\n", + " k=10,\n", + " filter_viewed=True\n", + ")\n", + "\n", + "recos = recos[['user_id', 'item_id']]\n", + "recos.to_csv('ALSnew.csv.gz', index=False, compression='gzip')" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.8" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/notebooks/online_LightFm.ipynb b/notebooks/online_LightFm.ipynb new file mode 100644 index 00000000..444b7730 --- /dev/null +++ b/notebooks/online_LightFm.ipynb @@ -0,0 +1,173 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import pickle\n", + "import time\n", + "from collections import defaultdict\n", + "from functools import reduce\n", + "from pathlib import Path\n", + "from typing import Optional\n", + "\n", + "import numpy as np\n", + "import pandas as pd\n", + "import scipy as sp\n", + "from lightfm import LightFM\n", + "from scipy.sparse import csr_matrix\n", + "from tqdm import tqdm\n", + "\n", + "from service.api.models_zoo import LightFMWrapper" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "os.environ['OPENBLAS_NUM_THREADS'] = \"1\"\n", + "datetime_col = 'last_watch_dt'\n", + "DATA_PATH = Path(\"../data/kion_train/\")" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 2.01 s, sys: 224 ms, total: 2.23 s\n", + "Wall time: 2.24 s\n" + ] + } + ], + "source": [ + "%%time\n", + "users = pd.read_csv(DATA_PATH / 'users.csv')\n", + "items = pd.read_csv(DATA_PATH / 'items.csv')\n", + "interactions = pd.read_csv(DATA_PATH / 'interactions.csv')" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "interactions[datetime_col] = pd.to_datetime(interactions[datetime_col], format='%Y-%m-%d')\n", + "interactions.dropna(inplace=True)" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "interactions['watched'] = pd.cut(\n", + " x=interactions['watched_pct'],\n", + " bins=5,\n", + " labels=[1, 2, 3, 4, 5]\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "# Удаляем те юзеры и айтемы, которых нет в основных табличках\n", + "interactions = interactions.merge(users.user_id.drop_duplicates(), on='user_id')\n", + "interactions = interactions.merge(items.item_id.drop_duplicates(), on='item_id')" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [], + "source": [ + "model = LightFMWrapper(epochs=5)" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Epoch: 100%|██████████| 5/5 [00:27<00:00, 5.43s/it]\n" + ] + } + ], + "source": [ + "model.fit(train=interactions, item_features=items, user_features=users)" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[3734, 2657, 11237, 13594, 12248, 11754, 1020, 10242, 142, 1451]" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "model.predict(user_id=176549)" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [], + "source": [ + "with open('../data/lightfm.pickle', 'wb') as f:\n", + " pickle.dump(model, f)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.7" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/poetry.lock b/poetry.lock index 7dfc0cc9..8c7cc5ea 100644 --- a/poetry.lock +++ b/poetry.lock @@ -66,7 +66,7 @@ yaml = ["PyYAML"] name = "certifi" version = "2022.9.24" description = "Python package for providing Mozilla's CA Bundle." -category = "dev" +category = "main" optional = false python-versions = ">=3.6" @@ -74,7 +74,7 @@ python-versions = ">=3.6" name = "chardet" version = "4.0.0" description = "Universal encoding detector for Python 2 and 3" -category = "dev" +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" @@ -97,6 +97,32 @@ category = "main" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +[[package]] +name = "contourpy" +version = "1.0.6" +description = "Python library for calculating contours of 2D quadrilateral grids" +category = "main" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +numpy = ">=1.16" + +[package.extras] +bokeh = ["bokeh", "selenium"] +docs = ["docutils (<0.18)", "sphinx (<=5.2.0)", "sphinx-rtd-theme"] +test = ["Pillow", "flake8", "isort", "matplotlib", "pytest"] +test-minimal = ["pytest"] +test-no-codebase = ["Pillow", "matplotlib", "pytest"] + +[[package]] +name = "cycler" +version = "0.11.0" +description = "Composable style cycles" +category = "main" +optional = false +python-versions = ">=3.6" + [[package]] name = "fastapi" version = "0.65.3" @@ -128,6 +154,28 @@ mccabe = ">=0.6.0,<0.7.0" pycodestyle = ">=2.7.0,<2.8.0" pyflakes = ">=2.3.0,<2.4.0" +[[package]] +name = "fonttools" +version = "4.38.0" +description = "Tools to manipulate font files" +category = "main" +optional = false +python-versions = ">=3.7" + +[package.extras] +all = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "fs (>=2.2.0,<3)", "lxml (>=4.0,<5)", "lz4 (>=1.7.4.2)", "matplotlib", "munkres", "scipy", "skia-pathops (>=0.5.0)", "sympy", "uharfbuzz (>=0.23.0)", "unicodedata2 (>=14.0.0)", "xattr", "zopfli (>=0.1.4)"] +graphite = ["lz4 (>=1.7.4.2)"] +interpolatable = ["munkres", "scipy"] +lxml = ["lxml (>=4.0,<5)"] +pathops = ["skia-pathops (>=0.5.0)"] +plot = ["matplotlib"] +repacker = ["uharfbuzz (>=0.23.0)"] +symfont = ["sympy"] +type1 = ["xattr"] +ufo = ["fs (>=2.2.0,<3)"] +unicode = ["unicodedata2 (>=14.0.0)"] +woff = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "zopfli (>=0.1.4)"] + [[package]] name = "gitdb" version = "4.0.9" @@ -175,11 +223,22 @@ category = "main" optional = false python-versions = ">=3.7" +[[package]] +name = "hnswlib" +version = "0.6.2" +description = "hnswlib" +category = "main" +optional = false +python-versions = "*" + +[package.dependencies] +numpy = "*" + [[package]] name = "idna" version = "2.10" description = "Internationalized Domain Names in Applications (IDNA)" -category = "dev" +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" @@ -205,6 +264,22 @@ pipfile-deprecated-finder = ["pipreqs", "requirementslib"] plugins = ["setuptools"] requirements-deprecated-finder = ["pip-api", "pipreqs"] +[[package]] +name = "joblib" +version = "1.2.0" +description = "Lightweight pipelining with Python functions" +category = "main" +optional = false +python-versions = ">=3.7" + +[[package]] +name = "kiwisolver" +version = "1.4.4" +description = "A fast implementation of the Cassowary constraint solver" +category = "main" +optional = false +python-versions = ">=3.7" + [[package]] name = "lazy-object-proxy" version = "1.8.0" @@ -213,6 +288,40 @@ category = "dev" optional = false python-versions = ">=3.7" +[[package]] +name = "lightfm" +version = "1.16" +description = "LightFM recommendation model" +category = "main" +optional = false +python-versions = "*" + +[package.dependencies] +numpy = "*" +requests = "*" +scikit-learn = "*" +scipy = ">=0.17.0" + +[[package]] +name = "matplotlib" +version = "3.6.2" +description = "Python plotting package" +category = "main" +optional = false +python-versions = ">=3.8" + +[package.dependencies] +contourpy = ">=1.0.1" +cycler = ">=0.10" +fonttools = ">=4.22.0" +kiwisolver = ">=1.0.1" +numpy = ">=1.19" +packaging = ">=20.0" +pillow = ">=6.2.0" +pyparsing = ">=2.2.1" +python-dateutil = ">=2.7" +setuptools_scm = ">=7" + [[package]] name = "mccabe" version = "0.6.1" @@ -245,6 +354,27 @@ category = "dev" optional = false python-versions = "*" +[[package]] +name = "nmslib" +version = "2.1.1" +description = "Non-Metric Space Library (NMSLIB)" +category = "main" +optional = false +python-versions = "*" + +[package.dependencies] +numpy = {version = ">=1.10.0", markers = "python_version >= \"3.5\""} +psutil = "*" +pybind11 = "<2.6.2" + +[[package]] +name = "numpy" +version = "1.23.5" +description = "NumPy is the fundamental package for array computing with Python." +category = "main" +optional = false +python-versions = ">=3.8" + [[package]] name = "orjson" version = "3.8.1" @@ -257,13 +387,33 @@ python-versions = ">=3.7" name = "packaging" version = "21.3" description = "Core utilities for Python packages" -category = "dev" +category = "main" optional = false python-versions = ">=3.6" [package.dependencies] pyparsing = ">=2.0.2,<3.0.5 || >3.0.5" +[[package]] +name = "pandas" +version = "1.5.2" +description = "Powerful data structures for data analysis, time series, and statistics" +category = "main" +optional = false +python-versions = ">=3.8" + +[package.dependencies] +numpy = [ + {version = ">=1.20.3", markers = "python_version < \"3.10\""}, + {version = ">=1.21.0", markers = "python_version >= \"3.10\""}, + {version = ">=1.23.2", markers = "python_version >= \"3.11\""}, +] +python-dateutil = ">=2.8.1" +pytz = ">=2020.1" + +[package.extras] +test = ["hypothesis (>=5.5.3)", "pytest (>=6.0)", "pytest-xdist (>=1.31)"] + [[package]] name = "pbr" version = "5.11.0" @@ -272,6 +422,18 @@ category = "dev" optional = false python-versions = ">=2.6" +[[package]] +name = "pillow" +version = "9.3.0" +description = "Python Imaging Library (Fork)" +category = "main" +optional = false +python-versions = ">=3.7" + +[package.extras] +docs = ["furo", "olefile", "sphinx (>=2.4)", "sphinx-copybutton", "sphinx-issues (>=3.0.1)", "sphinx-removed-in", "sphinxext-opengraph"] +tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout"] + [[package]] name = "pluggy" version = "1.0.0" @@ -284,6 +446,17 @@ python-versions = ">=3.6" dev = ["pre-commit", "tox"] testing = ["pytest", "pytest-benchmark"] +[[package]] +name = "psutil" +version = "5.9.4" +description = "Cross-platform lib for process and system monitoring in Python." +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" + +[package.extras] +test = ["enum34", "ipaddress", "mock", "pywin32", "wmi"] + [[package]] name = "py" version = "1.11.0" @@ -292,6 +465,17 @@ category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +[[package]] +name = "pybind11" +version = "2.6.1" +description = "Seamless operability between C++11 and Python" +category = "main" +optional = false +python-versions = "!=3.0,!=3.1,!=3.2,!=3.3,!=3.4,>=2.7" + +[package.extras] +global = ["pybind11-global (==2.6.1)"] + [[package]] name = "pycodestyle" version = "2.7.0" @@ -342,7 +526,7 @@ toml = ">=0.7.1" name = "pyparsing" version = "3.0.9" description = "pyparsing module - Classes and methods to define and execute parsing grammars" -category = "dev" +category = "main" optional = false python-versions = ">=3.6.8" @@ -370,6 +554,25 @@ toml = "*" [package.extras] testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xmlschema"] +[[package]] +name = "python-dateutil" +version = "2.8.2" +description = "Extensions to the standard Python datetime module" +category = "main" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" + +[package.dependencies] +six = ">=1.5" + +[[package]] +name = "pytz" +version = "2022.6" +description = "World timezone definitions, modern and historical" +category = "main" +optional = false +python-versions = "*" + [[package]] name = "pyyaml" version = "6.0" @@ -382,7 +585,7 @@ python-versions = ">=3.6" name = "requests" version = "2.25.1" description = "Python HTTP for Humans." -category = "dev" +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" @@ -396,6 +599,60 @@ urllib3 = ">=1.21.1,<1.27" security = ["cryptography (>=1.3.4)", "pyOpenSSL (>=0.14)"] socks = ["PySocks (>=1.5.6,!=1.5.7)", "win-inet-pton"] +[[package]] +name = "scikit-learn" +version = "1.2.0" +description = "A set of python modules for machine learning and data mining" +category = "main" +optional = false +python-versions = ">=3.8" + +[package.dependencies] +joblib = ">=1.1.1" +numpy = ">=1.17.3" +scipy = ">=1.3.2" +threadpoolctl = ">=2.0.0" + +[package.extras] +benchmark = ["matplotlib (>=3.1.3)", "memory-profiler (>=0.57.0)", "pandas (>=1.0.5)"] +docs = ["Pillow (>=7.1.2)", "matplotlib (>=3.1.3)", "memory-profiler (>=0.57.0)", "numpydoc (>=1.2.0)", "pandas (>=1.0.5)", "plotly (>=5.10.0)", "pooch (>=1.6.0)", "scikit-image (>=0.16.2)", "seaborn (>=0.9.0)", "sphinx (>=4.0.1)", "sphinx-gallery (>=0.7.0)", "sphinx-prompt (>=1.3.0)", "sphinxext-opengraph (>=0.4.2)"] +examples = ["matplotlib (>=3.1.3)", "pandas (>=1.0.5)", "plotly (>=5.10.0)", "pooch (>=1.6.0)", "scikit-image (>=0.16.2)", "seaborn (>=0.9.0)"] +tests = ["black (>=22.3.0)", "flake8 (>=3.8.2)", "matplotlib (>=3.1.3)", "mypy (>=0.961)", "numpydoc (>=1.2.0)", "pandas (>=1.0.5)", "pooch (>=1.6.0)", "pyamg (>=4.0.0)", "pytest (>=5.3.1)", "pytest-cov (>=2.9.0)", "scikit-image (>=0.16.2)"] + +[[package]] +name = "scipy" +version = "1.9.3" +description = "Fundamental algorithms for scientific computing in Python" +category = "main" +optional = false +python-versions = ">=3.8" + +[package.dependencies] +numpy = ">=1.18.5,<1.26.0" + +[package.extras] +dev = ["flake8", "mypy", "pycodestyle", "typing_extensions"] +doc = ["matplotlib (>2)", "numpydoc", "pydata-sphinx-theme (==0.9.0)", "sphinx (!=4.1.0)", "sphinx-panels (>=0.5.2)", "sphinx-tabs"] +test = ["asv", "gmpy2", "mpmath", "pytest", "pytest-cov", "pytest-xdist", "scikit-umfpack", "threadpoolctl"] + +[[package]] +name = "seaborn" +version = "0.12.1" +description = "Statistical data visualization" +category = "main" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +matplotlib = ">=3.1,<3.6.1 || >3.6.1" +numpy = ">=1.17" +pandas = ">=0.25" + +[package.extras] +dev = ["flake8", "mypy", "pandas-stubs", "pre-commit", "pytest", "pytest-cov", "pytest-xdist"] +docs = ["ipykernel", "nbconvert", "numpydoc", "pydata_sphinx_theme (==0.10.0rc2)", "pyyaml", "sphinx-copybutton", "sphinx-design", "sphinx-issues"] +stats = ["scipy (>=1.3)", "statsmodels (>=0.10)"] + [[package]] name = "setuptools" version = "65.5.1" @@ -409,6 +666,32 @@ docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "pygments-g testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8 (<5)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pip-run (>=8.8)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] +[[package]] +name = "setuptools-scm" +version = "7.0.5" +description = "the blessed package to manage your versions by scm tags" +category = "main" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +packaging = ">=20.0" +setuptools = "*" +tomli = ">=1.0.0" +typing-extensions = "*" + +[package.extras] +test = ["pytest (>=6.2)", "virtualenv (>20)"] +toml = ["setuptools (>=42)"] + +[[package]] +name = "six" +version = "1.16.0" +description = "Python 2 and 3 compatibility utilities" +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" + [[package]] name = "smmap" version = "5.0.0" @@ -439,6 +722,14 @@ python-versions = ">=3.8" [package.dependencies] pbr = ">=2.0.0,<2.1.0 || >2.1.0" +[[package]] +name = "threadpoolctl" +version = "3.1.0" +description = "threadpoolctl" +category = "main" +optional = false +python-versions = ">=3.6" + [[package]] name = "toml" version = "0.10.2" @@ -447,6 +738,14 @@ category = "dev" optional = false python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" +[[package]] +name = "tomli" +version = "2.0.1" +description = "A lil' TOML parser" +category = "main" +optional = false +python-versions = ">=3.7" + [[package]] name = "typed-ast" version = "1.4.3" @@ -467,7 +766,7 @@ python-versions = ">=3.7" name = "urllib3" version = "1.26.12" description = "HTTP library with thread-safe connection pooling, file post, and more." -category = "dev" +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, <4" @@ -516,7 +815,7 @@ python-versions = "*" [metadata] lock-version = "1.1" python-versions = "^3.8" -content-hash = "c01b97e2fda031efbc5277fdfb65da75cef9b2da388aa7ecbfbe6d5a68e8dfdb" +content-hash = "3957c89d954678489df8387dc97b248f3fd78e26a9d5e0455fc5779a33456910" [metadata.files] asgiref = [ @@ -554,6 +853,81 @@ colorama = [ {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, ] +contourpy = [ + {file = "contourpy-1.0.6-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:613c665529899b5d9fade7e5d1760111a0b011231277a0d36c49f0d3d6914bd6"}, + {file = "contourpy-1.0.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:78ced51807ccb2f45d4ea73aca339756d75d021069604c2fccd05390dc3c28eb"}, + {file = "contourpy-1.0.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b3b1bd7577c530eaf9d2bc52d1a93fef50ac516a8b1062c3d1b9bcec9ebe329b"}, + {file = "contourpy-1.0.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8834c14b8c3dd849005e06703469db9bf96ba2d66a3f88ecc539c9a8982e0ee"}, + {file = "contourpy-1.0.6-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f4052a8a4926d4468416fc7d4b2a7b2a3e35f25b39f4061a7e2a3a2748c4fc48"}, + {file = "contourpy-1.0.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1c0e1308307a75e07d1f1b5f0f56b5af84538a5e9027109a7bcf6cb47c434e72"}, + {file = "contourpy-1.0.6-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:9fc4e7973ed0e1fe689435842a6e6b330eb7ccc696080dda9a97b1a1b78e41db"}, + {file = "contourpy-1.0.6-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:08e8d09d96219ace6cb596506fb9b64ea5f270b2fb9121158b976d88871fcfd1"}, + {file = "contourpy-1.0.6-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:f33da6b5d19ad1bb5e7ad38bb8ba5c426d2178928bc2b2c44e8823ea0ecb6ff3"}, + {file = "contourpy-1.0.6-cp310-cp310-win32.whl", hash = "sha256:12a7dc8439544ed05c6553bf026d5e8fa7fad48d63958a95d61698df0e00092b"}, + {file = "contourpy-1.0.6-cp310-cp310-win_amd64.whl", hash = "sha256:eadad75bf91897f922e0fb3dca1b322a58b1726a953f98c2e5f0606bd8408621"}, + {file = "contourpy-1.0.6-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:913bac9d064cff033cf3719e855d4f1db9f1c179e0ecf3ba9fdef21c21c6a16a"}, + {file = "contourpy-1.0.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:46deb310a276cc5c1fd27958e358cce68b1e8a515fa5a574c670a504c3a3fe30"}, + {file = "contourpy-1.0.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b64f747e92af7da3b85631a55d68c45a2d728b4036b03cdaba4bd94bcc85bd6f"}, + {file = "contourpy-1.0.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50627bf76abb6ba291ad08db583161939c2c5fab38c38181b7833423ab9c7de3"}, + {file = "contourpy-1.0.6-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:358f6364e4873f4d73360b35da30066f40387dd3c427a3e5432c6b28dd24a8fa"}, + {file = "contourpy-1.0.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c78bfbc1a7bff053baf7e508449d2765964d67735c909b583204e3240a2aca45"}, + {file = "contourpy-1.0.6-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e43255a83835a129ef98f75d13d643844d8c646b258bebd11e4a0975203e018f"}, + {file = "contourpy-1.0.6-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:375d81366afd547b8558c4720337218345148bc2fcffa3a9870cab82b29667f2"}, + {file = "contourpy-1.0.6-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:b98c820608e2dca6442e786817f646d11057c09a23b68d2b3737e6dcb6e4a49b"}, + {file = "contourpy-1.0.6-cp311-cp311-win32.whl", hash = "sha256:0e4854cc02006ad6684ce092bdadab6f0912d131f91c2450ce6dbdea78ee3c0b"}, + {file = "contourpy-1.0.6-cp311-cp311-win_amd64.whl", hash = "sha256:d2eff2af97ea0b61381828b1ad6cd249bbd41d280e53aea5cccd7b2b31b8225c"}, + {file = "contourpy-1.0.6-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:5b117d29433fc8393b18a696d794961464e37afb34a6eeb8b2c37b5f4128a83e"}, + {file = "contourpy-1.0.6-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:341330ed19074f956cb20877ad8d2ae50e458884bfa6a6df3ae28487cc76c768"}, + {file = "contourpy-1.0.6-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:371f6570a81dfdddbb837ba432293a63b4babb942a9eb7aaa699997adfb53278"}, + {file = "contourpy-1.0.6-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9447c45df407d3ecb717d837af3b70cfef432138530712263730783b3d016512"}, + {file = "contourpy-1.0.6-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:730c27978a0003b47b359935478b7d63fd8386dbb2dcd36c1e8de88cbfc1e9de"}, + {file = "contourpy-1.0.6-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:da1ef35fd79be2926ba80fbb36327463e3656c02526e9b5b4c2b366588b74d9a"}, + {file = "contourpy-1.0.6-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:cd2bc0c8f2e8de7dd89a7f1c10b8844e291bca17d359373203ef2e6100819edd"}, + {file = "contourpy-1.0.6-cp37-cp37m-win32.whl", hash = "sha256:3a1917d3941dd58732c449c810fa7ce46cc305ce9325a11261d740118b85e6f3"}, + {file = "contourpy-1.0.6-cp37-cp37m-win_amd64.whl", hash = "sha256:06ca79e1efbbe2df795822df2fa173d1a2b38b6e0f047a0ec7903fbca1d1847e"}, + {file = "contourpy-1.0.6-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:e626cefff8491bce356221c22af5a3ea528b0b41fbabc719c00ae233819ea0bf"}, + {file = "contourpy-1.0.6-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:dbe6fe7a1166b1ddd7b6d887ea6fa8389d3f28b5ed3f73a8f40ece1fc5a3d340"}, + {file = "contourpy-1.0.6-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:e13b31d1b4b68db60b3b29f8e337908f328c7f05b9add4b1b5c74e0691180109"}, + {file = "contourpy-1.0.6-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a79d239fc22c3b8d9d3de492aa0c245533f4f4c7608e5749af866949c0f1b1b9"}, + {file = "contourpy-1.0.6-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9e8e686a6db92a46111a1ee0ee6f7fbfae4048f0019de207149f43ac1812cf95"}, + {file = "contourpy-1.0.6-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:acd2bd02f1a7adff3a1f33e431eb96ab6d7987b039d2946a9b39fe6fb16a1036"}, + {file = "contourpy-1.0.6-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:03d1b9c6b44a9e30d554654c72be89af94fab7510b4b9f62356c64c81cec8b7d"}, + {file = "contourpy-1.0.6-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:b48d94386f1994db7c70c76b5808c12e23ed7a4ee13693c2fc5ab109d60243c0"}, + {file = "contourpy-1.0.6-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:208bc904889c910d95aafcf7be9e677726df9ef71e216780170dbb7e37d118fa"}, + {file = "contourpy-1.0.6-cp38-cp38-win32.whl", hash = "sha256:444fb776f58f4906d8d354eb6f6ce59d0a60f7b6a720da6c1ccb839db7c80eb9"}, + {file = "contourpy-1.0.6-cp38-cp38-win_amd64.whl", hash = "sha256:9bc407a6af672da20da74823443707e38ece8b93a04009dca25856c2d9adadb1"}, + {file = "contourpy-1.0.6-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:aa4674cf3fa2bd9c322982644967f01eed0c91bb890f624e0e0daf7a5c3383e9"}, + {file = "contourpy-1.0.6-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6f56515e7c6fae4529b731f6c117752247bef9cdad2b12fc5ddf8ca6a50965a5"}, + {file = "contourpy-1.0.6-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:344cb3badf6fc7316ad51835f56ac387bdf86c8e1b670904f18f437d70da4183"}, + {file = "contourpy-1.0.6-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0b1e66346acfb17694d46175a0cea7d9036f12ed0c31dfe86f0f405eedde2bdd"}, + {file = "contourpy-1.0.6-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8468b40528fa1e15181cccec4198623b55dcd58306f8815a793803f51f6c474a"}, + {file = "contourpy-1.0.6-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1dedf4c64185a216c35eb488e6f433297c660321275734401760dafaeb0ad5c2"}, + {file = "contourpy-1.0.6-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:494efed2c761f0f37262815f9e3c4bb9917c5c69806abdee1d1cb6611a7174a0"}, + {file = "contourpy-1.0.6-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:75a2e638042118118ab39d337da4c7908c1af74a8464cad59f19fbc5bbafec9b"}, + {file = "contourpy-1.0.6-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a628bba09ba72e472bf7b31018b6281fd4cc903f0888049a3724afba13b6e0b8"}, + {file = "contourpy-1.0.6-cp39-cp39-win32.whl", hash = "sha256:e1739496c2f0108013629aa095cc32a8c6363444361960c07493818d0dea2da4"}, + {file = "contourpy-1.0.6-cp39-cp39-win_amd64.whl", hash = "sha256:a457ee72d9032e86730f62c5eeddf402e732fdf5ca8b13b41772aa8ae13a4563"}, + {file = "contourpy-1.0.6-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:d912f0154a20a80ea449daada904a7eb6941c83281a9fab95de50529bfc3a1da"}, + {file = "contourpy-1.0.6-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4081918147fc4c29fad328d5066cfc751da100a1098398742f9f364be63803fc"}, + {file = "contourpy-1.0.6-pp37-pypy37_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0537cc1195245bbe24f2913d1f9211b8f04eb203de9044630abd3664c6cc339c"}, + {file = "contourpy-1.0.6-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dcd556c8fc37a342dd636d7eef150b1399f823a4462f8c968e11e1ebeabee769"}, + {file = "contourpy-1.0.6-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:f6ca38dd8d988eca8f07305125dec6f54ac1c518f1aaddcc14d08c01aebb6efc"}, + {file = "contourpy-1.0.6-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:c1baa49ab9fedbf19d40d93163b7d3e735d9cd8d5efe4cce9907902a6dad391f"}, + {file = "contourpy-1.0.6-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:211dfe2bd43bf5791d23afbe23a7952e8ac8b67591d24be3638cabb648b3a6eb"}, + {file = "contourpy-1.0.6-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c38c6536c2d71ca2f7e418acaf5bca30a3af7f2a2fa106083c7d738337848dbe"}, + {file = "contourpy-1.0.6-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1b1ee48a130da4dd0eb8055bbab34abf3f6262957832fd575e0cab4979a15a41"}, + {file = "contourpy-1.0.6-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:5641927cc5ae66155d0c80195dc35726eae060e7defc18b7ab27600f39dd1fe7"}, + {file = "contourpy-1.0.6-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:7ee394502026d68652c2824348a40bf50f31351a668977b51437131a90d777ea"}, + {file = "contourpy-1.0.6-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0b97454ed5b1368b66ed414c754cba15b9750ce69938fc6153679787402e4cdf"}, + {file = "contourpy-1.0.6-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0236875c5a0784215b49d00ebbe80c5b6b5d5244b3655a36dda88105334dea17"}, + {file = "contourpy-1.0.6-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:84c593aeff7a0171f639da92cb86d24954bbb61f8a1b530f74eb750a14685832"}, + {file = "contourpy-1.0.6-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:9b0e7fe7f949fb719b206548e5cde2518ffb29936afa4303d8a1c4db43dcb675"}, + {file = "contourpy-1.0.6.tar.gz", hash = "sha256:6e459ebb8bb5ee4c22c19cc000174f8059981971a33ce11e17dddf6aca97a142"}, +] +cycler = [ + {file = "cycler-0.11.0-py3-none-any.whl", hash = "sha256:3a27e95f763a428a739d2add979fa7494c912a32c17c4c38c4d5f082cad165a3"}, + {file = "cycler-0.11.0.tar.gz", hash = "sha256:9c87405839a19696e837b3b818fed3f5f69f16f1eec1a1ad77e043dcea9c772f"}, +] fastapi = [ {file = "fastapi-0.65.3-py3-none-any.whl", hash = "sha256:d3e3c0ac35110efb22ee3ed28201cf32f9d11a9a0e52d7dd676cad25f5219523"}, {file = "fastapi-0.65.3.tar.gz", hash = "sha256:6ea2286e439c4ced7cce2b2862c25859601bf327a515c12dd6e431ef5d49d12f"}, @@ -562,6 +936,10 @@ flake8 = [ {file = "flake8-3.9.2-py2.py3-none-any.whl", hash = "sha256:bf8fd333346d844f616e8d47905ef3a3384edae6b4e9beb0c5101e25e3110907"}, {file = "flake8-3.9.2.tar.gz", hash = "sha256:07528381786f2a6237b061f6e96610a4167b226cb926e2aa2b6b1d78057c576b"}, ] +fonttools = [ + {file = "fonttools-4.38.0-py3-none-any.whl", hash = "sha256:820466f43c8be8c3009aef8b87e785014133508f0de64ec469e4efb643ae54fb"}, + {file = "fonttools-4.38.0.zip", hash = "sha256:2bb244009f9bf3fa100fc3ead6aeb99febe5985fa20afbfbaa2f8946c2fbdaf1"}, +] gitdb = [ {file = "gitdb-4.0.9-py3-none-any.whl", hash = "sha256:8033ad4e853066ba6ca92050b9df2f89301b8fc8bf7e9324d412a63f8bf1a8fd"}, {file = "gitdb-4.0.9.tar.gz", hash = "sha256:bac2fd45c0a1c9cf619e63a90d62bdc63892ef92387424b855792a6cabe789aa"}, @@ -578,6 +956,9 @@ h11 = [ {file = "h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761"}, {file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"}, ] +hnswlib = [ + {file = "hnswlib-0.6.2.tar.gz", hash = "sha256:b696d13f3678aa6795d054a0e8c33b3a2c8e14908432aaf4ced7ebef8290a10c"}, +] idna = [ {file = "idna-2.10-py2.py3-none-any.whl", hash = "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0"}, {file = "idna-2.10.tar.gz", hash = "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6"}, @@ -590,6 +971,80 @@ isort = [ {file = "isort-5.10.1-py3-none-any.whl", hash = "sha256:6f62d78e2f89b4500b080fe3a81690850cd254227f27f75c3a0c491a1f351ba7"}, {file = "isort-5.10.1.tar.gz", hash = "sha256:e8443a5e7a020e9d7f97f1d7d9cd17c88bcb3bc7e218bf9cf5095fe550be2951"}, ] +joblib = [ + {file = "joblib-1.2.0-py3-none-any.whl", hash = "sha256:091138ed78f800342968c523bdde947e7a305b8594b910a0fea2ab83c3c6d385"}, + {file = "joblib-1.2.0.tar.gz", hash = "sha256:e1cee4a79e4af22881164f218d4311f60074197fb707e082e803b61f6d137018"}, +] +kiwisolver = [ + {file = "kiwisolver-1.4.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:2f5e60fabb7343a836360c4f0919b8cd0d6dbf08ad2ca6b9cf90bf0c76a3c4f6"}, + {file = "kiwisolver-1.4.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:10ee06759482c78bdb864f4109886dff7b8a56529bc1609d4f1112b93fe6423c"}, + {file = "kiwisolver-1.4.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c79ebe8f3676a4c6630fd3f777f3cfecf9289666c84e775a67d1d358578dc2e3"}, + {file = "kiwisolver-1.4.4-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:abbe9fa13da955feb8202e215c4018f4bb57469b1b78c7a4c5c7b93001699938"}, + {file = "kiwisolver-1.4.4-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:7577c1987baa3adc4b3c62c33bd1118c3ef5c8ddef36f0f2c950ae0b199e100d"}, + {file = "kiwisolver-1.4.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f8ad8285b01b0d4695102546b342b493b3ccc6781fc28c8c6a1bb63e95d22f09"}, + {file = "kiwisolver-1.4.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8ed58b8acf29798b036d347791141767ccf65eee7f26bde03a71c944449e53de"}, + {file = "kiwisolver-1.4.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a68b62a02953b9841730db7797422f983935aeefceb1679f0fc85cbfbd311c32"}, + {file = "kiwisolver-1.4.4-cp310-cp310-win32.whl", hash = "sha256:e92a513161077b53447160b9bd8f522edfbed4bd9759e4c18ab05d7ef7e49408"}, + {file = "kiwisolver-1.4.4-cp310-cp310-win_amd64.whl", hash = "sha256:3fe20f63c9ecee44560d0e7f116b3a747a5d7203376abeea292ab3152334d004"}, + {file = "kiwisolver-1.4.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:e0ea21f66820452a3f5d1655f8704a60d66ba1191359b96541eaf457710a5fc6"}, + {file = "kiwisolver-1.4.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:bc9db8a3efb3e403e4ecc6cd9489ea2bac94244f80c78e27c31dcc00d2790ac2"}, + {file = "kiwisolver-1.4.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d5b61785a9ce44e5a4b880272baa7cf6c8f48a5180c3e81c59553ba0cb0821ca"}, + {file = "kiwisolver-1.4.4-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c2dbb44c3f7e6c4d3487b31037b1bdbf424d97687c1747ce4ff2895795c9bf69"}, + {file = "kiwisolver-1.4.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6295ecd49304dcf3bfbfa45d9a081c96509e95f4b9d0eb7ee4ec0530c4a96514"}, + {file = "kiwisolver-1.4.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4bd472dbe5e136f96a4b18f295d159d7f26fd399136f5b17b08c4e5f498cd494"}, + {file = "kiwisolver-1.4.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bf7d9fce9bcc4752ca4a1b80aabd38f6d19009ea5cbda0e0856983cf6d0023f5"}, + {file = "kiwisolver-1.4.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78d6601aed50c74e0ef02f4204da1816147a6d3fbdc8b3872d263338a9052c51"}, + {file = "kiwisolver-1.4.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:877272cf6b4b7e94c9614f9b10140e198d2186363728ed0f701c6eee1baec1da"}, + {file = "kiwisolver-1.4.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:db608a6757adabb32f1cfe6066e39b3706d8c3aa69bbc353a5b61edad36a5cb4"}, + {file = "kiwisolver-1.4.4-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:5853eb494c71e267912275e5586fe281444eb5e722de4e131cddf9d442615626"}, + {file = "kiwisolver-1.4.4-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:f0a1dbdb5ecbef0d34eb77e56fcb3e95bbd7e50835d9782a45df81cc46949750"}, + {file = "kiwisolver-1.4.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:283dffbf061a4ec60391d51e6155e372a1f7a4f5b15d59c8505339454f8989e4"}, + {file = "kiwisolver-1.4.4-cp311-cp311-win32.whl", hash = "sha256:d06adcfa62a4431d404c31216f0f8ac97397d799cd53800e9d3efc2fbb3cf14e"}, + {file = "kiwisolver-1.4.4-cp311-cp311-win_amd64.whl", hash = "sha256:e7da3fec7408813a7cebc9e4ec55afed2d0fd65c4754bc376bf03498d4e92686"}, + {file = "kiwisolver-1.4.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:62ac9cc684da4cf1778d07a89bf5f81b35834cb96ca523d3a7fb32509380cbf6"}, + {file = "kiwisolver-1.4.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:41dae968a94b1ef1897cb322b39360a0812661dba7c682aa45098eb8e193dbdf"}, + {file = "kiwisolver-1.4.4-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:02f79693ec433cb4b5f51694e8477ae83b3205768a6fb48ffba60549080e295b"}, + {file = "kiwisolver-1.4.4-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d0611a0a2a518464c05ddd5a3a1a0e856ccc10e67079bb17f265ad19ab3c7597"}, + {file = "kiwisolver-1.4.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:db5283d90da4174865d520e7366801a93777201e91e79bacbac6e6927cbceede"}, + {file = "kiwisolver-1.4.4-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:1041feb4cda8708ce73bb4dcb9ce1ccf49d553bf87c3954bdfa46f0c3f77252c"}, + {file = "kiwisolver-1.4.4-cp37-cp37m-win32.whl", hash = "sha256:a553dadda40fef6bfa1456dc4be49b113aa92c2a9a9e8711e955618cd69622e3"}, + {file = "kiwisolver-1.4.4-cp37-cp37m-win_amd64.whl", hash = "sha256:03baab2d6b4a54ddbb43bba1a3a2d1627e82d205c5cf8f4c924dc49284b87166"}, + {file = "kiwisolver-1.4.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:841293b17ad704d70c578f1f0013c890e219952169ce8a24ebc063eecf775454"}, + {file = "kiwisolver-1.4.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f4f270de01dd3e129a72efad823da90cc4d6aafb64c410c9033aba70db9f1ff0"}, + {file = "kiwisolver-1.4.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f9f39e2f049db33a908319cf46624a569b36983c7c78318e9726a4cb8923b26c"}, + {file = "kiwisolver-1.4.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c97528e64cb9ebeff9701e7938653a9951922f2a38bd847787d4a8e498cc83ae"}, + {file = "kiwisolver-1.4.4-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d1573129aa0fd901076e2bfb4275a35f5b7aa60fbfb984499d661ec950320b0"}, + {file = "kiwisolver-1.4.4-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ad881edc7ccb9d65b0224f4e4d05a1e85cf62d73aab798943df6d48ab0cd79a1"}, + {file = "kiwisolver-1.4.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b428ef021242344340460fa4c9185d0b1f66fbdbfecc6c63eff4b7c29fad429d"}, + {file = "kiwisolver-1.4.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:2e407cb4bd5a13984a6c2c0fe1845e4e41e96f183e5e5cd4d77a857d9693494c"}, + {file = "kiwisolver-1.4.4-cp38-cp38-win32.whl", hash = "sha256:75facbe9606748f43428fc91a43edb46c7ff68889b91fa31f53b58894503a191"}, + {file = "kiwisolver-1.4.4-cp38-cp38-win_amd64.whl", hash = "sha256:5bce61af018b0cb2055e0e72e7d65290d822d3feee430b7b8203d8a855e78766"}, + {file = "kiwisolver-1.4.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8c808594c88a025d4e322d5bb549282c93c8e1ba71b790f539567932722d7bd8"}, + {file = "kiwisolver-1.4.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f0a71d85ecdd570ded8ac3d1c0f480842f49a40beb423bb8014539a9f32a5897"}, + {file = "kiwisolver-1.4.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b533558eae785e33e8c148a8d9921692a9fe5aa516efbdff8606e7d87b9d5824"}, + {file = "kiwisolver-1.4.4-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:efda5fc8cc1c61e4f639b8067d118e742b812c930f708e6667a5ce0d13499e29"}, + {file = "kiwisolver-1.4.4-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:7c43e1e1206cd421cd92e6b3280d4385d41d7166b3ed577ac20444b6995a445f"}, + {file = "kiwisolver-1.4.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bc8d3bd6c72b2dd9decf16ce70e20abcb3274ba01b4e1c96031e0c4067d1e7cd"}, + {file = "kiwisolver-1.4.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4ea39b0ccc4f5d803e3337dd46bcce60b702be4d86fd0b3d7531ef10fd99a1ac"}, + {file = "kiwisolver-1.4.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:968f44fdbf6dd757d12920d63b566eeb4d5b395fd2d00d29d7ef00a00582aac9"}, + {file = "kiwisolver-1.4.4-cp39-cp39-win32.whl", hash = "sha256:da7e547706e69e45d95e116e6939488d62174e033b763ab1496b4c29b76fabea"}, + {file = "kiwisolver-1.4.4-cp39-cp39-win_amd64.whl", hash = "sha256:ba59c92039ec0a66103b1d5fe588fa546373587a7d68f5c96f743c3396afc04b"}, + {file = "kiwisolver-1.4.4-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:91672bacaa030f92fc2f43b620d7b337fd9a5af28b0d6ed3f77afc43c4a64b5a"}, + {file = "kiwisolver-1.4.4-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:787518a6789009c159453da4d6b683f468ef7a65bbde796bcea803ccf191058d"}, + {file = "kiwisolver-1.4.4-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da152d8cdcab0e56e4f45eb08b9aea6455845ec83172092f09b0e077ece2cf7a"}, + {file = "kiwisolver-1.4.4-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:ecb1fa0db7bf4cff9dac752abb19505a233c7f16684c5826d1f11ebd9472b871"}, + {file = "kiwisolver-1.4.4-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:28bc5b299f48150b5f822ce68624e445040595a4ac3d59251703779836eceff9"}, + {file = "kiwisolver-1.4.4-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:81e38381b782cc7e1e46c4e14cd997ee6040768101aefc8fa3c24a4cc58e98f8"}, + {file = "kiwisolver-1.4.4-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:2a66fdfb34e05b705620dd567f5a03f239a088d5a3f321e7b6ac3239d22aa286"}, + {file = "kiwisolver-1.4.4-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:872b8ca05c40d309ed13eb2e582cab0c5a05e81e987ab9c521bf05ad1d5cf5cb"}, + {file = "kiwisolver-1.4.4-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:70e7c2e7b750585569564e2e5ca9845acfaa5da56ac46df68414f29fea97be9f"}, + {file = "kiwisolver-1.4.4-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:9f85003f5dfa867e86d53fac6f7e6f30c045673fa27b603c397753bebadc3008"}, + {file = "kiwisolver-1.4.4-pp39-pypy39_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2e307eb9bd99801f82789b44bb45e9f541961831c7311521b13a6c85afc09767"}, + {file = "kiwisolver-1.4.4-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b1792d939ec70abe76f5054d3f36ed5656021dcad1322d1cc996d4e54165cef9"}, + {file = "kiwisolver-1.4.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6cb459eea32a4e2cf18ba5fcece2dbdf496384413bc1bae15583f19e567f3b2"}, + {file = "kiwisolver-1.4.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:36dafec3d6d6088d34e2de6b85f9d8e2324eb734162fba59d2ba9ed7a2043d5b"}, + {file = "kiwisolver-1.4.4.tar.gz", hash = "sha256:d41997519fcba4a1e46eb4a2fe31bc12f0ff957b2b81bac28db24744f333e955"}, +] lazy-object-proxy = [ {file = "lazy-object-proxy-1.8.0.tar.gz", hash = "sha256:c219a00245af0f6fa4e95901ed28044544f50152840c5b6a3e7b2568db34d156"}, {file = "lazy_object_proxy-1.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4fd031589121ad46e293629b39604031d354043bb5cdf83da4e93c2d7f3389fe"}, @@ -611,6 +1066,52 @@ lazy-object-proxy = [ {file = "lazy_object_proxy-1.8.0-pp38-pypy38_pp73-any.whl", hash = "sha256:7e1561626c49cb394268edd00501b289053a652ed762c58e1081224c8d881cec"}, {file = "lazy_object_proxy-1.8.0-pp39-pypy39_pp73-any.whl", hash = "sha256:ce58b2b3734c73e68f0e30e4e725264d4d6be95818ec0a0be4bb6bf9a7e79aa8"}, ] +lightfm = [ + {file = "lightfm-1.16.tar.gz", hash = "sha256:41950fd8affde192c10b517148aa7f6d016ae2f75a2ec1187335f1c4d21876ac"}, +] +matplotlib = [ + {file = "matplotlib-3.6.2-cp310-cp310-macosx_10_12_universal2.whl", hash = "sha256:8d0068e40837c1d0df6e3abf1cdc9a34a6d2611d90e29610fa1d2455aeb4e2e5"}, + {file = "matplotlib-3.6.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:252957e208c23db72ca9918cb33e160c7833faebf295aaedb43f5b083832a267"}, + {file = "matplotlib-3.6.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d50e8c1e571ee39b5dfbc295c11ad65988879f68009dd281a6e1edbc2ff6c18c"}, + {file = "matplotlib-3.6.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d840adcad7354be6f2ec28d0706528b0026e4c3934cc6566b84eac18633eab1b"}, + {file = "matplotlib-3.6.2-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:78ec3c3412cf277e6252764ee4acbdbec6920cc87ad65862272aaa0e24381eee"}, + {file = "matplotlib-3.6.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9347cc6822f38db2b1d1ce992f375289670e595a2d1c15961aacbe0977407dfc"}, + {file = "matplotlib-3.6.2-cp310-cp310-win32.whl", hash = "sha256:e0bbee6c2a5bf2a0017a9b5e397babb88f230e6f07c3cdff4a4c4bc75ed7c617"}, + {file = "matplotlib-3.6.2-cp310-cp310-win_amd64.whl", hash = "sha256:8a0ae37576ed444fe853709bdceb2be4c7df6f7acae17b8378765bd28e61b3ae"}, + {file = "matplotlib-3.6.2-cp311-cp311-macosx_10_12_universal2.whl", hash = "sha256:5ecfc6559132116dedfc482d0ad9df8a89dc5909eebffd22f3deb684132d002f"}, + {file = "matplotlib-3.6.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:9f335e5625feb90e323d7e3868ec337f7b9ad88b5d633f876e3b778813021dab"}, + {file = "matplotlib-3.6.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b2604c6450f9dd2c42e223b1f5dca9643a23cfecc9fde4a94bb38e0d2693b136"}, + {file = "matplotlib-3.6.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e5afe0a7ea0e3a7a257907060bee6724a6002b7eec55d0db16fd32409795f3e1"}, + {file = "matplotlib-3.6.2-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ca0e7a658fbafcddcaefaa07ba8dae9384be2343468a8e011061791588d839fa"}, + {file = "matplotlib-3.6.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:32d29c8c26362169c80c5718ce367e8c64f4dd068a424e7110df1dd2ed7bd428"}, + {file = "matplotlib-3.6.2-cp311-cp311-win32.whl", hash = "sha256:5024b8ed83d7f8809982d095d8ab0b179bebc07616a9713f86d30cf4944acb73"}, + {file = "matplotlib-3.6.2-cp311-cp311-win_amd64.whl", hash = "sha256:52c2bdd7cd0bf9d5ccdf9c1816568fd4ccd51a4d82419cc5480f548981b47dd0"}, + {file = "matplotlib-3.6.2-cp38-cp38-macosx_10_12_universal2.whl", hash = "sha256:8a8dbe2cb7f33ff54b16bb5c500673502a35f18ac1ed48625e997d40c922f9cc"}, + {file = "matplotlib-3.6.2-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:380d48c15ec41102a2b70858ab1dedfa33eb77b2c0982cb65a200ae67a48e9cb"}, + {file = "matplotlib-3.6.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:0844523dfaaff566e39dbfa74e6f6dc42e92f7a365ce80929c5030b84caa563a"}, + {file = "matplotlib-3.6.2-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:7f716b6af94dc1b6b97c46401774472f0867e44595990fe80a8ba390f7a0a028"}, + {file = "matplotlib-3.6.2-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:74153008bd24366cf099d1f1e83808d179d618c4e32edb0d489d526523a94d9f"}, + {file = "matplotlib-3.6.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f41e57ad63d336fe50d3a67bb8eaa26c09f6dda6a59f76777a99b8ccd8e26aec"}, + {file = "matplotlib-3.6.2-cp38-cp38-win32.whl", hash = "sha256:d0e9ac04065a814d4cf2c6791a2ad563f739ae3ae830d716d54245c2b96fead6"}, + {file = "matplotlib-3.6.2-cp38-cp38-win_amd64.whl", hash = "sha256:8a9d899953c722b9afd7e88dbefd8fb276c686c3116a43c577cfabf636180558"}, + {file = "matplotlib-3.6.2-cp39-cp39-macosx_10_12_universal2.whl", hash = "sha256:f04f97797df35e442ed09f529ad1235d1f1c0f30878e2fe09a2676b71a8801e0"}, + {file = "matplotlib-3.6.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:3964934731fd7a289a91d315919cf757f293969a4244941ab10513d2351b4e83"}, + {file = "matplotlib-3.6.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:168093410b99f647ba61361b208f7b0d64dde1172b5b1796d765cd243cadb501"}, + {file = "matplotlib-3.6.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5e16dcaecffd55b955aa5e2b8a804379789c15987e8ebd2f32f01398a81e975b"}, + {file = "matplotlib-3.6.2-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:83dc89c5fd728fdb03b76f122f43b4dcee8c61f1489e232d9ad0f58020523e1c"}, + {file = "matplotlib-3.6.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:795ad83940732b45d39b82571f87af0081c120feff2b12e748d96bb191169e33"}, + {file = "matplotlib-3.6.2-cp39-cp39-win32.whl", hash = "sha256:19d61ee6414c44a04addbe33005ab1f87539d9f395e25afcbe9a3c50ce77c65c"}, + {file = "matplotlib-3.6.2-cp39-cp39-win_amd64.whl", hash = "sha256:5ba73aa3aca35d2981e0b31230d58abb7b5d7ca104e543ae49709208d8ce706a"}, + {file = "matplotlib-3.6.2-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:1836f366272b1557a613f8265db220eb8dd883202bbbabe01bad5a4eadfd0c95"}, + {file = "matplotlib-3.6.2-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0eda9d1b43f265da91fb9ae10d6922b5a986e2234470a524e6b18f14095b20d2"}, + {file = "matplotlib-3.6.2-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec9be0f4826cdb3a3a517509dcc5f87f370251b76362051ab59e42b6b765f8c4"}, + {file = "matplotlib-3.6.2-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:3cef89888a466228fc4e4b2954e740ce8e9afde7c4315fdd18caa1b8de58ca17"}, + {file = "matplotlib-3.6.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:54fa9fe27f5466b86126ff38123261188bed568c1019e4716af01f97a12fe812"}, + {file = "matplotlib-3.6.2-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e68be81cd8c22b029924b6d0ee814c337c0e706b8d88495a617319e5dd5441c3"}, + {file = "matplotlib-3.6.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b0ca2c60d3966dfd6608f5f8c49b8a0fcf76de6654f2eda55fc6ef038d5a6f27"}, + {file = "matplotlib-3.6.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:4426c74761790bff46e3d906c14c7aab727543293eed5a924300a952e1a3a3c1"}, + {file = "matplotlib-3.6.2.tar.gz", hash = "sha256:b03fd10a1709d0101c054883b550f7c4c5e974f751e2680318759af005964990"}, +] mccabe = [ {file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"}, {file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"}, @@ -643,6 +1144,73 @@ mypy-extensions = [ {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"}, {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"}, ] +nmslib = [ + {file = "nmslib-2.1.1-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:495ace1146bb1e89ef585a490fa65de19a87fa0d5bb029f3156402a431fc3558"}, + {file = "nmslib-2.1.1-cp27-cp27m-macosx_10_15_x86_64.whl", hash = "sha256:c0ae48f01e63e70dc1e45b28cb1b1478ca09588a21127f1d4473afb22ff3bbbc"}, + {file = "nmslib-2.1.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:97b3f1af2c163369a043449dec7f05d681aa23c00f9d77bee09fd8f31ba41815"}, + {file = "nmslib-2.1.1-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:2061e94f980666bffff4f2173bf2b58a763062dee9cedab11ec46001e576c6b5"}, + {file = "nmslib-2.1.1-cp27-cp27m-win_amd64.whl", hash = "sha256:e8b30bab631258b36e751d217180cdba0d2f942d779d4444cbc57a5173ee19ad"}, + {file = "nmslib-2.1.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:191a23dea20c0ad855e78df41a90273020f76d878c52aa1a80557ca83cf0f392"}, + {file = "nmslib-2.1.1-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:eae9a1d640a9e4c52c43272620f54f367f03ce25d8b07218fd90dfc204d5c49d"}, + {file = "nmslib-2.1.1-cp35-cp35m-macosx_10_14_x86_64.whl", hash = "sha256:c22ffc3376d41b4b4e63d89ec5db2cf2e2051881827d658c94632800bed87e5b"}, + {file = "nmslib-2.1.1-cp35-cp35m-macosx_10_15_x86_64.whl", hash = "sha256:a1ff4aeb143747106994a68dfcc29b097fc4562f632f2709f8f467b93d7181e2"}, + {file = "nmslib-2.1.1-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:5ce529d4f9b572135cdc5a18f04d3cbe258f1f440f8a06ab7209428a3b4c30d6"}, + {file = "nmslib-2.1.1-cp35-cp35m-win_amd64.whl", hash = "sha256:00f5b37305837fd5656ab4a65c4f0c9bc8e44cc9cf77cc9222f4153a72f0c727"}, + {file = "nmslib-2.1.1-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:08cb77c3fc2a346edc3407bd985b63a05bd0ec0d6d81ff2c6f7d6eb6bfbdbc1d"}, + {file = "nmslib-2.1.1-cp36-cp36m-macosx_10_15_x86_64.whl", hash = "sha256:7dcc203450c9d95a551e9564646b9d0179edbde0874373ad63739b7e25a9980c"}, + {file = "nmslib-2.1.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:db4b817f0896e0bbc836722c67b51bc237dc79477d2d383ced344d755705d409"}, + {file = "nmslib-2.1.1-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:1b120f7766a52c4016c6b8889b34d97eddbb60a16fd39eb5a81e73ca101baf3e"}, + {file = "nmslib-2.1.1-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:9e5cd5d492bf7290adacac797ee092c863d230f3797d0db6a120a1a05c665be2"}, + {file = "nmslib-2.1.1-cp36-cp36m-win_amd64.whl", hash = "sha256:0a80e574c3e6bfb724dbb77cbaec53cf9f4366382c2c0a9a2f5148c69b646afe"}, + {file = "nmslib-2.1.1-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:7b0d916f219b4044cd31e8f6bda92a7f23d68cb3f34f1c7da81e5852702d6ce0"}, + {file = "nmslib-2.1.1-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:a2129a7519ab73d3544ab6fa2f6c6c4c54644bf3d1c60d6929dcaac49c9307e6"}, + {file = "nmslib-2.1.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:0f5c1c7e3c398a4ed7eaed65cd91776022b2ca4b8f15e504fa22c89da9333257"}, + {file = "nmslib-2.1.1-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:c5a644d32ad3b2e24635a839d17d9d53d01a47ca55d1ba0d051f51f49df7e98a"}, + {file = "nmslib-2.1.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:fc75c7e128fd19c21c8cd73a1681a32d902bf5203699321cdfff8cf98607c82d"}, + {file = "nmslib-2.1.1-cp37-cp37m-win_amd64.whl", hash = "sha256:43118bb64f06e62662a8c7f1fe54ae699a078b438e3f8cb75db547731a5e73f6"}, + {file = "nmslib-2.1.1-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:1b87f7a5813cabedef47b289337ab1eefa4e62485a05884c2dbe7ba1d9c327a4"}, + {file = "nmslib-2.1.1-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:ca3d4eb91232078fb96eaa938a4dcbcfb3da48a7800350e1ded70d8d3e6e65a5"}, + {file = "nmslib-2.1.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:b6ebb53999672abf7811ef35e2ec3d76b2a845fd5dbaa5482e2cc445481d87cf"}, + {file = "nmslib-2.1.1-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:26062f5f172c35038c46feabb5c60c104808c167db0c3dfab19d11eb99f18b85"}, + {file = "nmslib-2.1.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:ed63fda2a5572391a0a540689f00d390040b9255e08012ea43344958cea92f36"}, + {file = "nmslib-2.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:6a3aa123d85c188fc64cb8957e5cdded9c8c57bea2c6a5866fe06c729e6e6e85"}, + {file = "nmslib-2.1.1-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:3fe5bbf304fdde50f3a55329efcf26d4ba4eb1181885877a1baab1df900dd671"}, + {file = "nmslib-2.1.1-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:7b5a561a71dce6d56b32ea89a591dbe477b4173fbc3e9a1153d534bc248ae7b5"}, + {file = "nmslib-2.1.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:82680077a06a817df95ea716260231245cf077a4c08b0f39148d4a58d2eb58f2"}, + {file = "nmslib-2.1.1-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:be54644e1a1a6e2539e565fe24415997f18656a5260276c40266cacb70e2a9ab"}, + {file = "nmslib-2.1.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:3681e3e9160fa9661192c19202402e22151e016cf365621609ae5ca4a4677d21"}, + {file = "nmslib-2.1.1.tar.gz", hash = "sha256:971294a7766f91c697d63c88c8adda4797a944346cc535a217393f4167a19c20"}, +] +numpy = [ + {file = "numpy-1.23.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9c88793f78fca17da0145455f0d7826bcb9f37da4764af27ac945488116efe63"}, + {file = "numpy-1.23.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e9f4c4e51567b616be64e05d517c79a8a22f3606499941d97bb76f2ca59f982d"}, + {file = "numpy-1.23.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7903ba8ab592b82014713c491f6c5d3a1cde5b4a3bf116404e08f5b52f6daf43"}, + {file = "numpy-1.23.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5e05b1c973a9f858c74367553e236f287e749465f773328c8ef31abe18f691e1"}, + {file = "numpy-1.23.5-cp310-cp310-win32.whl", hash = "sha256:522e26bbf6377e4d76403826ed689c295b0b238f46c28a7251ab94716da0b280"}, + {file = "numpy-1.23.5-cp310-cp310-win_amd64.whl", hash = "sha256:dbee87b469018961d1ad79b1a5d50c0ae850000b639bcb1b694e9981083243b6"}, + {file = "numpy-1.23.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ce571367b6dfe60af04e04a1834ca2dc5f46004ac1cc756fb95319f64c095a96"}, + {file = "numpy-1.23.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:56e454c7833e94ec9769fa0f86e6ff8e42ee38ce0ce1fa4cbb747ea7e06d56aa"}, + {file = "numpy-1.23.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5039f55555e1eab31124a5768898c9e22c25a65c1e0037f4d7c495a45778c9f2"}, + {file = "numpy-1.23.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58f545efd1108e647604a1b5aa809591ccd2540f468a880bedb97247e72db387"}, + {file = "numpy-1.23.5-cp311-cp311-win32.whl", hash = "sha256:b2a9ab7c279c91974f756c84c365a669a887efa287365a8e2c418f8b3ba73fb0"}, + {file = "numpy-1.23.5-cp311-cp311-win_amd64.whl", hash = "sha256:0cbe9848fad08baf71de1a39e12d1b6310f1d5b2d0ea4de051058e6e1076852d"}, + {file = "numpy-1.23.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f063b69b090c9d918f9df0a12116029e274daf0181df392839661c4c7ec9018a"}, + {file = "numpy-1.23.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:0aaee12d8883552fadfc41e96b4c82ee7d794949e2a7c3b3a7201e968c7ecab9"}, + {file = "numpy-1.23.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:92c8c1e89a1f5028a4c6d9e3ccbe311b6ba53694811269b992c0b224269e2398"}, + {file = "numpy-1.23.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d208a0f8729f3fb790ed18a003f3a57895b989b40ea4dce4717e9cf4af62c6bb"}, + {file = "numpy-1.23.5-cp38-cp38-win32.whl", hash = "sha256:06005a2ef6014e9956c09ba07654f9837d9e26696a0470e42beedadb78c11b07"}, + {file = "numpy-1.23.5-cp38-cp38-win_amd64.whl", hash = "sha256:ca51fcfcc5f9354c45f400059e88bc09215fb71a48d3768fb80e357f3b457e1e"}, + {file = "numpy-1.23.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8969bfd28e85c81f3f94eb4a66bc2cf1dbdc5c18efc320af34bffc54d6b1e38f"}, + {file = "numpy-1.23.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a7ac231a08bb37f852849bbb387a20a57574a97cfc7b6cabb488a4fc8be176de"}, + {file = "numpy-1.23.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf837dc63ba5c06dc8797c398db1e223a466c7ece27a1f7b5232ba3466aafe3d"}, + {file = "numpy-1.23.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:33161613d2269025873025b33e879825ec7b1d831317e68f4f2f0f84ed14c719"}, + {file = "numpy-1.23.5-cp39-cp39-win32.whl", hash = "sha256:af1da88f6bc3d2338ebbf0e22fe487821ea4d8e89053e25fa59d1d79786e7481"}, + {file = "numpy-1.23.5-cp39-cp39-win_amd64.whl", hash = "sha256:09b7847f7e83ca37c6e627682f145856de331049013853f344f37b0c9690e3df"}, + {file = "numpy-1.23.5-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:abdde9f795cf292fb9651ed48185503a2ff29be87770c3b8e2a14b0cd7aa16f8"}, + {file = "numpy-1.23.5-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f9a909a8bae284d46bbfdefbdd4a262ba19d3bc9921b1e76126b1d21c3c34135"}, + {file = "numpy-1.23.5-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:01dd17cbb340bf0fc23981e52e1d18a9d4050792e8fb8363cecbf066a84b827d"}, + {file = "numpy-1.23.5.tar.gz", hash = "sha256:1b1766d6f397c18153d40015ddfc79ddb715cabadc04d2d228d4e5a8bc4ded1a"}, +] orjson = [ {file = "orjson-3.8.1-cp310-cp310-macosx_10_7_x86_64.whl", hash = "sha256:a70aaa2e56356e58c6e1b49f7b7f069df5b15e55db002a74db3ff3f7af67c7ff"}, {file = "orjson-3.8.1-cp310-cp310-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:d45db052d01d0ab7579470141d5c3592f4402d43cfacb67f023bc1210a67b7bc"}, @@ -698,18 +1266,130 @@ packaging = [ {file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"}, {file = "packaging-21.3.tar.gz", hash = "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb"}, ] +pandas = [ + {file = "pandas-1.5.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e9dbacd22555c2d47f262ef96bb4e30880e5956169741400af8b306bbb24a273"}, + {file = "pandas-1.5.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e2b83abd292194f350bb04e188f9379d36b8dfac24dd445d5c87575f3beaf789"}, + {file = "pandas-1.5.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2552bffc808641c6eb471e55aa6899fa002ac94e4eebfa9ec058649122db5824"}, + {file = "pandas-1.5.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fc87eac0541a7d24648a001d553406f4256e744d92df1df8ebe41829a915028"}, + {file = "pandas-1.5.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d0d8fd58df5d17ddb8c72a5075d87cd80d71b542571b5f78178fb067fa4e9c72"}, + {file = "pandas-1.5.2-cp310-cp310-win_amd64.whl", hash = "sha256:4aed257c7484d01c9a194d9a94758b37d3d751849c05a0050c087a358c41ad1f"}, + {file = "pandas-1.5.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:375262829c8c700c3e7cbb336810b94367b9c4889818bbd910d0ecb4e45dc261"}, + {file = "pandas-1.5.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cc3cd122bea268998b79adebbb8343b735a5511ec14efb70a39e7acbc11ccbdc"}, + {file = "pandas-1.5.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b4f5a82afa4f1ff482ab8ded2ae8a453a2cdfde2001567b3ca24a4c5c5ca0db3"}, + {file = "pandas-1.5.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8092a368d3eb7116e270525329a3e5c15ae796ccdf7ccb17839a73b4f5084a39"}, + {file = "pandas-1.5.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6257b314fc14958f8122779e5a1557517b0f8e500cfb2bd53fa1f75a8ad0af2"}, + {file = "pandas-1.5.2-cp311-cp311-win_amd64.whl", hash = "sha256:82ae615826da838a8e5d4d630eb70c993ab8636f0eff13cb28aafc4291b632b5"}, + {file = "pandas-1.5.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:457d8c3d42314ff47cc2d6c54f8fc0d23954b47977b2caed09cd9635cb75388b"}, + {file = "pandas-1.5.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:c009a92e81ce836212ce7aa98b219db7961a8b95999b97af566b8dc8c33e9519"}, + {file = "pandas-1.5.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:71f510b0efe1629bf2f7c0eadb1ff0b9cf611e87b73cd017e6b7d6adb40e2b3a"}, + {file = "pandas-1.5.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a40dd1e9f22e01e66ed534d6a965eb99546b41d4d52dbdb66565608fde48203f"}, + {file = "pandas-1.5.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5ae7e989f12628f41e804847a8cc2943d362440132919a69429d4dea1f164da0"}, + {file = "pandas-1.5.2-cp38-cp38-win32.whl", hash = "sha256:530948945e7b6c95e6fa7aa4be2be25764af53fba93fe76d912e35d1c9ee46f5"}, + {file = "pandas-1.5.2-cp38-cp38-win_amd64.whl", hash = "sha256:73f219fdc1777cf3c45fde7f0708732ec6950dfc598afc50588d0d285fddaefc"}, + {file = "pandas-1.5.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:9608000a5a45f663be6af5c70c3cbe634fa19243e720eb380c0d378666bc7702"}, + {file = "pandas-1.5.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:315e19a3e5c2ab47a67467fc0362cb36c7c60a93b6457f675d7d9615edad2ebe"}, + {file = "pandas-1.5.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e18bc3764cbb5e118be139b3b611bc3fbc5d3be42a7e827d1096f46087b395eb"}, + {file = "pandas-1.5.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0183cb04a057cc38fde5244909fca9826d5d57c4a5b7390c0cc3fa7acd9fa883"}, + {file = "pandas-1.5.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:344021ed3e639e017b452aa8f5f6bf38a8806f5852e217a7594417fb9bbfa00e"}, + {file = "pandas-1.5.2-cp39-cp39-win32.whl", hash = "sha256:e7469271497960b6a781eaa930cba8af400dd59b62ec9ca2f4d31a19f2f91090"}, + {file = "pandas-1.5.2-cp39-cp39-win_amd64.whl", hash = "sha256:c218796d59d5abd8780170c937b812c9637e84c32f8271bbf9845970f8c1351f"}, + {file = "pandas-1.5.2.tar.gz", hash = "sha256:220b98d15cee0b2cd839a6358bd1f273d0356bf964c1a1aeb32d47db0215488b"}, +] pbr = [ {file = "pbr-5.11.0-py2.py3-none-any.whl", hash = "sha256:db2317ff07c84c4c63648c9064a79fe9d9f5c7ce85a9099d4b6258b3db83225a"}, {file = "pbr-5.11.0.tar.gz", hash = "sha256:b97bc6695b2aff02144133c2e7399d5885223d42b7912ffaec2ca3898e673bfe"}, ] +pillow = [ + {file = "Pillow-9.3.0-1-cp37-cp37m-win32.whl", hash = "sha256:e6ea6b856a74d560d9326c0f5895ef8050126acfdc7ca08ad703eb0081e82b74"}, + {file = "Pillow-9.3.0-1-cp37-cp37m-win_amd64.whl", hash = "sha256:32a44128c4bdca7f31de5be641187367fe2a450ad83b833ef78910397db491aa"}, + {file = "Pillow-9.3.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:0b7257127d646ff8676ec8a15520013a698d1fdc48bc2a79ba4e53df792526f2"}, + {file = "Pillow-9.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b90f7616ea170e92820775ed47e136208e04c967271c9ef615b6fbd08d9af0e3"}, + {file = "Pillow-9.3.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:68943d632f1f9e3dce98908e873b3a090f6cba1cbb1b892a9e8d97c938871fbe"}, + {file = "Pillow-9.3.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:be55f8457cd1eac957af0c3f5ece7bc3f033f89b114ef30f710882717670b2a8"}, + {file = "Pillow-9.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d77adcd56a42d00cc1be30843d3426aa4e660cab4a61021dc84467123f7a00c"}, + {file = "Pillow-9.3.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:829f97c8e258593b9daa80638aee3789b7df9da5cf1336035016d76f03b8860c"}, + {file = "Pillow-9.3.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:801ec82e4188e935c7f5e22e006d01611d6b41661bba9fe45b60e7ac1a8f84de"}, + {file = "Pillow-9.3.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:871b72c3643e516db4ecf20efe735deb27fe30ca17800e661d769faab45a18d7"}, + {file = "Pillow-9.3.0-cp310-cp310-win32.whl", hash = "sha256:655a83b0058ba47c7c52e4e2df5ecf484c1b0b0349805896dd350cbc416bdd91"}, + {file = "Pillow-9.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:9f47eabcd2ded7698106b05c2c338672d16a6f2a485e74481f524e2a23c2794b"}, + {file = "Pillow-9.3.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:57751894f6618fd4308ed8e0c36c333e2f5469744c34729a27532b3db106ee20"}, + {file = "Pillow-9.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7db8b751ad307d7cf238f02101e8e36a128a6cb199326e867d1398067381bff4"}, + {file = "Pillow-9.3.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3033fbe1feb1b59394615a1cafaee85e49d01b51d54de0cbf6aa8e64182518a1"}, + {file = "Pillow-9.3.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:22b012ea2d065fd163ca096f4e37e47cd8b59cf4b0fd47bfca6abb93df70b34c"}, + {file = "Pillow-9.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b9a65733d103311331875c1dca05cb4606997fd33d6acfed695b1232ba1df193"}, + {file = "Pillow-9.3.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:502526a2cbfa431d9fc2a079bdd9061a2397b842bb6bc4239bb176da00993812"}, + {file = "Pillow-9.3.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:90fb88843d3902fe7c9586d439d1e8c05258f41da473952aa8b328d8b907498c"}, + {file = "Pillow-9.3.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:89dca0ce00a2b49024df6325925555d406b14aa3efc2f752dbb5940c52c56b11"}, + {file = "Pillow-9.3.0-cp311-cp311-win32.whl", hash = "sha256:3168434d303babf495d4ba58fc22d6604f6e2afb97adc6a423e917dab828939c"}, + {file = "Pillow-9.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:18498994b29e1cf86d505edcb7edbe814d133d2232d256db8c7a8ceb34d18cef"}, + {file = "Pillow-9.3.0-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:772a91fc0e03eaf922c63badeca75e91baa80fe2f5f87bdaed4280662aad25c9"}, + {file = "Pillow-9.3.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:afa4107d1b306cdf8953edde0534562607fe8811b6c4d9a486298ad31de733b2"}, + {file = "Pillow-9.3.0-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b4012d06c846dc2b80651b120e2cdd787b013deb39c09f407727ba90015c684f"}, + {file = "Pillow-9.3.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:77ec3e7be99629898c9a6d24a09de089fa5356ee408cdffffe62d67bb75fdd72"}, + {file = "Pillow-9.3.0-cp37-cp37m-manylinux_2_28_aarch64.whl", hash = "sha256:6c738585d7a9961d8c2821a1eb3dcb978d14e238be3d70f0a706f7fa9316946b"}, + {file = "Pillow-9.3.0-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:828989c45c245518065a110434246c44a56a8b2b2f6347d1409c787e6e4651ee"}, + {file = "Pillow-9.3.0-cp37-cp37m-win32.whl", hash = "sha256:82409ffe29d70fd733ff3c1025a602abb3e67405d41b9403b00b01debc4c9a29"}, + {file = "Pillow-9.3.0-cp37-cp37m-win_amd64.whl", hash = "sha256:41e0051336807468be450d52b8edd12ac60bebaa97fe10c8b660f116e50b30e4"}, + {file = "Pillow-9.3.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:b03ae6f1a1878233ac620c98f3459f79fd77c7e3c2b20d460284e1fb370557d4"}, + {file = "Pillow-9.3.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4390e9ce199fc1951fcfa65795f239a8a4944117b5935a9317fb320e7767b40f"}, + {file = "Pillow-9.3.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40e1ce476a7804b0fb74bcfa80b0a2206ea6a882938eaba917f7a0f004b42502"}, + {file = "Pillow-9.3.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a0a06a052c5f37b4ed81c613a455a81f9a3a69429b4fd7bb913c3fa98abefc20"}, + {file = "Pillow-9.3.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:03150abd92771742d4a8cd6f2fa6246d847dcd2e332a18d0c15cc75bf6703040"}, + {file = "Pillow-9.3.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:15c42fb9dea42465dfd902fb0ecf584b8848ceb28b41ee2b58f866411be33f07"}, + {file = "Pillow-9.3.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:51e0e543a33ed92db9f5ef69a0356e0b1a7a6b6a71b80df99f1d181ae5875636"}, + {file = "Pillow-9.3.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:3dd6caf940756101205dffc5367babf288a30043d35f80936f9bfb37f8355b32"}, + {file = "Pillow-9.3.0-cp38-cp38-win32.whl", hash = "sha256:f1ff2ee69f10f13a9596480335f406dd1f70c3650349e2be67ca3139280cade0"}, + {file = "Pillow-9.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:276a5ca930c913f714e372b2591a22c4bd3b81a418c0f6635ba832daec1cbcfc"}, + {file = "Pillow-9.3.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:73bd195e43f3fadecfc50c682f5055ec32ee2c933243cafbfdec69ab1aa87cad"}, + {file = "Pillow-9.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1c7c8ae3864846fc95f4611c78129301e203aaa2af813b703c55d10cc1628535"}, + {file = "Pillow-9.3.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2e0918e03aa0c72ea56edbb00d4d664294815aa11291a11504a377ea018330d3"}, + {file = "Pillow-9.3.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b0915e734b33a474d76c28e07292f196cdf2a590a0d25bcc06e64e545f2d146c"}, + {file = "Pillow-9.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:af0372acb5d3598f36ec0914deed2a63f6bcdb7b606da04dc19a88d31bf0c05b"}, + {file = "Pillow-9.3.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:ad58d27a5b0262c0c19b47d54c5802db9b34d38bbf886665b626aff83c74bacd"}, + {file = "Pillow-9.3.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:97aabc5c50312afa5e0a2b07c17d4ac5e865b250986f8afe2b02d772567a380c"}, + {file = "Pillow-9.3.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:9aaa107275d8527e9d6e7670b64aabaaa36e5b6bd71a1015ddd21da0d4e06448"}, + {file = "Pillow-9.3.0-cp39-cp39-win32.whl", hash = "sha256:bac18ab8d2d1e6b4ce25e3424f709aceef668347db8637c2296bcf41acb7cf48"}, + {file = "Pillow-9.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:b472b5ea442148d1c3e2209f20f1e0bb0eb556538690fa70b5e1f79fa0ba8dc2"}, + {file = "Pillow-9.3.0-pp37-pypy37_pp73-macosx_10_10_x86_64.whl", hash = "sha256:ab388aaa3f6ce52ac1cb8e122c4bd46657c15905904b3120a6248b5b8b0bc228"}, + {file = "Pillow-9.3.0-pp37-pypy37_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dbb8e7f2abee51cef77673be97760abff1674ed32847ce04b4af90f610144c7b"}, + {file = "Pillow-9.3.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bca31dd6014cb8b0b2db1e46081b0ca7d936f856da3b39744aef499db5d84d02"}, + {file = "Pillow-9.3.0-pp37-pypy37_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:c7025dce65566eb6e89f56c9509d4f628fddcedb131d9465cacd3d8bac337e7e"}, + {file = "Pillow-9.3.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:ebf2029c1f464c59b8bdbe5143c79fa2045a581ac53679733d3a91d400ff9efb"}, + {file = "Pillow-9.3.0-pp38-pypy38_pp73-macosx_10_10_x86_64.whl", hash = "sha256:b59430236b8e58840a0dfb4099a0e8717ffb779c952426a69ae435ca1f57210c"}, + {file = "Pillow-9.3.0-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:12ce4932caf2ddf3e41d17fc9c02d67126935a44b86df6a206cf0d7161548627"}, + {file = "Pillow-9.3.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ae5331c23ce118c53b172fa64a4c037eb83c9165aba3a7ba9ddd3ec9fa64a699"}, + {file = "Pillow-9.3.0-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:0b07fffc13f474264c336298d1b4ce01d9c5a011415b79d4ee5527bb69ae6f65"}, + {file = "Pillow-9.3.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:073adb2ae23431d3b9bcbcff3fe698b62ed47211d0716b067385538a1b0f28b8"}, + {file = "Pillow-9.3.0.tar.gz", hash = "sha256:c935a22a557a560108d780f9a0fc426dd7459940dc54faa49d83249c8d3e760f"}, +] pluggy = [ {file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"}, {file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"}, ] +psutil = [ + {file = "psutil-5.9.4-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:c1ca331af862803a42677c120aff8a814a804e09832f166f226bfd22b56feee8"}, + {file = "psutil-5.9.4-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:68908971daf802203f3d37e78d3f8831b6d1014864d7a85937941bb35f09aefe"}, + {file = "psutil-5.9.4-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:3ff89f9b835100a825b14c2808a106b6fdcc4b15483141482a12c725e7f78549"}, + {file = "psutil-5.9.4-cp27-cp27m-win32.whl", hash = "sha256:852dd5d9f8a47169fe62fd4a971aa07859476c2ba22c2254d4a1baa4e10b95ad"}, + {file = "psutil-5.9.4-cp27-cp27m-win_amd64.whl", hash = "sha256:9120cd39dca5c5e1c54b59a41d205023d436799b1c8c4d3ff71af18535728e94"}, + {file = "psutil-5.9.4-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:6b92c532979bafc2df23ddc785ed116fced1f492ad90a6830cf24f4d1ea27d24"}, + {file = "psutil-5.9.4-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:efeae04f9516907be44904cc7ce08defb6b665128992a56957abc9b61dca94b7"}, + {file = "psutil-5.9.4-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:54d5b184728298f2ca8567bf83c422b706200bcbbfafdc06718264f9393cfeb7"}, + {file = "psutil-5.9.4-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:16653106f3b59386ffe10e0bad3bb6299e169d5327d3f187614b1cb8f24cf2e1"}, + {file = "psutil-5.9.4-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:54c0d3d8e0078b7666984e11b12b88af2db11d11249a8ac8920dd5ef68a66e08"}, + {file = "psutil-5.9.4-cp36-abi3-win32.whl", hash = "sha256:149555f59a69b33f056ba1c4eb22bb7bf24332ce631c44a319cec09f876aaeff"}, + {file = "psutil-5.9.4-cp36-abi3-win_amd64.whl", hash = "sha256:fd8522436a6ada7b4aad6638662966de0d61d241cb821239b2ae7013d41a43d4"}, + {file = "psutil-5.9.4-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:6001c809253a29599bc0dfd5179d9f8a5779f9dffea1da0f13c53ee568115e1e"}, + {file = "psutil-5.9.4.tar.gz", hash = "sha256:3d7f9739eb435d4b1338944abe23f49584bde5395f27487d2ee25ad9a8774a62"}, +] py = [ {file = "py-1.11.0-py2.py3-none-any.whl", hash = "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"}, {file = "py-1.11.0.tar.gz", hash = "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719"}, ] +pybind11 = [ + {file = "pybind11-2.6.1-py2.py3-none-any.whl", hash = "sha256:c3691da74b670a4850dec30c1145a0dad53a50eeca78b7e7cdc855b5c98fd32d"}, + {file = "pybind11-2.6.1.tar.gz", hash = "sha256:ab7e60a520fe6ae25eca939191bb2ac416cd58478ce754740238a8bf1af18934"}, +] pycodestyle = [ {file = "pycodestyle-2.7.0-py2.py3-none-any.whl", hash = "sha256:514f76d918fcc0b55c6680472f0a37970994e07bbb80725808c17089be302068"}, {file = "pycodestyle-2.7.0.tar.gz", hash = "sha256:c389c1d06bf7904078ca03399a4816f974a1d590090fecea0c63ec26ebaf1cef"}, @@ -768,6 +1448,14 @@ pytest = [ {file = "pytest-6.2.5-py3-none-any.whl", hash = "sha256:7310f8d27bc79ced999e760ca304d69f6ba6c6649c0b60fb0e04a4a77cacc134"}, {file = "pytest-6.2.5.tar.gz", hash = "sha256:131b36680866a76e6781d13f101efb86cf674ebb9762eb70d3082b6f29889e89"}, ] +python-dateutil = [ + {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, + {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, +] +pytz = [ + {file = "pytz-2022.6-py2.py3-none-any.whl", hash = "sha256:222439474e9c98fced559f1709d89e6c9cbf8d79c794ff3eb9f8800064291427"}, + {file = "pytz-2022.6.tar.gz", hash = "sha256:e89512406b793ca39f5971bc999cc538ce125c0e51c27941bef4568b460095e2"}, +] pyyaml = [ {file = "PyYAML-6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53"}, {file = "PyYAML-6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c"}, @@ -814,10 +1502,68 @@ requests = [ {file = "requests-2.25.1-py2.py3-none-any.whl", hash = "sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e"}, {file = "requests-2.25.1.tar.gz", hash = "sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804"}, ] +scikit-learn = [ + {file = "scikit-learn-1.2.0.tar.gz", hash = "sha256:680b65b3caee469541385d2ca5b03ff70408f6c618c583948312f0d2125df680"}, + {file = "scikit_learn-1.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1beaa631434d1f17a20b1eef5d842e58c195875d2bc11901a1a70b5fe544745b"}, + {file = "scikit_learn-1.2.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:d395730f26d8fc752321f1953ddf72647c892d8bed74fad4d7c816ec9b602dfa"}, + {file = "scikit_learn-1.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fd3480c982b9e616b9f76ad8587804d3f4e91b4e2a6752e7dafb8a2e1f541098"}, + {file = "scikit_learn-1.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:184a42842a4e698ffa4d849b6019de50a77a0aa24d26afa28fa49c9190bb144b"}, + {file = "scikit_learn-1.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:867023a044fdfe59e5014a7fec7a3086a8928f10b5dce9382eedf4135f6709a2"}, + {file = "scikit_learn-1.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5546a8894a0616e92489ef995b39a0715829f3df96e801bb55cbf196be0d9649"}, + {file = "scikit_learn-1.2.0-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:bc7073e025b62c1067cbfb76e69d08650c6b9d7a0e7afdfa20cb92d4afe516f6"}, + {file = "scikit_learn-1.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fc0a72237f0c56780cf550df87201a702d3bdcbbb23c6ef7d54c19326fa23f19"}, + {file = "scikit_learn-1.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e1ea0bc1706da45589bcf2490cde6276490a1b88f9af208dbb396fdc3a0babf"}, + {file = "scikit_learn-1.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:f17420a8e3f40129aeb7e0f5ee35822d6178617007bb8f69521a2cefc20d5f00"}, + {file = "scikit_learn-1.2.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:25ba705ee1600ffc5df1dccd8fae129d7c6836e44ffcbb52d78536c9eaf8fcf9"}, + {file = "scikit_learn-1.2.0-cp38-cp38-macosx_12_0_arm64.whl", hash = "sha256:6b63ca2b0643d30fbf9d25d93017ed3fb8351f31175d82d104bfec60cba7bb87"}, + {file = "scikit_learn-1.2.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:83c772fa8c64776ad769fd764752c8452844307adcf10dee3adcc43988260f21"}, + {file = "scikit_learn-1.2.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0834e4cec2a2e0d8978f39cb8fe1cad3be6c27a47927e1774bf5737ea65ec228"}, + {file = "scikit_learn-1.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:da29d2e379c396a63af5ed4b671ad2005cd690ac373a23bee5a0f66504e05272"}, + {file = "scikit_learn-1.2.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:23a88883ca60c571a06278e4726b3b51b3709cfa4c93cacbf5568b22ba960899"}, + {file = "scikit_learn-1.2.0-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:40f3ff68c505cb9d1f3693397c73991875d609da905087e00e7b4477645ec67b"}, + {file = "scikit_learn-1.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e9535e867281ae6987bb80620ba14cf1649e936bfe45f48727b978b7a2dbe835"}, + {file = "scikit_learn-1.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:de897720173b26842e21bed54362f5294e282422116b61cd931d4f5d870b9855"}, + {file = "scikit_learn-1.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:ceb0008f345188aa236e49c973dc160b9ed504a3abd7b321a0ecabcb669be0bd"}, +] +scipy = [ + {file = "scipy-1.9.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1884b66a54887e21addf9c16fb588720a8309a57b2e258ae1c7986d4444d3bc0"}, + {file = "scipy-1.9.3-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:83b89e9586c62e787f5012e8475fbb12185bafb996a03257e9675cd73d3736dd"}, + {file = "scipy-1.9.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a72d885fa44247f92743fc20732ae55564ff2a519e8302fb7e18717c5355a8b"}, + {file = "scipy-1.9.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d01e1dd7b15bd2449c8bfc6b7cc67d630700ed655654f0dfcf121600bad205c9"}, + {file = "scipy-1.9.3-cp310-cp310-win_amd64.whl", hash = "sha256:68239b6aa6f9c593da8be1509a05cb7f9efe98b80f43a5861cd24c7557e98523"}, + {file = "scipy-1.9.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b41bc822679ad1c9a5f023bc93f6d0543129ca0f37c1ce294dd9d386f0a21096"}, + {file = "scipy-1.9.3-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:90453d2b93ea82a9f434e4e1cba043e779ff67b92f7a0e85d05d286a3625df3c"}, + {file = "scipy-1.9.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:83c06e62a390a9167da60bedd4575a14c1f58ca9dfde59830fc42e5197283dab"}, + {file = "scipy-1.9.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:abaf921531b5aeaafced90157db505e10345e45038c39e5d9b6c7922d68085cb"}, + {file = "scipy-1.9.3-cp311-cp311-win_amd64.whl", hash = "sha256:06d2e1b4c491dc7d8eacea139a1b0b295f74e1a1a0f704c375028f8320d16e31"}, + {file = "scipy-1.9.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:5a04cd7d0d3eff6ea4719371cbc44df31411862b9646db617c99718ff68d4840"}, + {file = "scipy-1.9.3-cp38-cp38-macosx_12_0_arm64.whl", hash = "sha256:545c83ffb518094d8c9d83cce216c0c32f8c04aaf28b92cc8283eda0685162d5"}, + {file = "scipy-1.9.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0d54222d7a3ba6022fdf5773931b5d7c56efe41ede7f7128c7b1637700409108"}, + {file = "scipy-1.9.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cff3a5295234037e39500d35316a4c5794739433528310e117b8a9a0c76d20fc"}, + {file = "scipy-1.9.3-cp38-cp38-win_amd64.whl", hash = "sha256:2318bef588acc7a574f5bfdff9c172d0b1bf2c8143d9582e05f878e580a3781e"}, + {file = "scipy-1.9.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d644a64e174c16cb4b2e41dfea6af722053e83d066da7343f333a54dae9bc31c"}, + {file = "scipy-1.9.3-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:da8245491d73ed0a994ed9c2e380fd058ce2fa8a18da204681f2fe1f57f98f95"}, + {file = "scipy-1.9.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4db5b30849606a95dcf519763dd3ab6fe9bd91df49eba517359e450a7d80ce2e"}, + {file = "scipy-1.9.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c68db6b290cbd4049012990d7fe71a2abd9ffbe82c0056ebe0f01df8be5436b0"}, + {file = "scipy-1.9.3-cp39-cp39-win_amd64.whl", hash = "sha256:5b88e6d91ad9d59478fafe92a7c757d00c59e3bdc3331be8ada76a4f8d683f58"}, + {file = "scipy-1.9.3.tar.gz", hash = "sha256:fbc5c05c85c1a02be77b1ff591087c83bc44579c6d2bd9fb798bb64ea5e1a027"}, +] +seaborn = [ + {file = "seaborn-0.12.1-py3-none-any.whl", hash = "sha256:a9eb39cba095fcb1e4c89a7fab1c57137d70a715a7f2eefcd41c9913c4d4ed65"}, + {file = "seaborn-0.12.1.tar.gz", hash = "sha256:bb1eb1d51d3097368c187c3ef089c0288ec1fe8aa1c69fb324c68aa1d02df4c1"}, +] setuptools = [ {file = "setuptools-65.5.1-py3-none-any.whl", hash = "sha256:d0b9a8433464d5800cbe05094acf5c6d52a91bfac9b52bcfc4d41382be5d5d31"}, {file = "setuptools-65.5.1.tar.gz", hash = "sha256:e197a19aa8ec9722928f2206f8de752def0e4c9fc6953527360d1c36d94ddb2f"}, ] +setuptools-scm = [ + {file = "setuptools_scm-7.0.5-py3-none-any.whl", hash = "sha256:7930f720905e03ccd1e1d821db521bff7ec2ac9cf0ceb6552dd73d24a45d3b02"}, + {file = "setuptools_scm-7.0.5.tar.gz", hash = "sha256:031e13af771d6f892b941adb6ea04545bbf91ebc5ce68c78aaf3fff6e1fb4844"}, +] +six = [ + {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, + {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, +] smmap = [ {file = "smmap-5.0.0-py3-none-any.whl", hash = "sha256:2aba19d6a040e78d8b09de5c57e96207b09ed71d8e55ce0959eeee6c8e190d94"}, {file = "smmap-5.0.0.tar.gz", hash = "sha256:c840e62059cd3be204b0c9c9f74be2c09d5648eddd4580d9314c3ecde0b30936"}, @@ -830,10 +1576,18 @@ stevedore = [ {file = "stevedore-4.1.1-py3-none-any.whl", hash = "sha256:aa6436565c069b2946fe4ebff07f5041e0c8bf18c7376dd29edf80cf7d524e4e"}, {file = "stevedore-4.1.1.tar.gz", hash = "sha256:7f8aeb6e3f90f96832c301bff21a7eb5eefbe894c88c506483d355565d88cc1a"}, ] +threadpoolctl = [ + {file = "threadpoolctl-3.1.0-py3-none-any.whl", hash = "sha256:8b99adda265feb6773280df41eece7b2e6561b772d21ffd52e372f999024907b"}, + {file = "threadpoolctl-3.1.0.tar.gz", hash = "sha256:a335baacfaa4400ae1f0d8e3a58d6674d2f8828e3716bb2802c44955ad391380"}, +] toml = [ {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, ] +tomli = [ + {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, + {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, +] typed-ast = [ {file = "typed_ast-1.4.3-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:2068531575a125b87a41802130fa7e29f26c09a2833fea68d9a40cf33902eba6"}, {file = "typed_ast-1.4.3-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:c907f561b1e83e93fad565bac5ba9c22d96a54e7ea0267c708bffe863cbe4075"}, diff --git a/pyproject.toml b/pyproject.toml index 82c2a0c7..7de1e1d0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -26,6 +26,11 @@ uvloop = "^0.15.2" uvicorn = "^0.14.0" orjson = "^3.7.7" starlette = "^0.14.2" +seaborn = "^0.12.1" +lightfm = "1.16" +hnswlib = "0.6.2" +pybind11 = "2.6.1" +nmslib = "^2.1.1" [tool.poetry.dev-dependencies] pytest = "^6.2.4" diff --git a/service/api/models_zoo.py b/service/api/models_zoo.py index 32a3c867..35aa87a9 100644 --- a/service/api/models_zoo.py +++ b/service/api/models_zoo.py @@ -1,11 +1,28 @@ -from abc import ABC -from typing import List +from abc import ABC, abstractmethod +from collections import defaultdict +from functools import reduce +from typing import Dict, List, Optional, Set, Tuple + +import dill +import numpy as np +import pandas as pd +import scipy as sp +from implicit.nearest_neighbours import ItemItemRecommender +from lightfm import LightFM +from scipy.sparse import csr_matrix class BaseModelZoo(ABC): def __init__(self): pass + @staticmethod + def unique_reco(items: List[int]) -> List[int]: + seen: Set[int] = set() + seen_add = seen.add + return [item for item in items if not (item in seen or seen_add(item))] + + @abstractmethod def reco_predict( self, user_id: int, @@ -33,3 +50,514 @@ def reco_predict( """ reco = list(range(k_recs)) return reco + + +class TopPopularAllCovered(BaseModelZoo): + def __init__( + self, + top_reco: Tuple[int, ...] = tuple([ + 10440, 15297, 9728, 13865, 2657, + 4151, 3734, 6809, 4740, 4880, 7571, + 11237, 8636, 14741 + ]) + ) -> None: + super().__init__() + self.top_reco = top_reco + + def reco_predict( + self, + user_id: int, + k_recs: int + ) -> List[int]: + """ + Main function for recommendation items to users + :param user_id: user identification + :param k_recs: how many recs do you need + :return: list of recommendation ids + """ + reco = list(self.top_reco)[:k_recs] + return reco + + +class Popular(BaseModelZoo): + def __init__( + self, + top_reco: Tuple[int, ...] = tuple([ + 10440, 15297, 9728, 13865, 4151, + 3734, 2657, 4880, 142, 6809 + ]) + ) -> None: + super().__init__() + self.top_reco = top_reco + + def reco_predict( + self, + user_id: int, + k_recs: int + ) -> List[int]: + """ + Main function for recommendation items to users + :param user_id: user identification + :param k_recs: how many recs do you need + :return: list of recommendation ids + """ + reco = list(self.top_reco)[:k_recs] + return reco + + +class KNNModelWithTop(BaseModelZoo): + def __init__( + self, + path_to_reco: str = "data/BlendingKNNWithAddFeatures.csv.gz", + top_reco: Tuple[int, ...] = tuple([ + 10440, 15297, 9728, 13865, 3734, + 12192, 4151, 11863, 7793, 7829 + ]), + ) -> None: + super().__init__() + self.path_to_reco = path_to_reco + if self.path_to_reco.endswith('csv.gz'): + self.data = pd.read_csv(path_to_reco, compression='gzip') + elif self.path_to_reco.endswith('.csv'): + self.data = pd.read_csv(path_to_reco) + self.top_reco = top_reco + + def reco_predict( + self, + user_id: int, + k_recs: int + ) -> List[int]: + """ + Main function for recommendation items to users + :param user_id: user identification + :param k_recs: how many recs do you need + :return: list of recommendation ids + """ + reco = ( + self.data[self.data.user_id == user_id] + .item_id + .tolist() + [:k_recs] + ) + + if len(reco) < k_recs: + reco.extend(self.top_reco) + reco = self.unique_reco(reco)[:k_recs] # Удаляем дубли + + return reco + + +class OnlineModel(BaseModelZoo): + def __init__( + self, + path_to_model: str = "data/knn_bm25.pickle", + top_reco: Tuple[int, ...] = tuple([ + 10440, 15297, 9728, 13865, 3734, + 12192, 4151, 11863, 7793, 7829 + ]) + ) -> None: + super().__init__() + + with open(path_to_model, 'rb') as f: + self.model = dill.load(f) + + self.top_reco = top_reco + + def reco_predict( + self, + user_id: int, + k_recs: int + ) -> List[int]: + """ + Main function for recommendation items to users + :param user_id: user identification + :param k_recs: how many recs do you need + :return: list of recommendation ids + """ + try: + reco = self.model.predict(user_id=user_id) + except KeyError: + reco = [] + + if len(reco) < k_recs: + reco.extend(self.top_reco) + reco = self.unique_reco(reco)[:k_recs] # Удаляем дубли + + return reco + + +class UserKNN: + """ + Class for fit-perdict UserKNN model and BM25 + based on ItemKNN model from implicit.nearest_neighbours + """ + + def __init__( + self, + dist_model: ItemItemRecommender, + n_neighbors: int = 50, + verbose: int = 1, + ): + self.n_neighbors = n_neighbors + self.dist_model = dist_model + self.verbose = verbose + self.is_fitted = False + + self.mapping: Dict[str, Dict[int, int]] = defaultdict(dict) + + self.weights_matrix = None + self.users_watched = None + + def get_mappings(self, train): + self.mapping['users_inv_mapping'] = dict( + enumerate(train['user_id'].unique()) + ) + self.mapping['users_mapping'] = { + v: k for k, v in self.mapping['users_inv_mapping'].items() + } + + self.mapping['items_inv_mapping'] = dict( + enumerate(train['item_id'].unique()) + ) + self.mapping['items_mapping'] = { + v: k for k, v in self.mapping['items_inv_mapping'].items() + } + + def get_matrix( + self, df: pd.DataFrame, + user_col: str = 'user_id', + item_col: str = 'item_id', + weight_col: str = None, + ): + if weight_col: + weights = df[weight_col].astype(np.float32) + else: + weights = np.ones(len(df), dtype=np.float32) + + if hasattr(self.mapping['users_mapping'], 'get') and \ + hasattr(self.mapping['items_mapping'], 'get'): + interaction_matrix = sp.sparse.coo_matrix(( + weights, + ( + df[user_col].map(self.mapping['users_mapping'].get), + df[item_col].map(self.mapping['items_mapping'].get) + ) + )) + else: + raise AttributeError + + self.users_watched = df.groupby(user_col).agg({item_col: list}) + return interaction_matrix + + def fit(self, train: pd.DataFrame): + self.get_mappings(train) + self.weights_matrix = self.get_matrix(train).tocsr().T + + self.dist_model.fit( + self.weights_matrix, + show_progress=(self.verbose > 0) + ) + self.is_fitted = True + + @staticmethod + def _generate_recs_mapper( + model: ItemItemRecommender, + user_mapping: Dict[int, int], + user_inv_mapping: Dict[int, int], + n_neighbors: int + ): + def _recs_mapper(user): + user_id = user_mapping[user] + recs = model.similar_items(user_id, N=n_neighbors) + return ( + [user_inv_mapping[user] for user, _ in zip(*recs)], + [sim for _, sim in zip(*recs)] + ) + + return _recs_mapper + + def predict(self, user_id: int, n_recs: int = 10): + + if not self.is_fitted: + raise ValueError("Fit model before predicting") + + mapper = self._generate_recs_mapper( + model=self.dist_model, + user_mapping=self.mapping['users_mapping'], + user_inv_mapping=self.mapping['users_inv_mapping'], + n_neighbors=self.n_neighbors + ) + + recs = pd.DataFrame({'user_id': [user_id]}) + + try: + recs['sim_user_id'], recs['sim'] = zip( + *recs['user_id'].map(mapper) + ) + except AttributeError: + return [] + + recs = recs.set_index('user_id').apply(pd.Series.explode).reset_index() + + recs = ( + recs + .merge( + self.users_watched, + left_on=['sim_user_id'], + right_on=['user_id'], how='left' + ) + .explode('item_id') + .sort_values(['user_id', 'sim'], ascending=False) + .drop_duplicates(['user_id', 'item_id'], keep='first') + ) + + recs['rank'] = recs.groupby('user_id').cumcount() + 1 + + result = recs[recs['rank'] <= n_recs][['user_id', 'item_id', 'rank']] + + return result.item_id.tolist()[:n_recs] + + +class LightFMWrapper: + """ + Class for fit-predict LightFM + """ + def __init__( + self, + random_state: int = 42, + learning_rate: float = 0.05, + no_components: int = 10, + item_alpha: float = 0, + user_alpha: float = 0, + loss: str = 'warp', + ): + + self.is_fitted = False + + self.mapping: Dict[str, Dict[int, int]] = defaultdict(dict) + + self.weights_matrix = None + self.users_watched = None + + self.user_features = None + self.item_features = None + + self.model = LightFM( + loss=loss, + no_components=no_components, + user_alpha=user_alpha, + item_alpha=item_alpha, + random_state=random_state, + learning_rate=learning_rate, + ) + + def get_mappings(self, users, items): + self.mapping['users_inv_mapping'] = dict( + enumerate(users['user_id'].unique()) + ) + self.mapping['users_mapping'] = dict({ + v: k for k, v in self.mapping['users_inv_mapping'].items() + }) + + self.mapping['items_inv_mapping'] = dict( + enumerate(items['item_id'].unique()) + ) + self.mapping['items_mapping'] = dict({ + v: k for k, v in self.mapping['items_inv_mapping'].items() + }) + + def get_matrix( + self, df: pd.DataFrame, + user_col: str = 'user_id', + item_col: str = 'item_id', + weight_col: str = None, + ): + if weight_col: + weights = df[weight_col].astype(np.float32) + else: + weights = np.ones(len(df), dtype=np.float32) + + if hasattr(self.mapping['users_mapping'], 'get') and \ + hasattr(self.mapping['items_mapping'], 'get'): + interaction_matrix = sp.sparse.coo_matrix(( + weights, + ( + df[user_col].map(self.mapping['users_mapping'].get), + df[item_col].map(self.mapping['items_mapping'].get) + ) + )) + else: + raise AttributeError + + self.users_watched = df.groupby(user_col).agg({item_col: list}) + return interaction_matrix + + def prepare_additional_features_users(self, features: pd.DataFrame): + user_features_frames = [] + for feature in ["sex", "age", "income"]: + feature_frame = features.reindex(columns=['user_id', feature]) + feature_frame.columns = ["id", "value"] + feature_frame["feature"] = feature + user_features_frames.append(feature_frame) + user_features = pd.concat(user_features_frames) + + user_final_features = pd.get_dummies( + user_features[['id', 'value']]).groupby('id', as_index=False).sum() + + user_final_features.id = user_final_features.id.map( + self.mapping['items_mapping'] + ) + user_final_features = user_final_features.sort_values('id').drop( + 'id', + axis=1 + ) + user_final_features = csr_matrix(user_final_features.values) + + return user_final_features + + def prepare_additional_features_items(self, features: pd.DataFrame): + features.fillna('Unknown', inplace=True) + features["genre"] = features["genres"].str.lower().str.replace( + ", ", + ",", + regex=False + ).str.split(",") + features["actors"] = features["actors"].str.lower().str.replace( + ", ", + ",", + regex=False + ).str.split(",") + + genre_feature = features[["item_id", "genre"]].explode("genre") + genre_feature.columns = ["id", "value"] + genre_feature["feature"] = "genre" + + actors_feature = features[["item_id", "actors"]].explode("actors") + actors_feature.columns = ["id", "value"] + actors_feature["feature"] = "actors" + + content_feature = features.reindex(columns=['item_id', "content_type"]) + content_feature.columns = ["id", "value"] + content_feature["feature"] = "content_type" + + country_feature = features.reindex(columns=['item_id', "countries"]) + country_feature.columns = ["id", "value"] + country_feature["feature"] = "countries" + + age_feature = features.reindex(columns=['item_id', "age_rating"]) + age_feature.columns = ["id", "value"] + age_feature["feature"] = "age_feature" + + studios_feature = features.reindex(columns=['item_id', "studios"]) + studios_feature.columns = ["id", "value"] + studios_feature["feature"] = "studios" + + genre_feature_bin = ( + pd.get_dummies(genre_feature[['id', 'value']]) + .groupby('id', as_index=False) + .sum() + ) + content_feature_bin = ( + pd.get_dummies(content_feature[['id', 'value']]) + .groupby('id', as_index=False) + .sum() + ) + studios_feature_bin = ( + pd.get_dummies(studios_feature[['id', 'value']]) + .groupby('id', as_index=False) + .sum() + ) + age_feature_bin = ( + pd.get_dummies(age_feature[['id', 'value']]) + .groupby('id', as_index=False) + .sum() + ) + country_feature_bin = ( + pd.get_dummies(country_feature[['id', 'value']]) + .groupby('id', as_index=False) + .sum() + ) + + dfs = [ + genre_feature_bin, + content_feature_bin, + studios_feature_bin, + age_feature_bin, + country_feature_bin + ] + item_final_features = reduce( + lambda left, right: pd.merge(left, right, on='id'), + dfs + ) + + item_final_features.id = item_final_features.id.map( + self.mapping['items_mapping'] + ) + item_final_features = ( + item_final_features + .sort_values('id') + .drop('id', axis=1) + ) + item_final_features_matrix_sparse = csr_matrix( + item_final_features.values) + + return item_final_features_matrix_sparse + + def fit( + self, + train: pd.DataFrame, + user_features: Optional[pd.DataFrame] = None, + # если не none, то делаем фичи + item_features: Optional[pd.DataFrame] = None, + # если не none, то делаем фичи + epochs: int = 1, + num_threads: int = 8, + verbose: int = 1, + + ): + if user_features is not None: + self.user_features = self.prepare_additional_features_users( + user_features) + + if item_features is not None: + self.item_features = self.prepare_additional_features_items( + item_features) + + self.get_mappings(user_features, item_features) + self.weights_matrix = self.get_matrix(train).tocsr() + + self.model.fit( + self.weights_matrix, + epochs=epochs, + user_features=self.user_features, + # csr_matrix of shape [n_users, n_user_features] + item_features=self.item_features, + # csr_matrix of shape [n_items, n_item_features] + num_threads=num_threads, + verbose=verbose > 0, + ) + + self.is_fitted = True + + def predict(self, user_id: int, n_recs: int = 10): + + if not self.is_fitted: + raise ValueError("Fit model before predicting") + + if user_id not in self.mapping['users_mapping'].keys(): + return [] + user_id = self.mapping['users_mapping'][user_id] + + scores = self.model.predict( + user_id, + np.arange(len(self.mapping['items_mapping'])), + item_features=self.item_features, + user_features=self.user_features + ) # LightFM + top_items = np.argsort(-scores)[:n_recs] + reco = [ + self.mapping['items_inv_mapping'][inv_reco_item] + for inv_reco_item in top_items + ] + + return reco diff --git a/service/api/views.py b/service/api/views.py index 1124fe1a..9603b00d 100644 --- a/service/api/views.py +++ b/service/api/views.py @@ -11,7 +11,7 @@ from .config import config_env from .models import NotFoundError, RecoResponse, UnauthorizedError -from .models_zoo import DumpModel +from .models_zoo import DumpModel, OnlineModel router = APIRouter() @@ -19,7 +19,15 @@ api_header = APIKeyHeader(name=config_env["API_KEY_NAME"], auto_error=False) token_bearer = HTTPBearer(auto_error=False) -models_zoo = {"model_1": DumpModel()} +try: + models_zoo = { + "model_1": DumpModel(), + "LightFM": OnlineModel(path_to_model='./data/lightfm.pickle') + } +except FileNotFoundError: + models_zoo = { + "model_1": DumpModel(), + } async def get_api_key(