{"cells": [{"cell_type": "markdown", "metadata": {}, "source": ["# Factorisation de matrice et recommandations\n", "\n", "Le notebook utilise la factorisation de matrice pour calculer des recommandations sur la base [movielens](https://grouplens.org/datasets/movielens/). On utilise le jeu de donn\u00e9es [ml-latest-small.zip](http://files.grouplens.org/datasets/movielens/ml-latest-small.zip)."]}, {"cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": ["%matplotlib inline"]}, {"cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [{"data": {"text/plain": ["['links', 'movies', 'ratings', 'tags']"]}, "execution_count": 3, "metadata": {}, "output_type": "execute_result"}], "source": ["from papierstat.datasets import load_movielens_dataset\n", "data = load_movielens_dataset(cache='movielens.zip')\n", "list(sorted(data))"]}, {"cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [{"data": {"text/html": ["
\n", "\n", "
\n", " \n", " \n", " | \n", " movieId | \n", " title | \n", " genres | \n", "
\n", " \n", " \n", " \n", " 9123 | \n", " 164977 | \n", " The Gay Desperado (1936) | \n", " Comedy | \n", "
\n", " \n", " 9124 | \n", " 164979 | \n", " Women of '69, Unboxed | \n", " Documentary | \n", "
\n", " \n", "
\n", "
"], "text/plain": [" movieId title genres\n", "9123 164977 The Gay Desperado (1936) Comedy\n", "9124 164979 Women of '69, Unboxed Documentary"]}, "execution_count": 4, "metadata": {}, "output_type": "execute_result"}], "source": ["data['movies'].tail(n=2)"]}, {"cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [{"data": {"text/html": ["\n", "\n", "
\n", " \n", " \n", " | \n", " userId | \n", " movieId | \n", " rating | \n", " timestamp | \n", " dt | \n", "
\n", " \n", " \n", " \n", " 100002 | \n", " 671 | \n", " 6385 | \n", " 2.5 | \n", " 1070979663 | \n", " 2003-12-09 14:21:03 | \n", "
\n", " \n", " 100003 | \n", " 671 | \n", " 6565 | \n", " 3.5 | \n", " 1074784724 | \n", " 2004-01-22 15:18:44 | \n", "
\n", " \n", "
\n", "
"], "text/plain": [" userId movieId rating timestamp dt\n", "100002 671 6385 2.5 1070979663 2003-12-09 14:21:03\n", "100003 671 6565 3.5 1074784724 2004-01-22 15:18:44"]}, "execution_count": 5, "metadata": {}, "output_type": "execute_result"}], "source": ["import pandas\n", "rate = data[\"ratings\"]\n", "rate[\"dt\"] = pandas.to_datetime(rate[\"timestamp\"], unit='s')\n", "rate.tail(n=2)"]}, {"cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [{"data": {"text/plain": ["(671, 9066)"]}, "execution_count": 6, "metadata": {}, "output_type": "execute_result"}], "source": ["len(set(rate['userId'])), len(set(rate['movieId']))"]}, {"cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [{"data": {"text/html": ["\n", "\n", "
\n", " \n", " \n", " | \n", " userId | \n", " movieId | \n", " rating | \n", " timestamp | \n", "
\n", " \n", " \n", " \n", " count | \n", " 100004.000000 | \n", " 100004.000000 | \n", " 100004.000000 | \n", " 1.000040e+05 | \n", "
\n", " \n", " mean | \n", " 347.011310 | \n", " 12548.664363 | \n", " 3.543608 | \n", " 1.129639e+09 | \n", "
\n", " \n", " std | \n", " 195.163838 | \n", " 26369.198969 | \n", " 1.058064 | \n", " 1.916858e+08 | \n", "
\n", " \n", " min | \n", " 1.000000 | \n", " 1.000000 | \n", " 0.500000 | \n", " 7.896520e+08 | \n", "
\n", " \n", " 25% | \n", " 182.000000 | \n", " 1028.000000 | \n", " 3.000000 | \n", " 9.658478e+08 | \n", "
\n", " \n", " 50% | \n", " 367.000000 | \n", " 2406.500000 | \n", " 4.000000 | \n", " 1.110422e+09 | \n", "
\n", " \n", " 75% | \n", " 520.000000 | \n", " 5418.000000 | \n", " 4.000000 | \n", " 1.296192e+09 | \n", "
\n", " \n", " max | \n", " 671.000000 | \n", " 163949.000000 | \n", " 5.000000 | \n", " 1.476641e+09 | \n", "
\n", " \n", "
\n", "
"], "text/plain": [" userId movieId rating timestamp\n", "count 100004.000000 100004.000000 100004.000000 1.000040e+05\n", "mean 347.011310 12548.664363 3.543608 1.129639e+09\n", "std 195.163838 26369.198969 1.058064 1.916858e+08\n", "min 1.000000 1.000000 0.500000 7.896520e+08\n", "25% 182.000000 1028.000000 3.000000 9.658478e+08\n", "50% 367.000000 2406.500000 4.000000 1.110422e+09\n", "75% 520.000000 5418.000000 4.000000 1.296192e+09\n", "max 671.000000 163949.000000 5.000000 1.476641e+09"]}, "execution_count": 7, "metadata": {}, "output_type": "execute_result"}], "source": ["rate.describe()"]}, {"cell_type": "markdown", "metadata": {}, "source": ["671 utilisateurs et 9066 films. C'est petit mais assez pour voir la factorisation et le temps que cela prend. Quelques id\u00e9es sur les donn\u00e9es."]}, {"cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [{"data": {"image/png": "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\n", "text/plain": [""]}, "metadata": {}, "output_type": "display_data"}], "source": ["ax = rate['rating'].hist(bins=10, figsize=(3,3))\n", "ax.set_title('Distribution des ratings');"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Les gens pr\u00e9f\u00e8rent les ratings arrondis."]}, {"cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [{"data": {"image/png": "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\n", "text/plain": [""]}, "metadata": {}, "output_type": "display_data"}], "source": ["ax = rate['dt'].hist(bins=50, figsize=(10,3))\n", "ax.set_title('Distribution des dates');"]}, {"cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [{"data": {"image/png": "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\n", "text/plain": [""]}, "metadata": {}, "output_type": "display_data"}], "source": ["import matplotlib.pyplot as plt\n", "fig, ax = plt.subplots(1,2, figsize=(6,3))\n", "gr = rate[[\"userId\", \"movieId\"]].groupby('userId').count()\n", "gr.hist('movieId', bins=50, figsize=(3,3), ax=ax[0])\n", "ax[0].set_yscale('log')\n", "ax[0].set_title('Distribution du nombre de\\nfilms not\u00e9s par utilisateur')\n", "gr = rate[[\"userId\", \"movieId\"]].groupby('movieId').count()\n", "gr.hist('userId', bins=50, figsize=(3,3), ax=ax[1])\n", "ax[1].set_yscale('log')\n", "ax[1].set_title('Distribution du nombre de\\nnotes par film');"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Il y a quelques utilisateurs z\u00e9l\u00e9s et quelques films suscitant beaucoup d'int\u00e9r\u00eat. Ce ne sont pas des valeurs aberrantes mais il faudra songer \u00e0 regarder \u00e7a de plus pr\u00e8s un jour. Noter plus de 2000 films para\u00eet suspect. M\u00eame si les votes s'\u00e9talent sur les 20 ans de collecte, cela fait un film tous les 3-4 jours. Il faut transformer les donn\u00e9es sous la forme d'une matrice [sparse](https://docs.scipy.org/doc/scipy/reference/sparse.html)."]}, {"cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [{"data": {"text/plain": ["matrix([[1., 0., 0., 0., 0.],\n", " [0., 2., 3., 0., 0.],\n", " [0., 0., 0., 4., 5.]])"]}, "execution_count": 11, "metadata": {}, "output_type": "execute_result"}], "source": ["from scipy.sparse import csr_matrix\n", "import numpy\n", "\n", "\n", "def conversion(rating, shape=None, movieId_col=None, userId_row=None):\n", " rating = rating[['userId', 'movieId', 'rating']].dropna()\n", " coefs = {}\n", " posix = {}\n", " movieId_col = movieId_col.copy() if movieId_col is not None else {}\n", " userId_row = userId_row.copy() if userId_row is not None else {}\n", " for ind, uid, mid, note in rating.itertuples():\n", " if uid not in userId_row:\n", " userId_row[uid] = len(userId_row)\n", " if mid not in movieId_col:\n", " movieId_col[mid] = len(movieId_col)\n", " row = userId_row[uid]\n", " col = movieId_col[mid]\n", " if row not in coefs:\n", " coefs[row] = []\n", " posix[row] = []\n", " coefs[row].append(note)\n", " posix[row].append(col)\n", " \n", " nbcoefs = sum(map(len, coefs.values()))\n", " indptr = numpy.zeros(len(coefs)+1)\n", " indices = numpy.zeros(nbcoefs)\n", " data = numpy.zeros(nbcoefs) \n", " nb = 0\n", " for row in range(len(userId_row)):\n", " cs = coefs[row]\n", " ps = posix[row]\n", " indptr[row] = nb\n", " for i, (p, c) in enumerate(sorted(zip(ps, cs))):\n", " indices[nb] = p\n", " data[nb] = c\n", " nb += 1 \n", " \n", " indptr[-1] = nb\n", " if shape is None:\n", " shape = (len(userId_row), len(movieId_col))\n", " mat = csr_matrix((data, indices, indptr), shape=shape)\n", " if mat.max() != data.max():\n", " end = min(10, len(indptr))\n", " raise RuntimeError(\"La conversion s'est mal pass\u00e9e.\\ndata={0}\\nindices={1}\\nindptr={2}\".format(\n", " data[:end], indices[:end], indptr[:end]))\n", " return mat, userId_row, movieId_col\n", "\n", "\n", "petit = pandas.DataFrame(dict(userId=[0, 1, 1, 5, 5], movieId=[0, 1, 2, 4, 10], \n", " rating=[1, 2, 3, 4, 5]))\n", "\n", "mat, userId_row, movieId_col = conversion(petit)\n", "numpy.nan_to_num(mat.todense())"]}, {"cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [{"data": {"text/plain": ["({0: 0, 1: 1, 5: 2}, '*', {0: 0, 1: 1, 2: 2, 4: 3, 10: 4})"]}, "execution_count": 12, "metadata": {}, "output_type": "execute_result"}], "source": ["userId_row, '*', movieId_col"]}, {"cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [{"data": {"text/plain": ["matrix([[2.5, 3. , 3. , 2. , 4. ],\n", " [0. , 0. , 0. , 0. , 0. ],\n", " [0. , 0. , 0. , 0. , 0. ],\n", " [0. , 0. , 0. , 0. , 0. ],\n", " [0. , 0. , 0. , 0. , 0. ]])"]}, "execution_count": 13, "metadata": {}, "output_type": "execute_result"}], "source": ["mat, userId_row, movieId_col = conversion(rate)\n", "numpy.nan_to_num(mat[:5,:5].todense())"]}, {"cell_type": "markdown", "metadata": {}, "source": ["On cale une factorisation de matrice."]}, {"cell_type": "code", "execution_count": 13, "metadata": {"scrolled": false}, "outputs": [{"data": {"text/plain": ["NMF(alpha=0.0, beta_loss='frobenius', init=None, l1_ratio=0.0, max_iter=400,\n", " n_components=20, random_state=None, shuffle=True, solver='cd',\n", " tol=0.0001, verbose=0)"]}, "execution_count": 14, "metadata": {}, "output_type": "execute_result"}], "source": ["from sklearn.decomposition import NMF\n", "mf = NMF(n_components=20, shuffle=True, max_iter=400)\n", "mf.fit(mat)"]}, {"cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [{"data": {"text/plain": ["897.9791684368183"]}, "execution_count": 15, "metadata": {}, "output_type": "execute_result"}], "source": ["mf.reconstruction_err_ "]}, {"cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [{"data": {"text/plain": ["array([[0. , 0.05039834, 0. , 0.00358679, 0. ],\n", " [0. , 0.01736155, 1.91278876, 0. , 0. ],\n", " [0.20592908, 0. , 0.29535495, 0. , 0. ],\n", " [0. , 0.11052953, 0. , 0.39806458, 0. ],\n", " [0.71489676, 0. , 0.20115088, 0.02163221, 0. ]])"]}, "execution_count": 16, "metadata": {}, "output_type": "execute_result"}], "source": ["wh = mf.transform(mat)\n", "wh[:5,:5]"]}, {"cell_type": "markdown", "metadata": {}, "source": ["L'erreur ne dit pas grand chose sur la pertinence de la recommandation. Le plus simple est d'enlever des notes pour voir si on les retrouve."]}, {"cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [], "source": ["from sklearn.model_selection import train_test_split\n", "rate_train, rate_test = train_test_split(rate)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Il faut quand m\u00eame s'assurer que la matrice \u00e0 d\u00e9composer a les m\u00eames dimensions que la pr\u00e9c\u00e9dente avec toutes les donn\u00e9es."]}, {"cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [], "source": ["shape0 = mat.shape\n", "mat_train, userId_row_train, movieId_col_train = conversion(rate, \n", " shape=shape0, userId_row=userId_row, movieId_col=movieId_col)"]}, {"cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [{"data": {"text/plain": ["NMF(alpha=0.0, beta_loss='frobenius', init=None, l1_ratio=0.0, max_iter=400,\n", " n_components=20, random_state=None, shuffle=True, solver='cd',\n", " tol=0.0001, verbose=0)"]}, "execution_count": 19, "metadata": {}, "output_type": "execute_result"}], "source": ["mf.fit(mat_train)"]}, {"cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [{"data": {"text/plain": ["898.1781492558509"]}, "execution_count": 20, "metadata": {}, "output_type": "execute_result"}], "source": ["mf.reconstruction_err_"]}, {"cell_type": "markdown", "metadata": {}, "source": ["On calcule l'erreur sur les bases d'apprentissage et de test."]}, {"cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [{"data": {"text/html": ["\n", "\n", "
\n", " \n", " \n", " | \n", " userId | \n", " movieId | \n", " rating | \n", " prediction | \n", "
\n", " \n", " index | \n", " | \n", " | \n", " | \n", " | \n", "
\n", " \n", " \n", " \n", " 13240 | \n", " 85 | \n", " 356 | \n", " 4.0 | \n", " 4.934174 | \n", "
\n", " \n", " 75789 | \n", " 527 | \n", " 1276 | \n", " 4.5 | \n", " 0.345162 | \n", "
\n", " \n", " 42713 | \n", " 306 | \n", " 1513 | \n", " 4.0 | \n", " 2.439180 | \n", "
\n", " \n", " 56562 | \n", " 407 | \n", " 3635 | \n", " 3.0 | \n", " 0.406101 | \n", "
\n", " \n", " 63681 | \n", " 457 | \n", " 122882 | \n", " 0.5 | \n", " 0.903360 | \n", "
\n", " \n", "
\n", "
"], "text/plain": [" userId movieId rating prediction\n", "index \n", "13240 85 356 4.0 4.934174\n", "75789 527 1276 4.5 0.345162\n", "42713 306 1513 4.0 2.439180\n", "56562 407 3635 3.0 0.406101\n", "63681 457 122882 0.5 0.903360"]}, "execution_count": 21, "metadata": {}, "output_type": "execute_result"}], "source": ["def predict(mf, mat_train, test, userId_row, movieId_col): \n", " W = mf.transform(mat_train)\n", " H = mf.components_\n", " wh = W @ H\n", " test = test[['userId', 'movieId', 'rating']]\n", " predictions = []\n", " for ind, uid, mid, note in test.itertuples(): \n", " row = userId_row[uid]\n", " col = movieId_col[mid]\n", " try:\n", " pred = wh[row, col] \n", " except Exception as e:\n", " raise Exception(\"Issue with uid={} mid={} row={} col={} shape={}\".format(uid, mid, row, col, wh.shape))\n", " predictions.append((ind, pred))\n", " dfpred = pandas.DataFrame(data=predictions, columns=['index', 'prediction']).set_index('index')\n", " dfall = pandas.concat([test, dfpred], axis=1)\n", " return dfall\n", "\n", "pred = predict(mf, mat_train, rate_test, userId_row_train, movieId_col_train)\n", "pred.head()"]}, {"cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [{"data": {"text/plain": ["-4.659895568960519"]}, "execution_count": 22, "metadata": {}, "output_type": "execute_result"}], "source": ["from sklearn.metrics import r2_score\n", "r2_score(pred['rating'], pred['prediction'])"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Pas extraordinaire. Faisons varier *k*."]}, {"cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [{"name": "stdout", "output_type": "stream", "text": ["5 {'train_time': 0.7479112074008754, 'k': 5, 'r2': -6.014138361502092, 'err_test': 7.929004708705666, 'err_train': 981.0205349504541}\n", "10 {'train_time': 1.910340634477734, 'k': 10, 'r2': -5.388353487045178, 'err_test': 7.221597617417111, 'err_train': 943.8568240851894}\n", "15 {'train_time': 2.2207374467998306, 'k': 15, 'r2': -4.96900640010828, 'err_test': 6.747554355716667, 'err_train': 918.0198374341521}\n", "20 {'train_time': 5.637187125555101, 'k': 20, 'r2': -4.694288211755458, 'err_test': 6.437004193066304, 'err_train': 897.9357561628665}\n", "25 {'train_time': 7.713239363839193, 'k': 25, 'r2': -4.420273628728207, 'err_test': 6.127249408216037, 'err_train': 878.84542031377}\n", "30 {'train_time': 12.43995074364534, 'k': 30, 'r2': -4.195368644607753, 'err_test': 5.873009673241581, 'err_train': 862.2473126443812}\n", "35 {'train_time': 15.610665020047463, 'k': 35, 'r2': -3.9997376232229183, 'err_test': 5.6518621552167065, 'err_train': 846.2449517351943}\n"]}], "source": ["from time import perf_counter as clock\n", "from sklearn.metrics import mean_squared_error\n", "values = []\n", "\n", "for k in [5, 10, 15, 20, 25, 30, 35]:\n", " mem = {}\n", " mf = NMF(n_components=k, shuffle=True, max_iter=400)\n", " cl = clock()\n", " mf.fit(mat_train)\n", " mem['train_time'] = clock() - cl\n", " pred = predict(mf, mat_train, rate_test, userId_row_train, movieId_col_train)\n", " mem['k'] = k\n", " mem['r2'] = r2_score(pred['rating'], pred['prediction'])\n", " mem['err_test'] = mean_squared_error(pred['rating'], pred['prediction'])\n", " mem['err_train'] = mf.reconstruction_err_\n", " values.append(mem)\n", " print(k, mem) "]}, {"cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [{"data": {"text/html": ["\n", "\n", "
\n", " \n", " \n", " | \n", " err_test | \n", " err_train | \n", " k | \n", " r2 | \n", " train_time | \n", "
\n", " \n", " \n", " \n", " 0 | \n", " 7.929005 | \n", " 981.020535 | \n", " 5 | \n", " -6.014138 | \n", " 0.747911 | \n", "
\n", " \n", " 1 | \n", " 7.221598 | \n", " 943.856824 | \n", " 10 | \n", " -5.388353 | \n", " 1.910341 | \n", "
\n", " \n", " 2 | \n", " 6.747554 | \n", " 918.019837 | \n", " 15 | \n", " -4.969006 | \n", " 2.220737 | \n", "
\n", " \n", " 3 | \n", " 6.437004 | \n", " 897.935756 | \n", " 20 | \n", " -4.694288 | \n", " 5.637187 | \n", "
\n", " \n", " 4 | \n", " 6.127249 | \n", " 878.845420 | \n", " 25 | \n", " -4.420274 | \n", " 7.713239 | \n", "
\n", " \n", " 5 | \n", " 5.873010 | \n", " 862.247313 | \n", " 30 | \n", " -4.195369 | \n", " 12.439951 | \n", "
\n", " \n", " 6 | \n", " 5.651862 | \n", " 846.244952 | \n", " 35 | \n", " -3.999738 | \n", " 15.610665 | \n", "
\n", " \n", "
\n", "
"], "text/plain": [" err_test err_train k r2 train_time\n", "0 7.929005 981.020535 5 -6.014138 0.747911\n", "1 7.221598 943.856824 10 -5.388353 1.910341\n", "2 6.747554 918.019837 15 -4.969006 2.220737\n", "3 6.437004 897.935756 20 -4.694288 5.637187\n", "4 6.127249 878.845420 25 -4.420274 7.713239\n", "5 5.873010 862.247313 30 -4.195369 12.439951\n", "6 5.651862 846.244952 35 -3.999738 15.610665"]}, "execution_count": 24, "metadata": {}, "output_type": "execute_result"}], "source": ["df = pandas.DataFrame(values)\n", "df"]}, {"cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [{"data": {"image/png": "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\n", "text/plain": [""]}, "metadata": {}, "output_type": "display_data"}], "source": ["fig, ax = plt.subplots(1, 4, figsize=(12, 3))\n", "df.plot(x='k', y=\"r2\", style='o-', ax=ax[0])\n", "ax[0].set_title(\"NMF\\nr2 base de test\\net k\")\n", "df.plot(x='k', y=\"err_test\", style='o-', ax=ax[1])\n", "ax[1].set_title(\"NMF\\nerreur de test\\net k\");\n", "df.plot(x='k', y=\"err_train\", style='o-', ax=ax[2])\n", "ax[2].set_title(\"NMF\\nerreur d'apprentissage\\net k\")\n", "df.plot(y='train_time', x=\"k\", style='o-', ax=ax[3])\n", "ax[3].set_title(\"NMF\\nk\\net temps d'apprentissage\");"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Il faudrait explorer de plus grandes valeurs de *k*, il faudrait aussi faire de la cross-validation puis regarder si on peut corr\u00e9l\u00e9rer les plus autres erreurs \u00e0 certains type d'utilisateurs ou de films, si on arrive \u00e0 d\u00e9terminer s'ils se distingue des autres par un faible ou fort taux de *ratings*, moyenne, plus ou moins proches des utilisateurs typiques (~*H*) ou des films typiques (~*W*). Bref, ce n'est pas fini."]}, {"cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [], "source": []}], "metadata": {"kernelspec": {"display_name": "Python 3", "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.6.4"}}, "nbformat": 4, "nbformat_minor": 2}