{ "cells": [ { "cell_type": "markdown", "id": "f437fde0-0d08-4cca-b29c-d942cf3ea4de", "metadata": {}, "source": [ "# Singular Value Decomposition" ] }, { "cell_type": "markdown", "id": "a5ed5710-3d99-4b7a-970d-4275ec8afa60", "metadata": {}, "source": [ "Singular Value Decomposition is explored on details here.\n", "\n", "- Machine Learning Exploration : Singular Value Decomposition\n", "\n", " https://machinelearningexploration.readthedocs.io/en/latest/MathExploration/SingularValueDecomposition.html" ] }, { "cell_type": "code", "execution_count": 1, "id": "2f0f30fc-bfaa-4f49-bc67-ad023779506b", "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", "import pandas as pd \n", "import matplotlib.pyplot as plt" ] }, { "cell_type": "code", "execution_count": 2, "id": "f2dfb133-27cf-4486-8352-070accdc1b78", "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", "
userIdmovieIdratingtimestamp
0114.0964982703
1134.0964981247
2164.0964982224
31475.0964983815
41505.0964982931
\n", "
" ], "text/plain": [ " userId movieId rating timestamp\n", "0 1 1 4.0 964982703\n", "1 1 3 4.0 964981247\n", "2 1 6 4.0 964982224\n", "3 1 47 5.0 964983815\n", "4 1 50 5.0 964982931" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "ratings = pd.read_csv('/opt/datasetsRepo/RecommendationData/ratings.csv')\n", "ratings.head()" ] }, { "cell_type": "code", "execution_count": 243, "id": "39cf0491-f66b-47ae-a717-c01572522caa", "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", "
movieIdtitlegenres
01Toy Story (1995)Adventure|Animation|Children|Comedy|Fantasy
12Jumanji (1995)Adventure|Children|Fantasy
23Grumpier Old Men (1995)Comedy|Romance
34Waiting to Exhale (1995)Comedy|Drama|Romance
45Father of the Bride Part II (1995)Comedy
\n", "
" ], "text/plain": [ " movieId title \\\n", "0 1 Toy Story (1995) \n", "1 2 Jumanji (1995) \n", "2 3 Grumpier Old Men (1995) \n", "3 4 Waiting to Exhale (1995) \n", "4 5 Father of the Bride Part II (1995) \n", "\n", " genres \n", "0 Adventure|Animation|Children|Comedy|Fantasy \n", "1 Adventure|Children|Fantasy \n", "2 Comedy|Romance \n", "3 Comedy|Drama|Romance \n", "4 Comedy " ] }, "execution_count": 243, "metadata": {}, "output_type": "execute_result" } ], "source": [ "movies = pd.read_csv('/opt/datasetsRepo/RecommendationData/movies.csv')\n", "movies.head(5)" ] }, { "cell_type": "code", "execution_count": 3, "id": "35dfb277-c707-4258-be37-f4b7d2cdcb3d", "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", "
userIdmovieIdratingtimestampuser_idxmovie_idx
0114.096498270300
1134.096498124701
2164.096498222402
31475.096498381503
41505.096498293104
\n", "
" ], "text/plain": [ " userId movieId rating timestamp user_idx movie_idx\n", "0 1 1 4.0 964982703 0 0\n", "1 1 3 4.0 964981247 0 1\n", "2 1 6 4.0 964982224 0 2\n", "3 1 47 5.0 964983815 0 3\n", "4 1 50 5.0 964982931 0 4" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "idx_to_userid_mapper = dict(enumerate(ratings.userId.unique()))\n", "userid_to_idx_mapper = dict(zip(idx_to_userid_mapper.values(), idx_to_userid_mapper.keys()))\n", "\n", "idx_to_movieid_mapper = dict(enumerate(ratings.movieId.unique()))\n", "movieid_to_idx_mapper = dict(zip(idx_to_movieid_mapper.values(), idx_to_movieid_mapper.keys()))\n", "\n", "ratings['user_idx'] = ratings['userId'].map(userid_to_idx_mapper).apply(np.int32)\n", "ratings['movie_idx'] = ratings['movieId'].map(movieid_to_idx_mapper).apply(np.int32)\n", "ratings.head(5)" ] }, { "cell_type": "code", "execution_count": 251, "id": "898fafc7-34b2-4227-a780-345edc58014f", "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", "
movieIdtitlegenresmovie_idx
01Toy Story (1995)Adventure|Animation|Children|Comedy|Fantasy0.0
12Jumanji (1995)Adventure|Children|Fantasy481.0
23Grumpier Old Men (1995)Comedy|Romance1.0
34Waiting to Exhale (1995)Comedy|Drama|Romance482.0
45Father of the Bride Part II (1995)Comedy483.0
\n", "
" ], "text/plain": [ " movieId title \\\n", "0 1 Toy Story (1995) \n", "1 2 Jumanji (1995) \n", "2 3 Grumpier Old Men (1995) \n", "3 4 Waiting to Exhale (1995) \n", "4 5 Father of the Bride Part II (1995) \n", "\n", " genres movie_idx \n", "0 Adventure|Animation|Children|Comedy|Fantasy 0.0 \n", "1 Adventure|Children|Fantasy 481.0 \n", "2 Comedy|Romance 1.0 \n", "3 Comedy|Drama|Romance 482.0 \n", "4 Comedy 483.0 " ] }, "execution_count": 251, "metadata": {}, "output_type": "execute_result" } ], "source": [ "movies['movie_idx'] = movies['movieId'].map(movieid_to_idx_mapper).dropna()\n", "movies.head(5)" ] }, { "cell_type": "markdown", "id": "79e814a6-ca21-4925-8ed7-ae225bde88da", "metadata": {}, "source": [ "non mapped movies. i.e. non rated movie by any user." ] }, { "cell_type": "code", "execution_count": 474, "id": "62766bfa-a6fd-43a8-9fe9-5ad4d6afcfb7", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(18, 4)" ] }, "execution_count": 474, "metadata": {}, "output_type": "execute_result" } ], "source": [ "movies[movies.movie_idx.isna()].shape" ] }, { "cell_type": "markdown", "id": "6b709007-eaa4-4e37-9347-e2a380f53fdd", "metadata": {}, "source": [ "## User Movie Matrix" ] }, { "cell_type": "code", "execution_count": 32, "id": "fdba0bd0-bfe9-47bf-b158-9caa03088271", "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", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
rating
movie_idx0123456789...9714971597169717971897199720972197229723
user_idx
04.04.04.05.05.03.05.04.05.05.0...NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
1NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN...NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
2NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN...NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
3NaNNaNNaN2.0NaNNaNNaNNaNNaNNaN...NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
44.0NaNNaNNaN4.0NaNNaN4.0NaNNaN...NaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
\n", "

5 rows × 9724 columns

\n", "
" ], "text/plain": [ " rating ... \\\n", "movie_idx 0 1 2 3 4 5 6 7 8 9 ... 9714 9715 \n", "user_idx ... \n", "0 4.0 4.0 4.0 5.0 5.0 3.0 5.0 4.0 5.0 5.0 ... NaN NaN \n", "1 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN \n", "2 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN \n", "3 NaN NaN NaN 2.0 NaN NaN NaN NaN NaN NaN ... NaN NaN \n", "4 4.0 NaN NaN NaN 4.0 NaN NaN 4.0 NaN NaN ... NaN NaN \n", "\n", " \n", "movie_idx 9716 9717 9718 9719 9720 9721 9722 9723 \n", "user_idx \n", "0 NaN NaN NaN NaN NaN NaN NaN NaN \n", "1 NaN NaN NaN NaN NaN NaN NaN NaN \n", "2 NaN NaN NaN NaN NaN NaN NaN NaN \n", "3 NaN NaN NaN NaN NaN NaN NaN NaN \n", "4 NaN NaN NaN NaN NaN NaN NaN NaN \n", "\n", "[5 rows x 9724 columns]" ] }, "execution_count": 32, "metadata": {}, "output_type": "execute_result" } ], "source": [ "user_movie_matrix = ratings.pivot_table(values=['rating'] ,index=['user_idx'], columns=['movie_idx'])\n", "user_movie_matrix.head(5)" ] }, { "cell_type": "code", "execution_count": 34, "id": "4b5c9141-67b1-44ed-8432-11b64905470f", "metadata": {}, "outputs": [], "source": [ "X = user_movie_matrix.fillna(0).values" ] }, { "cell_type": "markdown", "id": "1d85079b-bd3b-4556-b4b3-995ab5d5361c", "metadata": {}, "source": [ "## Mask for NaN values" ] }, { "cell_type": "code", "execution_count": 441, "id": "818d8bd8-c461-4ce9-8c37-91e26439225b", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[ True, True, True, ..., False, False, False],\n", " [False, False, False, ..., False, False, False],\n", " [False, False, False, ..., False, False, False],\n", " ...,\n", " [ True, True, False, ..., False, False, False],\n", " [ True, False, False, ..., False, False, False],\n", " [ True, False, True, ..., True, True, True]])" ] }, "execution_count": 441, "metadata": {}, "output_type": "execute_result" } ], "source": [ "M = ~np.isnan(user_movie_matrix.values)\n", "M" ] }, { "cell_type": "code", "execution_count": 35, "id": "c9db1e0d-99fd-43c6-ac15-6ad24a145aa7", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(610, 9724)" ] }, "execution_count": 35, "metadata": {}, "output_type": "execute_result" } ], "source": [ "X.shape" ] }, { "cell_type": "markdown", "id": "f8ff212a-4359-44f7-9a05-e2538220836e", "metadata": {}, "source": [ "## SVD Calculation" ] }, { "cell_type": "code", "execution_count": 36, "id": "f0ef7866-82ef-4c84-9134-8fd8721646a9", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "((610, 610), (610,), (610, 9724))" ] }, "execution_count": 36, "metadata": {}, "output_type": "execute_result" } ], "source": [ "U, S, VT = np.linalg.svd(X, full_matrices=False)\n", "U.shape, S.shape, VT.shape" ] }, { "cell_type": "markdown", "id": "004780f7-5027-4214-bcab-f101bc28b2b6", "metadata": {}, "source": [ "## Eigen values plot" ] }, { "cell_type": "code", "execution_count": 435, "id": "57186962-78d7-4143-b837-86c832d653d0", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([ 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100])" ] }, "execution_count": 435, "metadata": {}, "output_type": "execute_result" } ], "source": [ "deciles = (np.linspace(0,1,11)*100).astype('int')\n", "deciles" ] }, { "cell_type": "code", "execution_count": 436, "id": "efa87136-1322-4774-a981-5cbe73d00bdd", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([ 1, 61, 122, 183, 244, 305, 366, 427, 488, 549, 610])" ] }, "execution_count": 436, "metadata": {}, "output_type": "execute_result" } ], "source": [ "dims = np.linspace(1, len(S), 11).astype('int')\n", "dims" ] }, { "cell_type": "code", "execution_count": 458, "id": "6d559bb6-8425-40b3-b2cc-bd626308521b", "metadata": {}, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAlMAAAEvCAYAAABhSUTPAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/YYfK9AAAACXBIWXMAAAsTAAALEwEAmpwYAACFHElEQVR4nO2de1hU1frHPyuRMLVQ847hFQXl4g21kuwimqZlallqWhKdyrTSsI4/O5XHLC+njscyjdLUTpZlpWmpXRRNFLyBISIqojhKBqKCIgLr98cM+zDMgFwGub2f51mPs9e71nfW7L1nfFlr7fdVWmsEQRAEQRCE0nFDRQ9AEARBEAShKiPOlCAIgiAIQhkQZ0oQBEEQBKEMiDMlCIIgCIJQBsSZEgRBEARBKAPiTAmCIAiCIJQBp4p641tvvVW3bt262O0zMjKoW7duuYxFtEVbtK+P9p49e/7SWjcul8EIgiBUFFrrCindu3fXJeG3334rUXvRFm3RrnzawG5dQb85UqRIkVJeRZb5BEEQBEEQyoA4U4IgCIIgCGVAnClBEARBEIQyIM6UIAiCIAhCGRBnShAEQRAEoQyIMyUIgiAIglAGxJkSBEEQBEEoA9d0ppRSnyql/lRK/VGIXSmlFiiljiilopVS3Rw/TEEQBEEQhMpJcWamlgEDi7DfD3SwlGBgUdmHJQhCZWbatGm4ubkxefJkwsPDK3o4giAIFYrSWl+7kVKtgR+01l3s2BYDW7TWX1iO44B+WuvTRWn26NFD7969u9gDfeCBB2jRooVVXf/+/Rk5ciSZmZlMmjTJps+QIUMYMmQIaWlphISE2NhHjBhBYGAga9as4aeffrKxjxkzhoCAABITE5k1a5aNPSgoCH9/fw4fPsy8efNs7BMnTiQ1NZWGDRuycOFCG/vUqVPx8PAgIiKC0NBQG/v06dNxd3cnLCyMlStX2tgHDhzIww8/zKZNm/j6669t7HPmzMHV1ZV169axbt06G/uCBQtwcXFh9erVbN682cpmMpn44YcfAFixYgXbtm2zsru4uLBgwQIAQkNDiYiIsLK7uroyZ84cABYuXEh0dLSVdteuXZk5cyYA8+fPJy4uzqq/u7s706dPB2DWrFkkJiZa2Tt27MiUKVMAmDFjBsnJyYZ2ixYt8PHxYeLEiQCEhISQlpZm1d/f35+goCAAJk2aRGZmppW9b9++jB07FoDg4GArbXDcvZecnMyMGTOstMEx956Pjw/R0dH8/e9/t/nuFPfemzp1Kp988gmXL18mOzsbgNzcXPL/bjg5OREWFkafPn1sdAqilNqjte5xzYaCIAhVCEfk5msJnMx3nGSps3GmlFLBmGevaNq0KVu2bCnWGzTesoU+SUkU/Ps3JiaGxo0bk5WVhclksul34MAB6tevT3p6ul17VFQULXfsoFFKil37vn37yM3N5cyZM3bte/bs4dKlS5w8edKu/eyiRbjecguRHTrYte/atQuTyURsbKxde3h4OAkJCURFRdnY7zh9mkY33siWhg3t2gG2b99OvXr1OHDggF17WFgYzs7OxMTEWNnvOH0a95wc4/rYG5+zs7Nhj4uLs7FfuHDBsMfHxxv2PO24hg0N+9GjR2365+bmGvaEhATOnDljZXdycjLsiYmJpKamGtrhQJ06dQz7iRMnSE9Pt+ofFxdn2JOSksjKyrKyx8bGGnaTyWSlDY6595ydnUlNTaXNnj1W2lD2ey8yMpLU1FRyvvzS7nensHvvxIkTHDlyhGXLlpGbm0tOTo6Ndh4jLP9+nZ3Np59+ypUrVwptKwiCUK0pTs4ZoDXwRyG2H4A78x3/AvS4lqbk5hNt0a547cWLF2tPT0/dsGFD7eTkpIESFycnJ71jx45ijQXJzSdFipRqWBwxM3UKaJXv2M1S5zgyM7mhwMyBaIu2aJdOe9q0aXz66adcvHixTLNJNwKNb72Vr9auLdYSnyAIQnXFEc7UWmCiUmoV0As4r6+xX6rETJpEe5MJAgMdKivaol1TtKf98guffvop58+f5+rVq6WScnZ2platWjg5OVGnTh3WNmtGq1ataCGOlCAINZxrOlNKqS+AfsCtSqkk4B9AbQCt9UfABmAQcAS4BDxZXoMVBKH4TJs2jc7Ll3MlK4s569eXqG+tWrVwdnbmlltuoXfv3oSEhNjOPgUH292vJQiCUNO4pjOltX7sGnYNPO+wEQmCUGqmTZvG4sWLSU9PJycnh8Ul6Ovs7MxNN91EcHAw7777brmNURAEobrhiGU+QRAqkCVLlvD2229z6tQpI3xBcahduzb16tXD29ubd955R/Y9CYIglBJxpgShChIeHs6rr75KZGQkly9fLna/2rVr06BBA8aPHy+zT4IgCA6iajhTQ4aQcuAALa7dUrRFu1pr5y3jnT9/vljS6wCnWrVo0qiR4x2o8jwngiAIVYiq40zVry/aol0jtZcsWcL777/PsWPHih3KwMnJCTc3N4a89hoeHh5826+fgwabj/I8J4IgCFWI4uTmq3jS0nAqEMFatEW7umtPmzaNevXq8cwzzxAbG1ssR6pZs2YsXryYq1evkpCQQPAjj1TNcyIIglCFqBozUyEhtDWZ4IEHRFu0q7V2aWah6tevz7333ms/fEFVPSeCIAhViKrhTAlCNSfxxAm8GzUiNTW1WO1vvPFG2rVrx+TJk41EzIIgCELFIM6UIFQg06ZNw+PTT8nJyaE4bpSrq6vEgRIEQahkiDMlCNeZvLAGO3fuJCsr65qBNW+66SYCAwPtL+MJgiAIFY44U4JwnchzosLCworVXmahBEEQqgZVw5kaMYKzUVHlE89GtEW7nLXDw8N57rnn2L9/v1371/leOzs707t3b8dFJK+k50QQBKE6UTWcqcBAzjk7i7ZoVyntazlReWzGvKE8ZPJkx89CVbJzIgiCUB2pGs5UcjK1i/mUk2iLdkVrL1myhH/84x+cOXPmmm0bNmzI+6+9Rtu2bbnj4YfLOkpbKsk5EQRBqM5UjaCdM2bQ5tNPRVu0K7X2kiVLaN68Oc8888w1Ham84JopKSmMPXy42p4TQRCEmkDVmJkShEpMeHg448aNIz4+/pptmzVrxptvvimxoQRBEKoRxZqZUkoNVErFKaWOKKVetWN3V0r9opSKVkptUUq5OX6oglC5CA8Pp2vXrtx+++3XdKR8fX3ZsWMHp0+fFkdKEAShmnFNZ0opVQv4ALgf8AIeU0p5FWg2D1iutfYB3gJmO3qgglBZCA8P56677uL222+/5ubyPCdq//79EiNKEAShmlKcmSl/4IjW+pjWOgtYBTxYoI0X8Kvl9W927IJQLRgzZgy33377NWNFBQQEiBMlCIJQQyjOnqmWwMl8x0lArwJtooCHgX8Dw4D6SqlGWusUh4xyzBj+PW0a5wosj/Tv35+RI0eSmZnJpEmTbLoNGTKEIUOGkJaWRkhIiI19xIgRBI4ZQ/zWrbxhZ+llzJgxBAQEkJiYyKxZs2zsQUFB+Pv7c/jwYebNm2djn9anDxcuXOCv6GgWLlxoY586dSoeHh5EREQQGhpqY58+fTru7u6EhYWxcuVKK1uH06fx79WLFsCmTZv4+uuvbfrPmTMHV1dX1q1bx7p162zsCxYswMXFhdWrV7N582Yr7b9SUsh7SH/FihVs27bNqq+LiwsLFiwAIDQ0lIiICCu7q6src+bMAWDhwoVER0dbaTvPmMHMmTMBmD9/PnFxcVb93d3dmT59OgCzZs0iMTHRyt6xY0emTJkCwIwZM0hOTja0zwUH4+Pjw8SJEwEICQkhLS3Nqr+/vz9BQUEATJo0iczMTCt73759GTt2LADBwcFc/eUXEhIS2Kq1zXnMT8OGDbnzzjsJCgqiT58+Rd97gYEkJyezPN+48yjrvTdx4kR8fHw42qcPS5YssfnulOXeA5g5cyZNx4whed8+iTMlCEKNx1Eb0KcCC5VS44Ew4BSQU7CRUioYCAZo2rQpW7ZsKfYbRN1yC04mk1VdTEwMjRs3JisrC1MBG8CBAweoX78+6enpdu1RUVE49+zJydatMe3aZWPft28fubm5nDlzxm7/PXv2cOnSJU6ePGnXviU3l6bt2pEcGWnXvmvXLkwmE7GxsXbt4eHhJCQkEBUVZWM3Ac1at2bLli127QDbt2+nXr16HDhwwK49LCwMZ2dnYmJirOwmIPuWW4zrY298zs7Ohj0uLs7GfuHCBcMeHx9v2PO0myQmGvajR4/a9M/NzTXsCQkJNk/HOTk5GfbExERSU1MNbSeTiTp16hj2EydOkJ6ebtU/Li7OsCclJZGVlWVlj42NZcuWLSxevJivvvqK3Nxcm/OXn5tuugk/Pz8aNGhATk5O8e49Z2dSU1PZqrUx7jzKeu9FRkaSmprK0dxcu9+dstx7AL///jsNGzYkvV07zpfgeywIglAt0VoXWYA+wMZ8x68BrxXRvh6QdC3d7t2762Jz/Lje8cUXxW9fEkRbtO2wePFiXb9+fQ1oQN9mKRQozZo104sXL640467s2sBufY3fBilSpEipaqU4e6YigQ5KqTZKKWdgFLA2fwOl1K1KqTyt1wDHBp+ZNQt3O0sNoi3ajtYODw/Hw8ODZ555hosXLxr10y0lj4YNG7J48WLHPJ1Xyc9JhWgLgiBUIa7pTGmts4GJwEYgFvhKax2jlHpLKTXU0qwfEKeUOgw0BWw3eQhCJSb/E3pFhTnIc6JSUlIkxIEgCIIAFHPPlNZ6A7ChQN3r+V5/jXW+VkGoMkybNs3YLF8YzrVr07FTJ1IsG+kFQRAEIQ+JgC7UWIqTQ69OnTq88MILjD93zu5GbEEQBEEQZ0qokQwYMIBNmzYV2SYwMJCNGzeaD2RJTxAEQSiEqpHoOCiI04MHi7Zol1l7yZIlNGrUqEhHKi8JseFIFVO71Ii2IAhClaZqzEz5+3Px0iXRFu1Saxc3GXFISAjvvvuuraEanpNKrS0IglCFqBrO1OHD1Dl58trtRFu07WiPGTOGzz//vMiuAQEBvPPOO4Wnfqlm56TSawuCIFQhqsYy37x5tPryS9EW7RJp5y3pFeVItW/fnh07drB169aic+hVk3NSZbQFQRCqEFVjZkoQSkhxNpgXuqQnCIIgCCVAnCmhWpF44gTejRqRmppaaBtfX18WLVpU9EyUIAiCIBQTcaaEasOGDRtIOnWKwtyo9u3bs3z5cnGiBEEQBIdSNfZMCUIR5O2NSjp1qtA2ISEhxMfHiyMlCIIgOJyqMTM1cSKnIiNpIdqiXYD8e6MW2rE7bDaqCp2TaqEtCIJQhagazpSPDxlF7IER7ZqnvWTJEl577TWrvVEHCrRx6AbzKnBOqpW2IAhCFaJqLPNFR1P36FHRFm3APBv1zDPP2Gwy97aUvHAHDn1Sr5Kfk2qnLQiCUIWoGs7UwoW0/PZb0a7h2uHh4XTo0KHQkAcTgffati2fvVGV9JxUW21BEIQqRNVY5hNqPNOmTWPOnDmF2tu3b8+DXl7k5ORcx1EJgiAIQlWZmRJqLOHh4XTt2rVIRyrvSb2mTZtex5EJgiAIgpliOVNKqYFKqTil1BGl1Kt27LcppX5TSu1TSkUrpQY5fqhCTWPatGncfvvt7N+/3669XPZGCYIgCEIJueYyn1KqFvAB0B9IAiKVUmu11gfzNfs/4Cut9SKllBewAWhdDuMVagjXSgczevRoVq5ceR1HJAiCIAj2Kc6eKX/giNb6GIBSahXwIJDfmdLAzZbXtwAmRw6SqVM5uWtX+cSzEe1KpR0eHs7IkSM5dY0AnHZno6rpOamR2oIgCFWI4jhTLYGT+Y6TgF4F2rwBbFJKvQDUBe5zyOjy8PBg5ssv02LbNqvq/v37M3LkSDIzM5k0aZJNtyFDhjBkyBDS0tIICQmxsY8YMYLAwEBO/fEHwcHBNvYxY8YQEBBAYmIis2bNsrEHBQXh7+/P4cOHmTdvno194sSJXG7ViujoaBYutA0pOXXqVDw8PIiIiCA0NNTGPn36dNzd3QkLC7M7CzNw4EAANm3axNdff21jnzNnDq6urqxbt45169bZ2BcsWICLiwurV69m8+bNVjaTycQPY8cCsGLFCrYVOPcuLi4sWLAAgNDQUCIiIqzsrq6uxj6nhQsXEh0dbaXd9fBhZs6cCcD8+fOJi4tj165dVu0K0rBhQ+68807OnTvH/PnzmTJlCgAzZswgOTnZ0G6xbRs+Pj5MnDgRMDtfaWlpVlr+/v4EBQUBMGnSJDIzM63sffv2Zazl8+fdG3na4Lh7Lzk5mRnz5llpg2PuPR8fH6IzM5n55Zc2352y3nszZ86kqYcHl02O/btJEAShKuKop/keA5ZprecrpfoAK5RSXbTWufkbKaWCgWCApk2bsmXLlmKJ14+Npe1ff3GsQH1MTAyNGzcmKysLk50f9QMHDlC/fn3S09Pt2qOiomh09Cguycl27fv27SM3N5czZ87Yte/Zs4dLly5x8uRJu/aEL7+kUaNGRN5yi137rl27MJlMxMbG2rWHh4eTkJBAVFSUjd0jLQ2XFi3Y0rChXTvA9u3bqVevHgcOHLBrDwsLw9nZmZiYGCu7R1oabbOzjetjb3zOzs6GPS4uzsZ+4cIFwx4fH2/Y87QTExMN+9GjR/n222/566+/bMYIcOONN+Lh4cFtt91GTk4OJpMJJycno39iYiKpqamG9jGgTp06hv3EiROkp6dbacbFxRn2pKQksrKyrOyxsbGG3WQyWWmDY+49Z2dnUlNTqXfwoJU2lP3ei4yMJDU1lfObN9v97pTl3gP4/fffcU9OxunyZbbYWAVBEGoWSmtddAOzc/SG1nqA5fg1AK317HxtYoCBWuuTluNjQG+t9Z+F6fbo0UPv3r27eKMMDjb/5f7DD8VrXxJEu0K1w8PDeeKJJzhy5Ijd5v7+/uzatatU2g5FtB2irZTao7Xu4fjBCIIgVBzFmZmKBDoopdoAp4BRwOMF2pwA7gWWKaU8ARfgrCMHKlQ/lixZwjPPPFOoXTaZC5WVOnXqnMnMzJRYHDUQFxeX3MzMTAkrVANxcXFJvnz5cjN7tms6U1rrbKXURGAjUAv4VGsdo5R6C9ittV4LTAE+Vkq9hHkz+nh9rSkvoUZTVBBOpRQfffSR3X1sglAZyMzMbCo/cTUTpdQNlfnav/HGG9SrV48LFy4QEBDAffc5dgvztVi7di0HDx7k1VdtoihVeZRShf4BVaw9U1rrDZjDHeSvez3f64PAHaUdoFCz2LVrF3PWr7dra9++PcuXL3d8OhhBEMqF7OxsnJwkmUZl46233qqQ9x06dChDhw6tkPeuSGSqUriufPfdd5wtZKP56NGjyyevniDUUJYvX46Pjw++vr6MHTuW48ePc8899+Dj48O9997LiRMnOH/+PO7u7uTmmp8XysjIoFWrVly9epWjR48ycOBAunfvTt++fTl06BAA48eP529/+xu9evUiJCSEiIgI+vTpQ9euXbn99tuJi4sD4NKlSzzyyCN4eXkxbNgwevXqRd5e2U2bNtGnTx+6devGyJEjbR4SEYrPrFmz8PDw4M477zTO/fjx442nvFu3bs1rr72Gn58fPXr0YO/evQwYMIB27drx0UcfGTpz586lZ8+e+Pj48I9//AOA48eP4+npydNPP03nzp0JDAzk8uXLgPmJcC8vL3x8fBg1ahQAy5YtM56ktne/5Y1t0qRJ3H777bRt29YY5+nTpwkICMDPz48uXbrYPEVeqdFaV0jp3r27LjbHj+sdX3xR/PYlQbSvi/bixYt1gwYN9G2gbzMvBVuV0aNHl/1Nqtg5qYnamLcGVNjvjqOK+aezcvPHH3/oDh066LNnz2qttU5JSdEPPPCAXrZsmdZa608++UQ/+OCDWmuthw4dqn/99VettdarVq3SEyZM0Fprfc899+jDhw9rrbXeuXOnvvvuu7XWWo8bN04PHjxYZ2dna621Pn/+vL569arWWuvNmzfrhx9+WGut9dy5c3VwcLDWWusDBw7oWrVq6cjISH327Fndt29fnZ6errXW+p133tFvvvlmuZ4PR1HZrv3u3bt1ly5ddEZGhj5//rxu166dnjt3rh43bpxevXq11lprd3d3/eGHH2qttX7xxRe1t7e3vnDhgv7zzz91kyZNtNZab9y4UT/99NM6NzdX5+Tk6MGDB+utW7fqhIQEXatWLb1v3z6ttdYjR47UK1as0Fpr3bx5c52Zmam11vrcuXNaa62XLl2qn3/+ea21LvR+GzdunB4xYoTOycnRMTExul27dlprrefNm6f/+c9/aq21zs7O1hcuXCjHM1dyLNfe7m9C1ZibdXfnSkKCaFdR7TFjxvD5558DcK6ArWHDhsyePdsx+6Oq0DkRbaG8+fXXXxk5ciS33nor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DRuM123btrUJKl0eyMxUESxfvtxm0/mDDz4om84FQRAEQTCoGs5U//6c69HjumsXTKGilCrZxsUKGrdoi3aV1xYEQahCVI1lvpEjOWt56uN6aU+bNo2YmBiruhLPSlXAuEVbtKuFdiVHcvPVXCQ3X82lqNx8VePHoDyz09vRthegs8SzUoVoOwzRFu3qrF3JycvNJ6X05f3336dz5854eXnx3nvvWdnyAnKePXvWbt9ly5bRvn172rdvz7Jly4z6VatW4e3tjZeXFyEhIVZ9vvzySzw9PfHy8uKxxx4r9bgzMzMr/NxV95KdnY2fnx+DBw9Ga83PP/9M165d8fX15Y477iA+Ph6tzTle+/Xrh5+fH97e3qxfv96u3o8//oiHhwft2rVj9uzZZbn2pc/NV16lMufmCwgIsMm/FxIS4hBthyHaol0FtZHcfILW+sCBA7pz5846IyNDX716Vd977706Pj5ea631iRMndGBgoL7tttv02bNnbfqmpKToNm3a6JSUFJ2amqrbtGmjU1NT9V9//aVbtWql//zzT6211k888YT++eeftdZaHz58WPv5+enU1FSttdbJycmlHrtc+/KnYH6+Dh066IMHD2qttf7ggw/0uHHjtNZaP/3000auvZiYGO3u7m6jlZ2drdu2bauPHj2qr1y5on18fHRMTEypxkUZc/PVKMLDw0sXoFMQBEEoFrGxsfTq1YubbroJJycn7rrrLtasWQPASy+9xJw5cwpdStu4cSP9+/enYcOGNGjQgP79+/PTTz9x7NgxOnToYAQCve+++4zcfh9//DHPP/88DRo0AKBJkybX4VMKpcFefj6lFBcuXADMsaVatGhRZH1+IiIiaN++PW3btsXZ2ZlRo0bZPKXvCKrGnqnryKuvvmpTJwE6BUEQHEeXLl2YPn06KSkp1KlThw0bNtCjRw++//57WrZsia+vb6F9T506RatWrYzjvHxrAwcOJC4ujuPHj+Pm5sZ3331HlmUZOi+S+h133EFOTg5vvPGGTY43oXKQl5/v4sWLRl1oaCiDBg2iTp063HzzzezcuROAN954g8DAQP7zn/+QkZHBzz//bKNn737ZtWuXw8ctM1P5KGxWSgJ0CoIgOA5PT0+mTZtGYGAgAwcOxM/PjytXrvD2229bBWUsCQ0aNGDRokU8+uij9O3bl9atWxu5/bKzs4mP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QEAAN998s5WmUoq7777bCB/02Wef8eCDDzp87DXOmfr3v/9tdazASJooCIIgXB+GDx+Ol5cXQ4YMscrNZ28flMlkskoHkpGRwebNm3m4wKzot99+i5ubG+Hh4QwePNhIgLx9+3Z8fX3x8/Nj2LBhfPjhh9x6663l+wGFEpOcnMydd96Jr68v/v7+DB48mIEDBxbaPjY2li5dutCxY0d+/PFHq//fBw0aZIR1effdd/nXv/5F+/btSUlJMWZEHUmN2oEXHh5uk4OvWbNmNGjQoIJGJAiCUDMpLDffsmXLbOoK5lqrW7cuKSkpNu0Ky+E2duxYIwivUHlp27atkai6MPLnbOzTpw+HDx+22y7//dK2bVubwNKOpkbNTC1fvtzqWCmFv79/BY1GEARBEITqQNWYmRozhuR9+4z0JqXll19+sTru27cvTadMYZ8DtO3ioHGLtmjXOG1BEIQqRNVwpgICOJ9baEqcYjFt2jTi463DX3l5eTlEu1BEW7RFu1oiuflqLpKbr+ZSVG6+qvFjkJjIjQVys5WE8PBw5s6da1WnlOKJJ54os3aRiLZoi3a1JC83nxTHlyeffJLGjRvTuXNnoy4lJYX77ruP9u3bc99995GamorWmtzcXF544QXatWuHt7c3e/bssau5e/duunTpQrt27XjhhRfIzc0t9fgyMzMr/BxV53Lu3DmGDx9Ox44d6dSpEzt27OCrr77Cy8sLpRSRkZFW7d9++23atWuHh4cHP/30k13NY8eO4e/vT7t27XjkkUe4cuVKaa99oT5T1XCmZs3C3U7m+uKyfPlytLZOTPnKK6+Yg3SWUbtIRFu0RVsQSsT48eP56aefrOreeecd7r33XuLj47n33nuNbBU//vgj8fHxxMfHs2TJEp599lm7ms8++ywff/yx0bagvlB5mDx5MgMHDuTQoUNERUXh6elJly5dWLNmDQEBAVZtDx48yKpVq4iJieGnn37iueeeIycnx0Zz2rRpvPTSSxw5coQGDRrwySefOHzcVcOZKiMFs477+fnx7rvvVsxgBEEQhEIJCAigYcOGVnXff/8948aZE2vkz632/fff88QTT6CUonfv3qSlpXH69GmrvqdPn+bChQv07t3bWJEoj9xsQtk5f/48YWFhRugCZ2dnXF1dC825+P333zNq1ChuvPFG2rRpQ/v27W2e2tP6+uTm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\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "fig, ax = plt.subplots(1, 2, figsize=(10, 5))\n", "\n", "eig_value_coverage = S.cumsum()/S.sum()\n", "coverage = np.round(eig_value_coverage[dims-1]*100, 3)\n", "table = np.c_[coverage, dims]\n", "\n", "ax[0].plot(eig_value_coverage, \".-\", color='k')\n", "ax[0].hlines(deciles/100, xmin=0, xmax=len(S), alpha=0.8, color='k', linestyle='--')\n", "ax[0].vlines(dims, ymin=0, ymax=1, alpha=0.8, color='r', linestyle='--')\n", "\n", "ax[0].set_xticks(dims)\n", "ax[0].set_yticks(deciles/100)\n", "ax[0].grid()\n", "\n", "ax[1].table(cellText=table, colLabels=['coverage', 'dimensions'], loc='center')\n", "ax[1].axis('off')\n", "\n", "plt.show()" ] }, { "cell_type": "markdown", "id": "59624444-c285-4ab2-846d-b966fa847d7e", "metadata": {}, "source": [ "## Low Rank Matrix" ] }, { "cell_type": "code", "execution_count": 443, "id": "d12c312c-ce42-4cd6-824f-a6a9d880f26c", "metadata": {}, "outputs": [], "source": [ "def low_rank_matrix(U, S, VT, rank):\n", " X_tilde = U[:,:rank] @ np.diag(S[:rank]) @ VT[:rank, :]\n", " return X_tilde" ] }, { "cell_type": "markdown", "id": "9c40f56c-3fd2-4f72-a866-61104dc17eae", "metadata": {}, "source": [ "## Loss : RMSE" ] }, { "cell_type": "code", "execution_count": 452, "id": "3e539cb4-3d20-42c0-a2bc-dada3948755d", "metadata": {}, "outputs": [], "source": [ "def loss(X, U, S, VT, rank, M):\n", " X_tilde = low_rank_matrix(U, S, VT, rank)\n", " return np.sqrt(np.square(X - X_tilde, where=M).sum())" ] }, { "cell_type": "code", "execution_count": 459, "id": "ae1a0ed9-2ae0-4985-8255-38d841e75026", "metadata": {}, "outputs": [ { "data": { "image/png": "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h8jISP74xz+6XZaIiJQCvQ+nnKhQoQILFy6kc+fO3H777bz11ltulyQiIqVAwVyOVKpUiSVLlpCQkMCAAQP44IMP3C5JRER8TMFczlSuXJlly5bRrFkz+vXrx6pVq9wuSUREfEjBXA5Vq1aNFStW0KBBA6677jpWr17tdkkiIuIjCuZyKioqivT0dKKjo+nduzeff/652yWJiIgPKJjLsUsuuYTMzEyqVKlCjx492L59u9sliYjIeVIwl3Mej4eMjAxCQkLo1q0bu3fvdrskERE5DwrmANCkSRPS09M5cuQIXbt2Ze/evW6XJCIiv5GCOUA0b96c5cuXc+DAAbp27cq+ffvcLklERH4DBXMAadWqFcuWLWPPnj20bt2aevXq0aVLF2JjY0lLS3O7PBEROQsK5gDTvn177r33Xvbs2cPevXux1pKTk0NycrLCWUSkHFAwB6AFCxb8YqygoICUlBQXqhERkXOhYA5Aubm55zQuIiL+Q8EcgGJiYk45XrVqVQoLC8u4GhERORcK5gCUmppKRESE11hoaCiHDx+mX79+HD582KXKRETkTBTMASgpKYmZM2fi8XgwxuDxeJg7dy6TJk3i/fffp02bNmzdutXtMkVE5BQUzAEqKSmJ7OxsVq5cSXZ2NklJSYwYMYKVK1dy+PBhEhISePPNN90uU0REfkbBHGQ6dOjAxo0bufzyy7n55psZNWoUx48fd7ssERFxKJiD0CWXXMKqVasYNmwYEyZMoHv37uzfv9/tskREBAVz0KpQoQIvvvgic+fOZfXq1cTHx7NmzRq3yxIRCXoK5iB322238X//93+EhYXRsWNHZs6cibXW7bJERIKWglm48sor2bBhA507d2bo0KEMGTKEI0eOuF2WiEhQUjALADVq1OD999/nkUceYfbs2XTo0EGfFCYi4gIFsxQLDQ3l6aef5p133uHLL7+kZcuWZGRkuF2WiEhQUTDLL/Tp04d169YRHR1Nz549ee655zTvLCJSRhTMckpNmjRh9erVJCYmMnr0aBITE/nhhx/cLktEJOApmOW0KleuzIIFC5gwYQJLliwhISGBL774wu2yREQCmoJZfpUxhgceeICMjAwOHDhA69atWbx4sdtliYgELAWznJVOnTqxceNGLr30Um688UZGjx6tj/IUESkFCmY5a3Xr1uXjjz9m6NChPPfcc/Tq1Yvvv//e7bJERAKKglnOSXh4ONOnT2f27Nl88sknxMfHs379erfLEhEJGApm+U3uuOMO/v73vwPQvn17Zs+e7XJFIiKBQcEsv1l8fDwbNmygQ4cODB48mKFDh3L06FG3yxIRKdcUzHJeoqKi+PDDDxkzZgwzZ86kY8eO7Nmzx+2yRETKLQWznLfQ0FCeeeYZ3nrrLbZt20Z8fDxZWVlulyUiUi6ddTAbY0KNMZ8ZY95z1usbY9YYY3YaY94wxlRwxsOd9Z3O9thSql38TL9+/Vi3bh01a9ake/fuTJgwgbS0NGJjYwkJCSE2Npa0tDS3yxQR8WvncsQ8AtheYv05YKK1thGQBwx2xgcDec74RGc/CRJxcXGsXbuWvn37MmrUKAYNGkROTg7WWnJyckhOTlY4i4j8irMKZmNMXeBa4BVn3QBdgEXOLnOBvs5yH2cdZ3tXZ38JElWqVGHhwoVUq1aNEydOeG0rKCggJSXFpcpERPzf2R4xTwL+DBQ66zWBQ9banz76aS9Qx1muA+wBcLYfdvaXIGKM4fDhw6fcpus8i4icXtiZdjDGXAfst9ZuMMZ08tUDG2OSgWSAWrVqsWrVKp/cb35+vs/uKxC42Y+LL76Yffv2/WL8wgsvdK0m/Xx4Uz9OUi+8qR/eyrQf1tpfvQF/oeiIOBv4FigA0oDvgTBnn3bAcmd5OdDOWQ5z9jO/9hjx8fHWV7Kysnx2X4HAzX7MmzfPRkREWKD4ZoyxgE1MTLR79+4t85r08+FN/ThJvfCmfnjzdT+A9fY0mXjGU9nW2jHW2rrW2ljgFmCltTYJyAISnd0GAUuc5aXOOs72lU4REmSSkpKYOXMmHo8HYwwej4dXX32V1NRU3nvvPeLi4pg8ebIuhiEiUsL5vI/5IeABY8xOiuaQZznjs4CazvgDwOjzK1HKs6SkJLKzsyksLCQ7O5tBgwbx8MMPs3XrVtq3b899991HmzZtWLt2rdulioj4hXMKZmvtKmvtdc7ybmttG2ttI2vtTdbao874EWe9kbN9d2kULuVbgwYNWLZsGQsXLmTfvn20bduWYcOGcejQIbdLExFxlT75S1xjjCExMZHt27dz7733Mn36dOLi4pg/fz6a/RCRYKVgFtdVrVqVSZMmsW7dOmJiYrj11lvp3r07X375pduliYiUOQWz+I2WLVvy6aefMm3aNNatW0fz5s154oknOHLkiNuliYiUGQWz+JXQ0FDuueceduzYQWJiIk8++STNmzcnPT3d7dJERMqEgln8UnR0NGlpaaSnp2OMoUePHtx66618++23bpcmIlKqFMzi17p168amTZt44okneOutt/jd737HtGnTfvEZ3CIigULBLH6vYsWKPP7442zevJk2bdrwpz/9ibZt27Jx40a3SxMR8TkFs5QbTZo0YcWKFbz++uvs2bOH1q1bM2LECH744Qe3SxMR8RkFs5QrxhgGDBjAF198wd13383UqVOJi4tj4cKFeu+ziAQEBbOUS9WqVWPatGmsWbOG6Oho+vfvzzXXXMOuXbvcLk1E5LwomKVca926NWvXrmXy5Mn8/e9/p1mzZowdO5ajR4+6XZqIyG+iYJZyLywsjHvvvZft27fzhz/8gUcffZQWLVqQlZXldmkiIudMwSwBo06dOrz55pssW7aMY8eO0aVLF2677Tb2799PWloasbGxdOnShdjYWNLS0twuV0TklMLcLkDE13r37s3WrVtJTU1l3LhxLFq0iBMnTnDs2DEAcnJySE5OBoouSyki4k90xCwBqVKlSowdO5Z//OMfFBYWFofyTwoKCkhJSXGpOhGR01MwS0Br2rTpL0L5J7m5uWVcjYjImSmYJeDFxMSccjwsLIwFCxZw/PjxMq5IROT0FMwS8FJTU4mIiPAaq1ChAlFRUQwYMIC4uDhmzJihy0uKiF9QMEvAS0pKYubMmXg8HowxeDweZs+ezd69e1m8eDE1atTg7rvvpn79+jz//PP6iE8RcZWCWYJCUlIS2dnZrFy5kuzsbJKSkggJCeGGG25gzZo1ZGRk0KxZM/785z/j8Xh45JFH2L9/v9tli0gQUjBL0DPG0LVrV9LT01m7di1du3blmWeeITY2luHDh5OTk+N2iSISRBTMIiW0bt2aRYsWsW3bNgYMGMCMGTNo2LAht912G1u3bnW7PBEJAgpmkVOIi4tj1qxZ7Nq1i+HDh/PWW2/RrFkz+vTpw+rVq90uT0QCmIJZ5FfUq1ePiRMnkpuby+OPP87f/vY32rVrR+fOnVm+fLkuNSkiPqdgFjkLNWvW5IknniA3N5cXXniBr776il69ehEfH8+bb77JiRMn3C5RRAKEglnkHFSuXJn777+fXbt2MWvWLH788UduvvlmmjZtyiuvvKLLTYrI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\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "l_losses = []\n", "\n", "ranks = [2, 10, 20, 30, 50, 100, 150, 200, 300, 600]\n", "for i in ranks:\n", " l_losses.append(loss(X, U, S, VT, i, M))\n", "\n", "fig, ax = plt.subplots(1, 1, figsize=(8,5))\n", "\n", "ax.plot(ranks, l_losses, 'ko-')\n", "\n", "ax.grid()\n", "plt.show()" ] }, { "cell_type": "markdown", "id": "c8e8cf3f-9447-4863-957c-3dc69b2c7703", "metadata": {}, "source": [ "## single prediction" ] }, { "cell_type": "code", "execution_count": 460, "id": "cfc3d5ef-b610-4179-bb37-4d53e1698ee8", "metadata": {}, "outputs": [], "source": [ "def get_prediction(user_idx, movie_idx, U, S, VT, rank):\n", " return U[user_idx,:rank] @ np.diag(S[:rank]) @ VT[: rank, movie_idx]" ] }, { "cell_type": "code", "execution_count": 461, "id": "9bf5f2f1-c88e-421e-8513-88ccd9d900a8", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "2.4850892043557016" ] }, "execution_count": 461, "metadata": {}, "output_type": "execute_result" } ], "source": [ "get_prediction(0, 0, U, S, VT, 2)" ] }, { "cell_type": "markdown", "id": "102c1c33-0f3d-47bc-821d-6aa50ab03f8d", "metadata": {}, "source": [ "## user idx based top non watched/rated movie recommendations " ] }, { "cell_type": "code", "execution_count": 462, "id": "f138cbd0-2824-4edc-bee3-e608b68e69e4", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Int64Index([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,\n", " ...\n", " 600, 601, 602, 603, 604, 605, 606, 607, 608, 609],\n", " dtype='int64', name='user_idx', length=610)" ] }, "execution_count": 462, "metadata": {}, "output_type": "execute_result" } ], "source": [ "user_movie_matrix.index" ] }, { "cell_type": "code", "execution_count": 469, "id": "2311be25-5d99-4aba-9389-eee8c127ee02", "metadata": {}, "outputs": [], "source": [ "user_idx = 10\n", "rank = 100" ] }, { "cell_type": "code", "execution_count": 476, "id": "61bafd08-bc2d-4a70-9a7b-2a2cb8303e14", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([nan, nan, 5., ..., nan, nan, nan])" ] }, "execution_count": 476, "metadata": {}, "output_type": "execute_result" } ], "source": [ "user_vector = user_movie_matrix.iloc[user_idx].values\n", "user_vector" ] }, { "cell_type": "code", "execution_count": 478, "id": "63c7070e-5ac9-4af8-a37a-fd21a2eb756a", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([ True, True, False, ..., True, True, True])" ] }, "execution_count": 478, "metadata": {}, "output_type": "execute_result" } ], "source": [ "non_rated_movies_idx = np.isnan(user_vector)\n", "non_rated_movies_idx" ] }, { "cell_type": "code", "execution_count": 479, "id": "4a5dd61d-39ea-4e22-a311-ea9fe08ae6cb", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([ 1.17833575, -0.08102169, 1.9669552 , ..., 0.01067371,\n", " 0.01245267, 0.01245267])" ] }, "execution_count": 479, "metadata": {}, "output_type": "execute_result" } ], "source": [ "all_movies_ratings = get_prediction(user_idx, ..., U, S, VT, rank)\n", "all_movies_ratings" ] }, { "cell_type": "code", "execution_count": 480, "id": "7df149e8-edf3-4de2-8d74-cdbe7293b534", "metadata": {}, "outputs": [], "source": [ "top_n_movies = 5" ] }, { "cell_type": "code", "execution_count": 481, "id": "1295097b-b207-498c-82c0-2a100a3f18c6", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([ 7, 20, 25, 463, 34])" ] }, "execution_count": 481, "metadata": {}, "output_type": "execute_result" } ], "source": [ "top_n_idxs = np.c_[np.argsort(all_movies_ratings)][non_rated_movies_idx][::-1][:top_n_movies, 0]\n", "top_n_idxs" ] }, { "cell_type": "code", "execution_count": 482, "id": "e9804e1b-e1e4-4421-b434-5d0cbf620052", "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", "
movieIdtitlegenresmovie_idx
97110Braveheart (1995)Action|Drama|War7.0
123150Apollo 13 (1995)Adventure|Drama|IMAX463.0
314356Forrest Gump (1994)Comedy|Drama|Romance|War20.0
398457Fugitive, The (1993)Thriller25.0
510593Silence of the Lambs, The (1991)Crime|Horror|Thriller34.0
\n", "
" ], "text/plain": [ " movieId title genres \\\n", "97 110 Braveheart (1995) Action|Drama|War \n", "123 150 Apollo 13 (1995) Adventure|Drama|IMAX \n", "314 356 Forrest Gump (1994) Comedy|Drama|Romance|War \n", "398 457 Fugitive, The (1993) Thriller \n", "510 593 Silence of the Lambs, The (1991) Crime|Horror|Thriller \n", "\n", " movie_idx \n", "97 7.0 \n", "123 463.0 \n", "314 20.0 \n", "398 25.0 \n", "510 34.0 " ] }, "execution_count": 482, "metadata": {}, "output_type": "execute_result" } ], "source": [ "movies[movies['movie_idx'].isin(top_n_idxs)]" ] } ], "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.1" } }, "nbformat": 4, "nbformat_minor": 5 }