{ "cells": [ { "cell_type": "code", "execution_count": 46, "source": [ "# This Notebook is created with VS Code on Windows\r\n", "# Create python virtual environment\r\n", "!python -m venv .venv\r\n", "# If you want to use it on macOS/Linux\r\n", "# You may need to run sudo apt-get install python3-venv first\r\n", "#python3 -m venv .venv\r\n", "\r\n", "# Install Python Packages\r\n", "!pip install --user --upgrade pip\r\n", "!pip install --upgrade setuptools\r\n", "!pip install --user seaborn\r\n", "!pip install --user numpy\r\n", "!pip install --user pandas\r\n", "!pip install --user matplotlib\r\n", "!pip install --user plotly\r\n", "!pip install --user nbformat\r\n", "!pip install --user surprise\r\n" ], "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "Requirement already satisfied: pip in c:\\users\\oli\\appdata\\roaming\\python\\python38\\site-packages (21.2.4)\n", "Requirement already satisfied: seaborn in c:\\users\\oli\\appdata\\roaming\\python\\python38\\site-packages (0.11.2)\n", "Requirement already satisfied: matplotlib>=2.2 in c:\\users\\oli\\appdata\\local\\programs\\python\\python38\\lib\\site-packages (from seaborn) (3.3.4)\n", "Requirement already satisfied: numpy>=1.15 in c:\\users\\oli\\appdata\\local\\programs\\python\\python38\\lib\\site-packages (from seaborn) (1.19.5)\n", "Requirement already satisfied: scipy>=1.0 in c:\\users\\oli\\appdata\\local\\programs\\python\\python38\\lib\\site-packages (from seaborn) (1.6.1)\n", "Requirement already satisfied: pandas>=0.23 in c:\\users\\oli\\appdata\\local\\programs\\python\\python38\\lib\\site-packages (from seaborn) (1.2.2)\n", "Requirement already satisfied: cycler>=0.10 in c:\\users\\oli\\appdata\\local\\programs\\python\\python38\\lib\\site-packages (from matplotlib>=2.2->seaborn) (0.10.0)\n", "Requirement already satisfied: kiwisolver>=1.0.1 in c:\\users\\oli\\appdata\\local\\programs\\python\\python38\\lib\\site-packages (from matplotlib>=2.2->seaborn) (1.3.1)\n", "Requirement already satisfied: pillow>=6.2.0 in c:\\users\\oli\\appdata\\local\\programs\\python\\python38\\lib\\site-packages (from matplotlib>=2.2->seaborn) (8.1.0)\n", "Requirement already satisfied: pyparsing!=2.0.4,!=2.1.2,!=2.1.6,>=2.0.3 in c:\\users\\oli\\appdata\\local\\programs\\python\\python38\\lib\\site-packages (from matplotlib>=2.2->seaborn) (2.4.7)\n", "Requirement already satisfied: python-dateutil>=2.1 in c:\\users\\oli\\appdata\\roaming\\python\\python38\\site-packages (from matplotlib>=2.2->seaborn) (2.8.1)\n", "Requirement already satisfied: six in c:\\users\\oli\\appdata\\roaming\\python\\python38\\site-packages (from cycler>=0.10->matplotlib>=2.2->seaborn) (1.15.0)\n", "Requirement already satisfied: pytz>=2017.3 in c:\\users\\oli\\appdata\\local\\programs\\python\\python38\\lib\\site-packages (from pandas>=0.23->seaborn) (2021.1)\n", "Requirement already satisfied: numpy in c:\\users\\oli\\appdata\\local\\programs\\python\\python38\\lib\\site-packages (1.19.5)\n", "Requirement already satisfied: pandas in c:\\users\\oli\\appdata\\local\\programs\\python\\python38\\lib\\site-packages (1.2.2)\n", "Requirement already satisfied: pytz>=2017.3 in c:\\users\\oli\\appdata\\local\\programs\\python\\python38\\lib\\site-packages (from pandas) (2021.1)\n", "Requirement already satisfied: python-dateutil>=2.7.3 in c:\\users\\oli\\appdata\\roaming\\python\\python38\\site-packages (from pandas) (2.8.1)\n", "Requirement already satisfied: numpy>=1.16.5 in c:\\users\\oli\\appdata\\local\\programs\\python\\python38\\lib\\site-packages (from pandas) (1.19.5)\n", "Requirement already satisfied: six>=1.5 in c:\\users\\oli\\appdata\\roaming\\python\\python38\\site-packages (from python-dateutil>=2.7.3->pandas) (1.15.0)\n", "Requirement already satisfied: matplotlib in c:\\users\\oli\\appdata\\local\\programs\\python\\python38\\lib\\site-packages (3.3.4)\n", "Requirement already satisfied: cycler>=0.10 in c:\\users\\oli\\appdata\\local\\programs\\python\\python38\\lib\\site-packages (from matplotlib) (0.10.0)\n", "Requirement already satisfied: kiwisolver>=1.0.1 in c:\\users\\oli\\appdata\\local\\programs\\python\\python38\\lib\\site-packages (from matplotlib) (1.3.1)\n", "Requirement already satisfied: numpy>=1.15 in c:\\users\\oli\\appdata\\local\\programs\\python\\python38\\lib\\site-packages (from matplotlib) (1.19.5)\n", "Requirement already satisfied: pyparsing!=2.0.4,!=2.1.2,!=2.1.6,>=2.0.3 in c:\\users\\oli\\appdata\\local\\programs\\python\\python38\\lib\\site-packages (from matplotlib) (2.4.7)\n", "Requirement already satisfied: python-dateutil>=2.1 in c:\\users\\oli\\appdata\\roaming\\python\\python38\\site-packages (from matplotlib) (2.8.1)\n", "Requirement already satisfied: pillow>=6.2.0 in c:\\users\\oli\\appdata\\local\\programs\\python\\python38\\lib\\site-packages (from matplotlib) (8.1.0)\n", "Requirement already satisfied: six in c:\\users\\oli\\appdata\\roaming\\python\\python38\\site-packages (from cycler>=0.10->matplotlib) (1.15.0)\n", "Requirement already satisfied: plotly in c:\\users\\oli\\appdata\\roaming\\python\\python38\\site-packages (5.3.0)\n", "Requirement already satisfied: six in c:\\users\\oli\\appdata\\roaming\\python\\python38\\site-packages (from plotly) (1.15.0)\n", "Requirement already satisfied: tenacity>=6.2.0 in c:\\users\\oli\\appdata\\roaming\\python\\python38\\site-packages (from plotly) (8.0.1)\n", "Requirement already satisfied: nbformat in c:\\users\\oli\\appdata\\roaming\\python\\python38\\site-packages (5.1.3)\n", "Requirement already satisfied: traitlets>=4.1 in c:\\users\\oli\\appdata\\roaming\\python\\python38\\site-packages (from nbformat) (5.0.5)\n", "Requirement already satisfied: jsonschema!=2.5.0,>=2.4 in c:\\users\\oli\\appdata\\roaming\\python\\python38\\site-packages (from nbformat) (3.2.0)\n", "Requirement already satisfied: ipython-genutils in c:\\users\\oli\\appdata\\roaming\\python\\python38\\site-packages (from nbformat) (0.2.0)\n", "Requirement already satisfied: jupyter-core in c:\\users\\oli\\appdata\\roaming\\python\\python38\\site-packages (from nbformat) (4.7.1)\n", "Requirement already satisfied: six>=1.11.0 in c:\\users\\oli\\appdata\\roaming\\python\\python38\\site-packages (from jsonschema!=2.5.0,>=2.4->nbformat) (1.15.0)\n", "Requirement already satisfied: setuptools in c:\\users\\oli\\appdata\\local\\programs\\python\\python38\\lib\\site-packages (from jsonschema!=2.5.0,>=2.4->nbformat) (49.2.1)\n", "Requirement already satisfied: pyrsistent>=0.14.0 in c:\\users\\oli\\appdata\\roaming\\python\\python38\\site-packages (from jsonschema!=2.5.0,>=2.4->nbformat) (0.18.0)\n", "Requirement already satisfied: attrs>=17.4.0 in c:\\users\\oli\\appdata\\roaming\\python\\python38\\site-packages (from jsonschema!=2.5.0,>=2.4->nbformat) (21.2.0)\n", "Requirement already satisfied: pywin32>=1.0 in c:\\users\\oli\\appdata\\roaming\\python\\python38\\site-packages (from jupyter-core->nbformat) (300)\n", "Collecting surprise\n", " Downloading surprise-0.1-py2.py3-none-any.whl (1.8 kB)\n", "Collecting scikit-surprise\n", " Downloading scikit-surprise-1.1.1.tar.gz (11.8 MB)\n", "Requirement already satisfied: joblib>=0.11 in c:\\users\\oli\\appdata\\local\\programs\\python\\python38\\lib\\site-packages (from scikit-surprise->surprise) (1.0.1)\n", "Requirement already satisfied: numpy>=1.11.2 in c:\\users\\oli\\appdata\\local\\programs\\python\\python38\\lib\\site-packages (from scikit-surprise->surprise) (1.19.5)\n", "Requirement already satisfied: scipy>=1.0.0 in c:\\users\\oli\\appdata\\local\\programs\\python\\python38\\lib\\site-packages (from scikit-surprise->surprise) (1.6.1)\n", "Requirement already satisfied: six>=1.10.0 in c:\\users\\oli\\appdata\\roaming\\python\\python38\\site-packages (from scikit-surprise->surprise) (1.15.0)\n", "Building wheels for collected packages: scikit-surprise\n", " Building wheel for scikit-surprise (setup.py): started\n", " Building wheel for scikit-surprise (setup.py): finished with status 'error'\n", " Running setup.py clean for scikit-surprise\n", "Failed to build scikit-surprise\n", "Installing collected packages: scikit-surprise, surprise\n", " Running setup.py install for scikit-surprise: started\n", " Running setup.py install for scikit-surprise: finished with status 'error'\n" ] }, { "output_type": "stream", "name": "stderr", "text": [ " ERROR: Command errored out with exit status 1:\n", " command: 'c:\\users\\oli\\appdata\\local\\programs\\python\\python38\\python.exe' -u -c 'import io, os, sys, setuptools, tokenize; sys.argv[0] = '\"'\"'C:\\\\Users\\\\Oli\\\\AppData\\\\Local\\\\Temp\\\\pip-install-jibnz200\\\\scikit-surprise_07dc192d3cf347769fae216d5b05a944\\\\setup.py'\"'\"'; __file__='\"'\"'C:\\\\Users\\\\Oli\\\\AppData\\\\Local\\\\Temp\\\\pip-install-jibnz200\\\\scikit-surprise_07dc192d3cf347769fae216d5b05a944\\\\setup.py'\"'\"';f = getattr(tokenize, '\"'\"'open'\"'\"', open)(__file__) if os.path.exists(__file__) else io.StringIO('\"'\"'from setuptools import setup; setup()'\"'\"');code = f.read().replace('\"'\"'\\r\\n'\"'\"', '\"'\"'\\n'\"'\"');f.close();exec(compile(code, __file__, '\"'\"'exec'\"'\"'))' bdist_wheel -d 'C:\\Users\\Oli\\AppData\\Local\\Temp\\pip-wheel-dz4_1ymq'\n", " cwd: C:\\Users\\Oli\\AppData\\Local\\Temp\\pip-install-jibnz200\\scikit-surprise_07dc192d3cf347769fae216d5b05a944\\\n", " Complete output (49 lines):\n", " running bdist_wheel\n", " running build\n", " running build_py\n", " creating build\n", " creating build\\lib.win-amd64-3.8\n", " creating build\\lib.win-amd64-3.8\\surprise\n", " copying surprise\\accuracy.py -> build\\lib.win-amd64-3.8\\surprise\n", " copying surprise\\builtin_datasets.py -> build\\lib.win-amd64-3.8\\surprise\n", " copying surprise\\dataset.py -> build\\lib.win-amd64-3.8\\surprise\n", " copying surprise\\dump.py -> build\\lib.win-amd64-3.8\\surprise\n", " copying surprise\\reader.py -> build\\lib.win-amd64-3.8\\surprise\n", " copying surprise\\trainset.py -> build\\lib.win-amd64-3.8\\surprise\n", " copying surprise\\utils.py -> build\\lib.win-amd64-3.8\\surprise\n", " copying surprise\\__init__.py -> build\\lib.win-amd64-3.8\\surprise\n", " copying surprise\\__main__.py -> build\\lib.win-amd64-3.8\\surprise\n", " creating build\\lib.win-amd64-3.8\\surprise\\model_selection\n", " copying surprise\\model_selection\\search.py -> build\\lib.win-amd64-3.8\\surprise\\model_selection\n", " copying surprise\\model_selection\\split.py -> build\\lib.win-amd64-3.8\\surprise\\model_selection\n", " copying surprise\\model_selection\\validation.py -> build\\lib.win-amd64-3.8\\surprise\\model_selection\n", " copying surprise\\model_selection\\__init__.py -> build\\lib.win-amd64-3.8\\surprise\\model_selection\n", " creating build\\lib.win-amd64-3.8\\surprise\\prediction_algorithms\n", " copying surprise\\prediction_algorithms\\algo_base.py -> build\\lib.win-amd64-3.8\\surprise\\prediction_algorithms\n", " copying surprise\\prediction_algorithms\\baseline_only.py -> build\\lib.win-amd64-3.8\\surprise\\prediction_algorithms\n", " copying surprise\\prediction_algorithms\\knns.py -> build\\lib.win-amd64-3.8\\surprise\\prediction_algorithms\n", " copying surprise\\prediction_algorithms\\predictions.py -> build\\lib.win-amd64-3.8\\surprise\\prediction_algorithms\n", " copying surprise\\prediction_algorithms\\random_pred.py -> build\\lib.win-amd64-3.8\\surprise\\prediction_algorithms\n", " copying surprise\\prediction_algorithms\\__init__.py -> build\\lib.win-amd64-3.8\\surprise\\prediction_algorithms\n", " running egg_info\n", " writing scikit_surprise.egg-info\\PKG-INFO\n", " writing dependency_links to scikit_surprise.egg-info\\dependency_links.txt\n", " writing entry points to scikit_surprise.egg-info\\entry_points.txt\n", " writing requirements to scikit_surprise.egg-info\\requires.txt\n", " writing top-level names to scikit_surprise.egg-info\\top_level.txt\n", " reading manifest file 'scikit_surprise.egg-info\\SOURCES.txt'\n", " reading manifest template 'MANIFEST.in'\n", " writing manifest file 'scikit_surprise.egg-info\\SOURCES.txt'\n", " copying surprise\\similarities.c -> build\\lib.win-amd64-3.8\\surprise\n", " copying surprise\\similarities.pyx -> build\\lib.win-amd64-3.8\\surprise\n", " copying surprise\\prediction_algorithms\\co_clustering.c -> build\\lib.win-amd64-3.8\\surprise\\prediction_algorithms\n", " copying surprise\\prediction_algorithms\\matrix_factorization.c -> build\\lib.win-amd64-3.8\\surprise\\prediction_algorithms\n", " copying surprise\\prediction_algorithms\\optimize_baselines.c -> build\\lib.win-amd64-3.8\\surprise\\prediction_algorithms\n", " copying surprise\\prediction_algorithms\\slope_one.c -> build\\lib.win-amd64-3.8\\surprise\\prediction_algorithms\n", " copying surprise\\prediction_algorithms\\co_clustering.pyx -> build\\lib.win-amd64-3.8\\surprise\\prediction_algorithms\n", " copying surprise\\prediction_algorithms\\matrix_factorization.pyx -> build\\lib.win-amd64-3.8\\surprise\\prediction_algorithms\n", " copying surprise\\prediction_algorithms\\optimize_baselines.pyx -> build\\lib.win-amd64-3.8\\surprise\\prediction_algorithms\n", " copying surprise\\prediction_algorithms\\slope_one.pyx -> build\\lib.win-amd64-3.8\\surprise\\prediction_algorithms\n", " running build_ext\n", " building 'surprise.similarities' extension\n", " error: Microsoft Visual C++ 14.0 is required. Get it with \"Build Tools for Visual Studio\": https://visualstudio.microsoft.com/downloads/\n", " ----------------------------------------\n", " ERROR: Failed building wheel for scikit-surprise\n", " ERROR: Command errored out with exit status 1:\n", " command: 'c:\\users\\oli\\appdata\\local\\programs\\python\\python38\\python.exe' -u -c 'import io, os, sys, setuptools, tokenize; sys.argv[0] = '\"'\"'C:\\\\Users\\\\Oli\\\\AppData\\\\Local\\\\Temp\\\\pip-install-jibnz200\\\\scikit-surprise_07dc192d3cf347769fae216d5b05a944\\\\setup.py'\"'\"'; __file__='\"'\"'C:\\\\Users\\\\Oli\\\\AppData\\\\Local\\\\Temp\\\\pip-install-jibnz200\\\\scikit-surprise_07dc192d3cf347769fae216d5b05a944\\\\setup.py'\"'\"';f = getattr(tokenize, '\"'\"'open'\"'\"', open)(__file__) if os.path.exists(__file__) else io.StringIO('\"'\"'from setuptools import setup; setup()'\"'\"');code = f.read().replace('\"'\"'\\r\\n'\"'\"', '\"'\"'\\n'\"'\"');f.close();exec(compile(code, __file__, '\"'\"'exec'\"'\"'))' install --record 'C:\\Users\\Oli\\AppData\\Local\\Temp\\pip-record-ivcio2vz\\install-record.txt' --single-version-externally-managed --user --prefix= --compile --install-headers 'C:\\Users\\Oli\\AppData\\Roaming\\Python\\Python38\\Include\\scikit-surprise'\n", " cwd: C:\\Users\\Oli\\AppData\\Local\\Temp\\pip-install-jibnz200\\scikit-surprise_07dc192d3cf347769fae216d5b05a944\\\n", " Complete output (49 lines):\n", " running install\n", " running build\n", " running build_py\n", " creating build\n", " creating build\\lib.win-amd64-3.8\n", " creating build\\lib.win-amd64-3.8\\surprise\n", " copying surprise\\accuracy.py -> build\\lib.win-amd64-3.8\\surprise\n", " copying surprise\\builtin_datasets.py -> build\\lib.win-amd64-3.8\\surprise\n", " copying surprise\\dataset.py -> build\\lib.win-amd64-3.8\\surprise\n", " copying surprise\\dump.py -> build\\lib.win-amd64-3.8\\surprise\n", " copying surprise\\reader.py -> build\\lib.win-amd64-3.8\\surprise\n", " copying surprise\\trainset.py -> build\\lib.win-amd64-3.8\\surprise\n", " copying surprise\\utils.py -> build\\lib.win-amd64-3.8\\surprise\n", " copying surprise\\__init__.py -> build\\lib.win-amd64-3.8\\surprise\n", " copying surprise\\__main__.py -> build\\lib.win-amd64-3.8\\surprise\n", " creating build\\lib.win-amd64-3.8\\surprise\\model_selection\n", " copying surprise\\model_selection\\search.py -> build\\lib.win-amd64-3.8\\surprise\\model_selection\n", " copying surprise\\model_selection\\split.py -> build\\lib.win-amd64-3.8\\surprise\\model_selection\n", " copying surprise\\model_selection\\validation.py -> build\\lib.win-amd64-3.8\\surprise\\model_selection\n", " copying surprise\\model_selection\\__init__.py -> build\\lib.win-amd64-3.8\\surprise\\model_selection\n", " creating build\\lib.win-amd64-3.8\\surprise\\prediction_algorithms\n", " copying surprise\\prediction_algorithms\\algo_base.py -> build\\lib.win-amd64-3.8\\surprise\\prediction_algorithms\n", " copying surprise\\prediction_algorithms\\baseline_only.py -> build\\lib.win-amd64-3.8\\surprise\\prediction_algorithms\n", " copying surprise\\prediction_algorithms\\knns.py -> build\\lib.win-amd64-3.8\\surprise\\prediction_algorithms\n", " copying surprise\\prediction_algorithms\\predictions.py -> build\\lib.win-amd64-3.8\\surprise\\prediction_algorithms\n", " copying surprise\\prediction_algorithms\\random_pred.py -> build\\lib.win-amd64-3.8\\surprise\\prediction_algorithms\n", " copying surprise\\prediction_algorithms\\__init__.py -> build\\lib.win-amd64-3.8\\surprise\\prediction_algorithms\n", " running egg_info\n", " writing scikit_surprise.egg-info\\PKG-INFO\n", " writing dependency_links to scikit_surprise.egg-info\\dependency_links.txt\n", " writing entry points to scikit_surprise.egg-info\\entry_points.txt\n", " writing requirements to scikit_surprise.egg-info\\requires.txt\n", " writing top-level names to scikit_surprise.egg-info\\top_level.txt\n", " reading manifest file 'scikit_surprise.egg-info\\SOURCES.txt'\n", " reading manifest template 'MANIFEST.in'\n", " writing manifest file 'scikit_surprise.egg-info\\SOURCES.txt'\n", " copying surprise\\similarities.c -> build\\lib.win-amd64-3.8\\surprise\n", " copying surprise\\similarities.pyx -> build\\lib.win-amd64-3.8\\surprise\n", " copying surprise\\prediction_algorithms\\co_clustering.c -> build\\lib.win-amd64-3.8\\surprise\\prediction_algorithms\n", " copying surprise\\prediction_algorithms\\matrix_factorization.c -> build\\lib.win-amd64-3.8\\surprise\\prediction_algorithms\n", " copying surprise\\prediction_algorithms\\optimize_baselines.c -> build\\lib.win-amd64-3.8\\surprise\\prediction_algorithms\n", " copying surprise\\prediction_algorithms\\slope_one.c -> build\\lib.win-amd64-3.8\\surprise\\prediction_algorithms\n", " copying surprise\\prediction_algorithms\\co_clustering.pyx -> build\\lib.win-amd64-3.8\\surprise\\prediction_algorithms\n", " copying surprise\\prediction_algorithms\\matrix_factorization.pyx -> build\\lib.win-amd64-3.8\\surprise\\prediction_algorithms\n", " copying surprise\\prediction_algorithms\\optimize_baselines.pyx -> build\\lib.win-amd64-3.8\\surprise\\prediction_algorithms\n", " copying surprise\\prediction_algorithms\\slope_one.pyx -> build\\lib.win-amd64-3.8\\surprise\\prediction_algorithms\n", " running build_ext\n", " building 'surprise.similarities' extension\n", " error: Microsoft Visual C++ 14.0 is required. Get it with \"Build Tools for Visual Studio\": https://visualstudio.microsoft.com/downloads/\n", " ----------------------------------------\n", "ERROR: Command errored out with exit status 1: 'c:\\users\\oli\\appdata\\local\\programs\\python\\python38\\python.exe' -u -c 'import io, os, sys, setuptools, tokenize; sys.argv[0] = '\"'\"'C:\\\\Users\\\\Oli\\\\AppData\\\\Local\\\\Temp\\\\pip-install-jibnz200\\\\scikit-surprise_07dc192d3cf347769fae216d5b05a944\\\\setup.py'\"'\"'; __file__='\"'\"'C:\\\\Users\\\\Oli\\\\AppData\\\\Local\\\\Temp\\\\pip-install-jibnz200\\\\scikit-surprise_07dc192d3cf347769fae216d5b05a944\\\\setup.py'\"'\"';f = getattr(tokenize, '\"'\"'open'\"'\"', open)(__file__) if os.path.exists(__file__) else io.StringIO('\"'\"'from setuptools import setup; setup()'\"'\"');code = f.read().replace('\"'\"'\\r\\n'\"'\"', '\"'\"'\\n'\"'\"');f.close();exec(compile(code, __file__, '\"'\"'exec'\"'\"'))' install --record 'C:\\Users\\Oli\\AppData\\Local\\Temp\\pip-record-ivcio2vz\\install-record.txt' --single-version-externally-managed --user --prefix= --compile --install-headers 'C:\\Users\\Oli\\AppData\\Roaming\\Python\\Python38\\Include\\scikit-surprise' Check the logs for full command output.\n" ] } ], "metadata": {} }, { "cell_type": "code", "execution_count": 3, "source": [ "import numpy as np # maths\r\n", "import pandas as pd # data processing\r\n", "import matplotlib.pyplot as plt\r\n", "import seaborn as sns\r\n", "import os\r\n", "import re\r\n", "\r\n", "from plotly.offline import init_notebook_mode, iplot\r\n", "import plotly.graph_objs as go\r\n", "import plotly.offline as py\r\n", "py.init_notebook_mode(connected=True)\r\n", "\r\n", "import warnings\r\n", "warnings.filterwarnings('ignore')\r\n", "\r\n", "plt.style.use('fivethirtyeight')\r\n", "plt.rcParams['figure.figsize'] = [18, 8]" ], "outputs": [ { "output_type": "display_data", "data": { "text/html": [ " \n", " " ] }, "metadata": {} } ], "metadata": {} }, { "cell_type": "code", "execution_count": 4, "source": [ "# Import Tables\r\n", "reviews = pd.read_csv('./ml-1m/ratings.dat', names=['userId', 'movieId', 'rating', 'timestamp'], delimiter='::', engine='python')\r\n", "movies = pd.read_csv('./ml-1m/movies.dat', names=['movieId', 'title', 'genres'], delimiter='::', engine='python')\r\n", "users = pd.read_csv('./ml-1m/users.dat', names=['userId', 'gender', 'age', 'occupation', 'zip'], delimiter='::', engine='python')\r\n", "\r\n", "# Print Table shape\r\n", "print('Reviews shape:', reviews.shape)\r\n", "print('Users shape:', users.shape)\r\n", "print('Movies shape:', movies.shape)" ], "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "Reviews shape: (1000209, 4)\n", "Users shape: (6040, 5)\n", "Movies shape: (3883, 3)\n" ] } ], "metadata": {} }, { "cell_type": "code", "execution_count": 5, "source": [ "# Drop unused Attributes\r\n", "reviews.drop(['timestamp'], axis=1, inplace=True) # Time\r\n", "users.drop(['zip'], axis=1, inplace=True) # Zip-Code\r\n", "\r\n", "# Extract the movie year from title to extra attrbute\r\n", "movies['release_year'] = movies['title'].str.extract(r'(?:\\((\\d{4})\\))?\\s*$', expand=False)" ], "outputs": [], "metadata": {} }, { "cell_type": "code", "execution_count": 6, "source": [ "# Print movie table\r\n", "movies.head()" ], "outputs": [ { "output_type": "execute_result", "data": { "text/plain": [ " movieId title genres \\\n", "0 1 Toy Story (1995) Animation|Children's|Comedy \n", "1 2 Jumanji (1995) Adventure|Children's|Fantasy \n", "2 3 Grumpier Old Men (1995) Comedy|Romance \n", "3 4 Waiting to Exhale (1995) Comedy|Drama \n", "4 5 Father of the Bride Part II (1995) Comedy \n", "\n", " release_year \n", "0 1995 \n", "1 1995 \n", "2 1995 \n", "3 1995 \n", "4 1995 " ], "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", "
movieIdtitlegenresrelease_year
01Toy Story (1995)Animation|Children's|Comedy1995
12Jumanji (1995)Adventure|Children's|Fantasy1995
23Grumpier Old Men (1995)Comedy|Romance1995
34Waiting to Exhale (1995)Comedy|Drama1995
45Father of the Bride Part II (1995)Comedy1995
\n", "
" ] }, "metadata": {}, "execution_count": 6 } ], "metadata": {} }, { "cell_type": "code", "execution_count": 7, "source": [ "# Changed feature values based on README_users.txt\r\n", "\r\n", "ages_map = {1: 'Under 18',\r\n", " 18: '18 - 24',\r\n", " 25: '25 - 34',\r\n", " 35: '35 - 44',\r\n", " 45: '45 - 49',\r\n", " 50: '50 - 55',\r\n", " 56: '56+'}\r\n", "\r\n", "occupations_map = {0: 'Not specified',\r\n", " 1: 'Academic / Educator',\r\n", " 2: 'Artist',\r\n", " 3: 'Clerical / Admin',\r\n", " 4: 'College / Grad Student',\r\n", " 5: 'Customer Service',\r\n", " 6: 'Doctor / Health Care',\r\n", " 7: 'Executive / Managerial',\r\n", " 8: 'Farmer',\r\n", " 9: 'Homemaker',\r\n", " 10: 'K-12 student',\r\n", " 11: 'Lawyer',\r\n", " 12: 'Programmer',\r\n", " 13: 'Retired',\r\n", " 14: 'Sales / Marketing',\r\n", " 15: 'Scientist',\r\n", " 16: 'Self-Employed',\r\n", " 17: 'Technician / Engineer',\r\n", " 18: 'Tradesman / Craftsman',\r\n", " 19: 'Unemployed',\r\n", " 20: 'Writer'}\r\n", "\r\n", "gender_map = {'M': 'Male', 'F': 'Female'}\r\n", "\r\n", "users['age'] = users['age'].map(ages_map)\r\n", "users['occupation'] = users['occupation'].map(occupations_map)\r\n", "users['gender'] = users['gender'].map(gender_map)" ], "outputs": [], "metadata": {} }, { "cell_type": "code", "execution_count": 8, "source": [ "# Plot age kategories\r\n", "\r\n", "age_reindex = ['Under 18', '18 - 24', '25 - 34', '35 - 44', '45 - 49', '50 - 55', '56+']\r\n", "age_counts = users['age'].value_counts().reindex(age_reindex)\r\n", "sns.barplot(x=age_counts.values,\r\n", " y=age_counts.index,\r\n", " palette='magma').set_title(\r\n", " 'Users age', fontsize=12)\r\n", "\r\n", "plt.show()" ], "outputs": [ { "output_type": "display_data", "data": { "text/plain": [ "
" ], "image/svg+xml": "\r\n\r\n\r\n\r\n \r\n \r\n \r\n \r\n 2021-08-30T20:53:27.375390\r\n image/svg+xml\r\n \r\n \r\n Matplotlib v3.3.4, https://matplotlib.org/\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n\r\n", "image/png": "iVBORw0KGgoAAAANSUhEUgAABLkAAAICCAYAAAAj5h9BAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjMuNCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8QVMy6AAAACXBIWXMAAAsTAAALEwEAmpwYAAA7p0lEQVR4nO3de5hVdd03/vcwo0KgDiKOnAkYQAFFQSV79PGAGKmQecBD2mMmd6gPeecBPOWxkDykpmKPilqpUai3h0wrj6SYlsfUmxvFAyKijkIBIsrM749+7asJBJQZNktfr+va1zVrfb97fT9rvmvP3vs9a69dMX/+/IYAAAAAQIG1KHcBAAAAALCmhFwAAAAAFJ6QCwAAAIDCE3IBAAAAUHhCLgAAAAAKT8gFAAAAQOEJuQAAAAAoPCEXAECZVFdXZ9asWY3WTZgwIaNHjy5TRQAAxSXkAgD4jPvoo4/KXQIAQLMTcgEArKPq6uoyatSodO3aNd27d8/w4cNTX1+fJJk7d24OO+yw9OzZM1tttVWuvPLK0v0mTJiQww8/PKNHj06XLl1y44035i9/+Ut22WWXdOnSJbW1tTnllFNWOOb8+fMzatSo9OzZM926dcuoUaMyZ86cUvsrr7yS4cOHp3Pnzhk5cmROOOGERmeePf744xk2bFi6du2aL3/5y5k2bVoz/XYAABoTcgEArKMuu+yydOzYMS+99FJmzpyZ008/PRUVFamvr89BBx2U/v3754UXXsjtt9+eSZMm5d577y3d96677sqIESPy6quv5oADDsj48ePzne98J7Nnz86TTz6Zfffdd4Vj1tfX55BDDsmzzz6bv/71r2nZsmVOPPHEUvtRRx2VQYMGZdasWRk/fnymTJlSanvjjTdy4IEH5oQTTsgrr7ySc889N4cffnjeeeed5vslAQD8/4RcAADrqKqqqrz55puZPXt21ltvvey4446pqKjIE088kbq6uowbNy7rr79+unfvnm9+85u5+eabS/fdbrvtsvfee6dFixZp1apVqqqqMmvWrNTV1aVNmzbZbrvtVjjmJptskpEjR+YLX/hCNtxwwxx//PF5+OGHkySzZ8/OE088kVNOOSXrr79+vvSlL2X48OGl+/7qV7/KHnvskWHDhqVFixbZdddds8022+R3v/td8/6iAAAi5AIAKJvKysp8+OGHjdZ99NFHqaqqSpKMHTs2PXr0yL777putt946P/7xj5P8I2yaO3duunbtWrpddNFFefvtt0vb6dy5c6PtXnbZZXnppZey3XbbZdddd83dd9+9wpoWL16c4447Lv3790+XLl2y1157ZcGCBVm2bFnefPPNtG3bNl/4whdK/Tt16lT6efbs2bntttsa1fXoo49m3rx5a/aLAgBYDVXlLgAA4POqc+fOee2119KnT5/SuldffTU9e/ZMkmy44Yb5wQ9+kB/84Ad5/vnnM2LEiGy77bbp1KlTunXrlieeeOJjt11RUdFouWfPnrnmmmtSX1+fO+64I9/85jcza9astG7dulG/yy67LDNnzsy9996bmpqaPPPMM9l5553T0NCQmpqavPfee1m8eHEp6PrX63V16tQpo0aNyqWXXrrGvxsAgE/KmVwAAGXy9a9/PRdccEHmzJmT+vr6PPDAA7n77rszcuTIJMndd9+dWbNmpaGhIRtttFEqKytTUVGRQYMGpU2bNrn44ovz/vvvZ9myZXn++edXGnpNmTIl77zzTlq0aJGNN944SdKixfIvBRcuXJhWrVpl4403znvvvZeJEyeW2rp27Zptttkm5513XpYuXZrHHnus0RlhBx54YO6+++7ce++9WbZsWZYsWZJp06Y1CsIAAJqLkAsAoExOOumkbL/99vnKV76S7t275/vf/37+3//7f9lyyy2TJC+99FJGjhyZTp06ZdiwYTnyyCOz8847p7KyMlOmTMmzzz6brbfeOj169MjYsWPzt7/97WPHuvfeezNkyJB06tQp48ePzzXXXJNWrVot12/MmDF5//3307NnzwwdOjRDhw5t1H7VVVfl8ccfT48ePXLuuedm3333zfrrr5/kH2em3XjjjbnwwgvTs2fP9OvXLz/5yU9K3wgJANCcKubPn99Q7iIAACimI444IrW1tTnllFPKXQoA8DnnTC4AAFbbE088kZdffjn19fX5wx/+kLvuuit77bVXucsCAHDheQAAVt+8efNy2GGH5d13303Hjh1z4YUXZuutty53WQAAPq4IAAAAQPH5uCIAAAAAhSfkAgAAAKDwhFwAAAAAFJ6QCwAAAIDCE3LBapo5c2a5S6CMzP/nm/nHMfD5Zv4/38z/55v5/3wz/8Uj5AIAAACg8IRcAAAAABSekAsAAACAwqsqdwFFtE2fr5W7BNbAkzP+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oPCEXAAAAAAUnpALAAAAgMITcgEAAABQeEIuAAAAAApPyAUAAABA4Qm5AAAAACg8IRcAAAAAhSfkAgAAAKDwhFwAAAAAFJ6QCwAAAIDCE3IBAAAAUHhCLgAAAAAKT8gFAAAAQOEJuQAAAAAoPCEXAAAAAIUn5AIAAACg8IRcAAAAABSekAsAAACAwmvWkOvhhx/OQQcdlC222CLV1dW54YYbluuzcOHCnHjiidlyyy2z+eabZ/Dgwbn88svXeOxXX301xx57bLbeeutsvvnm2XrrrXPWWWfl/fffX2H/urq6Up11dXVrPD4AAAAAa09Vc2580aJF2XLLLXPwwQfnO9/5zgr7nHrqqXnggQdy5ZVXplu3bnnkkUfy3e9+N+3atctBBx30qceeOXNmli1blosuuig9e/bMjBkzctxxx+Xdd9/NJZdcslz/o48+OgMGDMjcuXM/9ZgAAAAAlEeznsk1bNiwfP/738/IkSPTosWKh3rssccyatSo7LzzzunWrVsOPvjgDB48OH/5y1/WaOyhQ4dm0qRJ2X333dO9e/fsueeeOf7443P77bcv13fSpEl5//33c8wxx6zRmAAAAACUR9mvyTVkyJDcfffdef3115Mkf/rTn/LXv/41u+++e5OP9fe//z3V1dWN1j399NO55JJLcuWVV35sEAcAAADAuq3sqc7EiRPTv3//9O/fP5tuumn22muvnHnmmfnKV77SpOO89tpr+clPfpIjjzyytG7RokU58sgjM3HixHTs2LFJxwMAAABg7Sl7yPXTn/40jz32WG666aY88MAD+eEPf5jTTz89f/jDH1bYf/bs2enUqVPpduGFF65yjLfeeiv7779/dt1110YfSRw3blyGDBmSkSNHNtn+AAAAALD2NeuF51fl/fffz9lnn53rrrsuw4cPT5L0798/zz77bH7yk59k6NChy92nQ4cOmTZtWmm5bdu2Kx1j3rx5GTFiRLbYYov89Kc/TUVFRantwQcfzJw5c3LTTTclSRoaGpIkvXv3znHHHZfTTz99jfcRAAAAgOZX1pDrww8/zIcffpjKyspG6ysrK1NfX7/C+1RVVaVHjx6rtf0333wz++yzT/r27ZtrrrkmVVWNd/fWW2/N0qVLS8tPPPFEjj322Nx5553p2bPnJ9wbAAAAAMqlWUOuhQsXZtasWUmS+vr6vP7663nm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FwAAAACFJ+QCAAAAoPCEXAAAAAAUnpALAAAAgMITcgEAAABQeEIuAAAAAApPyAUAAABA4Qm5AAAAACg8IRcAAAAAhSfkAgAAAKDwhFwAAAAAFN5aC7kuuuiiVFdX58QTT2y0fsyYMamurm50Gzp0aJOOvWTJknz5y19OdXV1nnzyyUZtDz74YIYNG5bOnTund+/eOeOMM/LRRx816fgAAAAANK+1EnI9/vjjue6669KvX78Vtu+yyy6ZMWNG6fbrX/+6Scc//fTT06lTp+XWP/vssznggAOyyy675KGHHsrkyZPz29/+NmeeeWaTjg8AAABA82r2kGvBggU56qijctlll6W6unqFfTbYYIPU1NSUbm3btm2y8X/zm99k2rRpOeecc5Zru/XWW9OnT5+ccsop6dGjR/7X//pfOeuss3L11Vfn73//e5PVAAAAAEDzavaQ67jjjsvIkSOz8847f2yf6dOnp1evXhk0aFDGjh2bt99+u0nGnjNnTo4//vhcddVVadmy5XLtH3zwwXLrW7VqlSVLluSpp55qkhoAAAAAaH7NGnJdf/31mTVrVk477bSP7TN06NBceeWVue2223LuuefmL3/5S0aMGJEPPvhgjcZetmxZjjrqqBxzzDEZMGDACvvsvvvu+fOf/5wpU6bko48+yhtvvJGJEycmSebNm7dG4wMAAACw9jRbyDVz5sycffbZufrqq7Peeut9bL/99tsvX/3qV9OvX78MHz48U6dOzcyZM3PPPfessP/s2bPTqVOn0u3CCy9cYb8LL7ww66+/fo499tiPHXu33XbLOeeckxNPPDE1NTUZPHhwhg0bliRp0cIXTwIAAAAURVVzbfixxx5LXV1dhgwZUlq3bNmyPPLII5k8eXLeeOONbLDBBsvdr0OHDunYsWNmzZq1wu126NAh06ZNKy1/3PW7HnzwwUyfPj2bbrppo/VDhw7N17/+9Vx11VVJkmOPPTbHHHNM3nzzzVRXV+e1117LWWedle7du3/SXQYAAACgTJot5Nprr72yzTbbNFp3zDHHpGfPnvne976X9ddff4X3q6ury9y5c1NTU7PC9qqqqvTo0WOV419++eVZvHhxafnNN98shVs77LBDo74VFRXp0KFDkmTq1Knp3Llztt5661WOAQAAAMC6odlCrurq6uW+TfELX/hC2rZtmy233DJJsnDh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hFwAAAAAFJ6QCwAAAIDCE3IBAAAAUHhCLgAAAAAKT8gFAAAAQOFVlbuAImp5+KnlLoEymDlzZmpra8tdBgAAALACzuQCAAAAoPCEXAAAAAAUnpALAAAAgMITcgEAAABQeEIuAAAAAApPyAUAAABA4Qm5AAAAACg8IRcAAAAAhSfkAgAAAKDwhFwAAAAAFJ6QCwAAAIDCE3IBAAAAUHhV5S6giBr+elO5S6AMeiVp+Oufy13GOqGi/8HlLgEAAAAacSYXAAAAAIUn5AIAAACg8IRcAAAAABSekAsAAACAwhNyAQAAAFB4Qi4AAAAACk/IBQAAAEDhCbkAAAAAKDwhFwAAAACFJ+QCAAAAoPCEXAAAAAAUnpALAAAAgMITcgEAAABQeEIuAAAAAApPyAUAAABA4Qm5AAAAACg8IRcAAAAAhSfkAgAAAKDwhFwAAAAAFJ6QCwAAAIDCE3IBAAAAUHhCLgAAAAAKr1Ah14QJE1JdXd3o1rt370Z9XnzxxXzjG99I165d06FDh+y8886ZMWNGmSoGAAAAYG2oKncBn1RtbW3uvPPO0nJlZWXp51deeSV77rlnDjrooNx+++2prq7O//zP/6R169Yfu70BAwbkiiuuyE477dSsdQMAAADQfAoXclVVVaWmpmaFbeeee2522223/OAHPyit6969+1qqDAAAAIByKdTHFZN/nK3Vt2/fbLXVVvnWt76VV155JUlSX1+fu+++O3369Ml+++2Xnj17Ztddd80tt9xS3oIBAAAAaHaFCrkGDx6cK664IlOnTs2ll16aefPmZdiwYXn33Xfz9ttvZ+HChbnooouy66675tZbb81+++2Xo446Kvfcc0+5SwcAAACgGRXq44p77LFHo+XBgwdn4MCBufHGG7PffvslSb761a/m2GOPTZJstdVWeeqpp3LVVVdlzz33TJLsv//+mT59emkbixcvzgEHHNDo2l5z5sxp7l0BAAAAoAkVKuT6d23atEnfvn0za9astGvXLlVVVenTp0+jPr179270kcVLL700S5YsKS3vvffeOfPMMzN48OC1VjcAAAAATavQIdeSJUsyc+bM7LTTTll//fWz7bbbZubMmY36vPjii+nSpUtpuWPHjo3aKysr06FDh/To0WOt1AwAAABA0ytUyHXaaaflK1/5Sjp37px33nkn559/fhYvXpyDDz44STJ27NgcccQR2XHHHbPzzjtn2rRpueWWW3LDDTeUuXIAAAAAmlOhQq433ngj3/72t1NXV5dNN900gwcPzu9///t07do1yT8+enjxxRfnoosuyvjx49OjR49ceeWVpetxAQAAAPDZVKiQa/Lkyavsc+ihh+bQQw9d7W0+++yza1ISAAAAAOuAFuUuAAAAAADWlJALAAAAgMITcgEAAABQeEIuAAAAAApPyAUAAABA4Qm5AAAAACg8IRcAAAAAhSfkAgAAAKDwhFwAAAAAFJ6QCwAAAIDCE3IBAAAAUHhCLgAAAAAKT8gFAAAAQOEJuQAAAAAoPCEXAAAAAIUn5AIAAACg8IRcAAAAABSekAsAAACAwhNyAQAAAFB4Qi4AAAAACq+q3AUUUUX/g8tdAmUwc+bM1NbWlrsMAAAAYAWcyQUAAABA4Qm5AAAAACg8IRcAAAAAhSfkAgAAAKDwKubPn99Q7iIAAAAAYE04kwsAAACAwhNyAQAAAFB4Qi4AAAAACk/IBQAAAEDhCbkAAAAAKDwh12q6+uqrs9VWW6Wmpib/+3//7zzyyCPlLok1dNFFF2XXXXdNly5d0rNnz4waNSrPP/98oz5jxoxJdXV1o9vQoUMb9fnggw9y4oknpkePHunYsWMOOuigzJkzZ23uCp/ChAkTlpvb3r17l9obGhoyYcKE9O3bN5tvvnn22muvvPDCC422MX/+/IwePTpdu3ZN165dM3r06MyfP38t7wmfxoABA5ab/+rq6hx44IFJVn18JKt3jLDuePjhh3PQQQdliy22SHV1dW644YZG7U31mH/uuefy1a9+NZtvvnm22GKLTJw4MQ0Nvsi6nFY29x9++GHOOOOM7LjjjunYsWP69OmTb3/725k9e3ajbey1117L/U341re+1aiP54R116oe/031em/27NkZNWpUOnbsmB49euSkk07K0qVLm33/WLlVzf+KXg9UV1fnhBNOKPXxnqCYVuf9nuf/zx4h12q45ZZbMn78+Bx//PF56KGHsv322+eAAw5Y7gUQxfLHP/4xRx55ZO65557cfvvtqaqqyte+9rW89957jfrtsssumTFjRun261//ulH7ySefnDvuuCPXXHNN7rrrrvz973/PqFGjsmzZsrW5O3wKtbW1jeb2X8PrSy65JJdffnkmTpyY++67L+3bt8++++6bv//976U+3/72t/PMM89k6tSpmTp1ap555pn8x3/8Rzl2hU/o/vvvbzT3Dz74YCoqKvK1r32t1Gdlx0eyescI645FixZlyy23zHnnnZdWrVot194Uj/m//e1v2XfffbPZZpvlvvvuy3nnnZef/OQnueyyy9bKPrJiK5v7xYsX5+mnn84JJ5yQBx98MDfeeGPmzJmT/fffPx999FGjvoceemijvwk//vGPG7V7Tlh3rerxn6z5671ly5Zl1KhRWbhwYe66665cc801uf3223Pqqac2+/6xcqua/3+d9xkzZuSXv/xlkjR6TZB4T1BEq/N+z/P/Z0/F/PnzxYursPvuu6dfv3659NJLS+u23XbbjBw5MmeccUYZK6MpLVy4MF27ds0NN9yQ4cOHJ/nHf23efffdTJkyZYX3WbBgQXr16pXLL7+8dAbI66+/ngEDBmTq1KnZfffd11r9fDITJkzI7bffnunTpy/X1tDQkL59++aoo44q/Rfv/fffT21tbc4555wcccQRmTFjRnbYYYfcfffdGTJkSJJk+vTpGT58eB5//PHU1tau1f1hzVxwwQW59NJLM2PGjLRq1Wqlx0eyescI665OnTrlRz/6UQ499NAkTfeYv+aaa3LmmWfmf/7nf0pvpM4///xMnjw5zz//fCoqKsqzw5T8+9yvyH//939nyJAhefjhh9OvX78k/ziTa8stt8z555+/wvt4TiiOFR0DTfF67/e//30OPPDAPPvss+ncuXOSZMqUKRk7dmxmzpyZjTbaqPl3jlVanb8BY8eOzSOPPJI///nPpXXeE3w2/Pv7Pc//n03O5FqFpUuX5qmnnspuu+3WaP1uu+2WP/3pT2WqiuawcOHC1NfXp7q6utH66dOnp1evXhk0aFDGjh2bt99+u9T21FNP5cMPP2x0fHTu3Dl9+vRxfBTAK6+8kr59+2arrbbKt771rbzyyitJkldffTXz5s1rNK+tWrXKjjvuWJrXxx57LG3atMkOO+xQ6jNkyJC0bt3a3BdMQ0NDfv7zn2fUqFGN/sP7ccdHsnrHCMXRVI/5xx57LF/60pcaHUe777575s6dm1dffXUt7Q1r6p//vf/31wM333xzevTokSFDhuS0005r9F9+zwnFt6av9x577LH06dOnFHAl/3j8f/DBB3nqqafW2n6wZhYuXJhbbrkl3/zmN5dr856g+P79/Z7n/8+mqnIXsK6rq6vLsmXL0r59+0br27dvn7feeqtMVdEcxo8fnwEDBmT77bcvrRs6dGj22WefdOvWLa+99lrOPffcjBgxIg888EA22GCDvPXWW6msrEy7du0abcvxse4bPHhwrrjiitTW1uadd97J+eefn2HDhuXRRx/NvHnzkmSFj/u5c+cmSd566620a9eu0X9mKioqsummm5r7grn//vvz6quv5vDDDy+tW9nxsckmm6zWMUJxNNVj/q233krHjh2X28Y/27p3795cu0ATWbp0aU477bR85StfSadOnUrrDzjggHTp0iWbb755/vu//ztnnXVWnnvuudx6661JPCcUXVO83nvrrbeW+xvSrl27VFZWOgYKZOrUqVm6dGkOPvjgRuu9J/hs+Pf3e57/P5uEXJDklFNOyaOPPpq77747lZWVpfX77bdf6ed+/fpl4MCBGTBgQO65556MGDGiHKXSRPbYY49Gy4MHD87AgQNz4403ZrvttitTVZTD9ddfn2233TYDBgworVvZ8XHssceu7RKBteCjjz7K6NGjs2DBgtx0002N2v7P//k/pZ/79euX7t27Z/fdd89TTz2VgQMHrt1CaXJe7/FP119/fb761a9m0003bbTeMVJ8H/d+j88eH1dchX/+B+ZfT0dNkrfffjubbbZZmaqiKZ188sm5+eabc/vtt68yZe/QoUM6duyYWbNmJUk222yzLFu2LHV1dY36OT6Kp02bNunbt29mzZqVmpqaJFnp436zzTZLXV1do29NaWhoyDvvvGPuC+Ttt9/OXXfdtcKPJfyrfz0+kqzWMUJxNNVjfrPNNlvhNv7Zxrrro48+ypFHHpnnnnsut912WzbZZJOV9t9mm21SWVnZ6PWA54TPjk/zem9Fj/9/fiLEMVAMzzzzTJ588slVviZIvCcomo97v+f5/7NJyLUK66+/fgYOHJj777+/0fr777+/0edyKaZx48aV/uD17t17lf3r6uoyd+7c0h/EgQMHZr311mt0fMyZM6d0gUKKY8mSJZk5c2ZqamrSrVu31NTUNJrXJUuWZPr06aV53X777bNw4cI89thjpT6PPfZYFi1aZO4L5MYbb8wGG2zQ6D+0K/Kvx0eS1TpGKI6mesxvv/32mT59epYsWVLqc//996dDhw7p1q3bWtobPqkPP/wwRxxxRJ577rnccccdpcf5yjz33HNZtmxZqa/nhM+WT/N6b/vtt8+MGTMyZ86cUp/7778/G2ywgbP9CuL6669Pt27dsssuu6yyr/cExbGy93ue/z+bfFxxNRxzzDH5j//4jwwaNCg77LBDJk+enDfffNO3ZxXcCSeckClTpuQXv/hFqqurS5/Jbt26ddq0aZOFCxfmvPPOy4gRI1JTU5PXXnstZ599dtq3b5+99947SbLxxhvnsMMOyxlnnJH27dunbdu2OfXUU9OvX7/VeoKkfP55zZXOnTuXrrm0ePHiHHzwwamoqMiYMWNy0UUXpba2Nr169coFF1yQ1q1bZ//990+S9OnTJ0OHDs1//ud/5uKLL06S/Od//mf23HNP36JVEA0NDfnZz36Wr3/962nTpk2jtpUdH0lW6xhh3bJw4cLSf9zr6+vz+uuv55lnnknbtm3TpUuXJnnM77///pk4cWKOPvronHDCCXnxxRdz8cUX56STTvLNSmW0srnv0KFDvvnNb+bJJ5/MTTfdlIqKitLrgY022iitWrXKyy+/nF/96lcZNmxYNtlkk8yYMSOnnXZattpqq9I3bXlOWLet7Bho27Ztk7ze22233bLFFlvkO9/5Ts4999y89957+f73v5/DDz/cNyuW2ar+/ifJ4sWL8+tf/zpjx45d7u+19wTFtar3e031mt/z/7qlYv78+Q2r7sbVV1+dSy65JPPmzcsWW2yRH/7wh/nyl79c7rJYA//+rUn/NG7cuJx88sl5//33c+ihh+aZZ57JggULUlNTk5122imnnnpqo2/O+eCDD3Laaadl6tSpWbJkSXbeeedceOGFjfqw7vnWt76VRx55JHV1ddl0000zePDgnHrqqenbt2+SfwQg5513Xq677rrMnz8/gwYNygUXXJAtt9yytI358+fnpJNOym9/+9skyfDhw/OjH/3oY48t1i0PPfRQRowYkXvvvTeDBg1q1Laq4yNZvWOEdce0adOyzz77LLf+4IMPzqRJk5rsMf/cc8/lhBNOyBNPPJHq6uocccQRGTdunBe5ZbSyuR8/fny23nrrFd7v8ssvz6GHHprXX389o0ePzgsvvJBFixalU6dOGTZsWMaPH5+2bduW+ntOWHet7Bi46KKLmuz13uzZs3PCCSfkoYceSsuWLXPAAQfknHPOyQYbbLBW9pMVW9Xf/yT5xS9+ke9+97v561//mg4dOjTq5z1Bca3q/V7SdK/5Pf+vO4RcAAAAABSea3IBAAAAUHhCLgAAAAAKT8gFAAAAQOEJuQAAAAAoPCEXAAAAAIUn5AIAAACg8IRcAAAAABSekAsAAACAwhNyAQAAAFB4/x9nBGN4jbN+fgAAAABJRU5ErkJggg==" }, "metadata": {} } ], "metadata": {} }, { "cell_type": "code", "execution_count": 9, "source": [ "# Plot gender of users\r\n", "gender_counts = users['gender'].value_counts()\r\n", "colors1 = ['lightblue', 'pink']\r\n", "pie = go.Pie(labels=gender_counts.index,\r\n", " values=gender_counts.values,\r\n", " marker=dict(colors=colors1),\r\n", " hole=0.5)\r\n", "layout = go.Layout(title='Gender Users', font=dict(size=12), legend=dict(orientation='h'))\r\n", "\r\n", "fig = go.Figure(data=[pie], layout=layout)\r\n", "py.iplot(fig)" ], "outputs": [ { "output_type": "display_data", "data": { "text/html": [ "
" ], "application/vnd.plotly.v1+json": { "config": { "linkText": "Export to plot.ly", "plotlyServerURL": "https://plot.ly", "showLink": false }, "data": [ { "hole": 0.5, "labels": [ "Male", "Female" ], "marker": { "colors": [ "lightblue", "pink" ] }, "type": "pie", "values": [ 4331, 1709 ] } ], "layout": { "font": { "size": 12 }, "legend": { "orientation": "h" }, "template": { "data": { "bar": [ { "error_x": { "color": "#2a3f5f" }, "error_y": { "color": "#2a3f5f" }, "marker": { "line": { "color": "#E5ECF6", "width": 0.5 }, "pattern": { "fillmode": "overlay", "size": 10, "solidity": 0.2 } }, "type": "bar" } ], "barpolar": [ { "marker": { "line": { "color": "#E5ECF6", "width": 0.5 }, "pattern": { "fillmode": "overlay", "size": 10, "solidity": 0.2 } }, "type": "barpolar" } ], "carpet": [ { "aaxis": { "endlinecolor": "#2a3f5f", "gridcolor": "white", "linecolor": "white", "minorgridcolor": "white", "startlinecolor": "#2a3f5f" }, "baxis": { "endlinecolor": "#2a3f5f", "gridcolor": "white", "linecolor": "white", "minorgridcolor": "white", "startlinecolor": "#2a3f5f" }, "type": "carpet" } ], "choropleth": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "type": "choropleth" } ], "contour": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "colorscale": [ [ 0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1, "#f0f921" ] ], "type": "contour" } ], "contourcarpet": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "type": "contourcarpet" } ], "heatmap": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "colorscale": [ [ 0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1, "#f0f921" ] ], "type": "heatmap" } ], "heatmapgl": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "colorscale": [ [ 0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1, "#f0f921" ] ], "type": "heatmapgl" } ], "histogram": [ { "marker": { "pattern": { "fillmode": "overlay", "size": 10, "solidity": 0.2 } }, "type": "histogram" } ], "histogram2d": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "colorscale": [ [ 0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1, "#f0f921" ] ], "type": "histogram2d" } ], "histogram2dcontour": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "colorscale": [ [ 0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1, "#f0f921" ] ], "type": "histogram2dcontour" } ], "mesh3d": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "type": "mesh3d" } ], "parcoords": [ { "line": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "parcoords" } ], "pie": [ { "automargin": true, "type": "pie" } ], "scatter": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scatter" } ], "scatter3d": [ { "line": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scatter3d" } ], "scattercarpet": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scattercarpet" } ], "scattergeo": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scattergeo" } ], "scattergl": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scattergl" } ], "scattermapbox": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scattermapbox" } ], "scatterpolar": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scatterpolar" } ], "scatterpolargl": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scatterpolargl" } ], "scatterternary": [ { "marker": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "type": "scatterternary" } ], "surface": [ { "colorbar": { "outlinewidth": 0, "ticks": "" }, "colorscale": [ [ 0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1, "#f0f921" ] ], "type": "surface" } ], "table": [ { "cells": { "fill": { "color": "#EBF0F8" }, "line": { "color": "white" } }, "header": { "fill": { "color": "#C8D4E3" }, "line": { "color": "white" } }, "type": "table" } ] }, "layout": { "annotationdefaults": { "arrowcolor": "#2a3f5f", "arrowhead": 0, "arrowwidth": 1 }, "autotypenumbers": "strict", "coloraxis": { "colorbar": { "outlinewidth": 0, "ticks": "" } }, "colorscale": { "diverging": [ [ 0, "#8e0152" ], [ 0.1, "#c51b7d" ], [ 0.2, "#de77ae" ], [ 0.3, "#f1b6da" ], [ 0.4, "#fde0ef" ], [ 0.5, "#f7f7f7" ], [ 0.6, "#e6f5d0" ], [ 0.7, "#b8e186" ], [ 0.8, "#7fbc41" ], [ 0.9, "#4d9221" ], [ 1, "#276419" ] ], "sequential": [ [ 0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1, "#f0f921" ] ], "sequentialminus": [ [ 0, "#0d0887" ], [ 0.1111111111111111, "#46039f" ], [ 0.2222222222222222, "#7201a8" ], [ 0.3333333333333333, "#9c179e" ], [ 0.4444444444444444, "#bd3786" ], [ 0.5555555555555556, "#d8576b" ], [ 0.6666666666666666, "#ed7953" ], [ 0.7777777777777778, "#fb9f3a" ], [ 0.8888888888888888, "#fdca26" ], [ 1, "#f0f921" ] ] }, "colorway": [ "#636efa", "#EF553B", "#00cc96", "#ab63fa", "#FFA15A", "#19d3f3", "#FF6692", "#B6E880", "#FF97FF", "#FECB52" ], "font": { "color": "#2a3f5f" }, "geo": { "bgcolor": "white", "lakecolor": "white", "landcolor": "#E5ECF6", "showlakes": true, "showland": true, "subunitcolor": "white" }, "hoverlabel": { "align": "left" }, "hovermode": "closest", "mapbox": { "style": "light" }, "paper_bgcolor": "white", "plot_bgcolor": "#E5ECF6", "polar": { "angularaxis": { "gridcolor": "white", "linecolor": "white", "ticks": "" }, "bgcolor": "#E5ECF6", "radialaxis": { "gridcolor": "white", "linecolor": "white", "ticks": "" } }, "scene": { "xaxis": { "backgroundcolor": "#E5ECF6", "gridcolor": "white", "gridwidth": 2, "linecolor": "white", "showbackground": true, "ticks": "", "zerolinecolor": "white" }, "yaxis": { "backgroundcolor": "#E5ECF6", "gridcolor": "white", "gridwidth": 2, "linecolor": "white", "showbackground": true, "ticks": "", "zerolinecolor": "white" }, "zaxis": { "backgroundcolor": "#E5ECF6", "gridcolor": "white", "gridwidth": 2, "linecolor": "white", "showbackground": true, "ticks": "", "zerolinecolor": "white" } }, "shapedefaults": { "line": { "color": "#2a3f5f" } }, "ternary": { "aaxis": { "gridcolor": "white", "linecolor": "white", "ticks": "" }, "baxis": { "gridcolor": "white", "linecolor": "white", "ticks": "" }, "bgcolor": "#E5ECF6", "caxis": { "gridcolor": "white", "linecolor": "white", "ticks": "" } }, "title": { "x": 0.05 }, "xaxis": { "automargin": true, "gridcolor": "white", "linecolor": "white", "ticks": "", "title": { "standoff": 15 }, "zerolinecolor": "white", "zerolinewidth": 2 }, "yaxis": { "automargin": true, "gridcolor": "white", "linecolor": "white", "ticks": "", "title": { "standoff": 15 }, "zerolinecolor": "white", "zerolinewidth": 2 } } }, "title": { "text": "Gender Users" } } } }, "metadata": {} } ], "metadata": {} }, { "cell_type": "code", "execution_count": 10, "source": [ "# Merge reviews, movie and user dataset\r\n", "final_df = reviews.merge(movies, on='movieId', how='left').merge(users, on='userId', how='left')\r\n", "print('final_df shape:', final_df.shape)\r\n", "final_df.head()" ], "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "final_df shape: (1000209, 9)\n" ] }, { "output_type": "execute_result", "data": { "text/plain": [ " userId movieId rating title \\\n", "0 1 1193 5 One Flew Over the Cuckoo's Nest (1975) \n", "1 1 661 3 James and the Giant Peach (1996) \n", "2 1 914 3 My Fair Lady (1964) \n", "3 1 3408 4 Erin Brockovich (2000) \n", "4 1 2355 5 Bug's Life, A (1998) \n", "\n", " genres release_year gender age occupation \n", "0 Drama 1975 Female Under 18 K-12 student \n", "1 Animation|Children's|Musical 1996 Female Under 18 K-12 student \n", "2 Musical|Romance 1964 Female Under 18 K-12 student \n", "3 Drama 2000 Female Under 18 K-12 student \n", "4 Animation|Children's|Comedy 1998 Female Under 18 K-12 student " ], "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", "
userIdmovieIdratingtitlegenresrelease_yeargenderageoccupation
0111935One Flew Over the Cuckoo's Nest (1975)Drama1975FemaleUnder 18K-12 student
116613James and the Giant Peach (1996)Animation|Children's|Musical1996FemaleUnder 18K-12 student
219143My Fair Lady (1964)Musical|Romance1964FemaleUnder 18K-12 student
3134084Erin Brockovich (2000)Drama2000FemaleUnder 18K-12 student
4123555Bug's Life, A (1998)Animation|Children's|Comedy1998FemaleUnder 18K-12 student
\n", "
" ] }, "metadata": {}, "execution_count": 10 } ], "metadata": {} }, { "cell_type": "code", "execution_count": 39, "source": [ "final_df[final_df['age'] == '18 - 24']['title'].value_counts()[:10].to_frame()" ], "outputs": [ { "output_type": "execute_result", "data": { "text/plain": [ " title\n", "American Beauty (1999) 715\n", "Star Wars: Episode VI - Return of the Jedi (1983) 586\n", "Star Wars: Episode V - The Empire Strikes Back ... 579\n", "Matrix, The (1999) 567\n", "Star Wars: Episode IV - A New Hope (1977) 562\n", "Braveheart (1995) 544\n", "Saving Private Ryan (1998) 543\n", "Jurassic Park (1993) 541\n", "Terminator 2: Judgment Day (1991) 529\n", "Sixth Sense, The (1999) 514" ], "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", "
title
American Beauty (1999)715
Star Wars: Episode VI - Return of the Jedi (1983)586
Star Wars: Episode V - The Empire Strikes Back (1980)579
Matrix, The (1999)567
Star Wars: Episode IV - A New Hope (1977)562
Braveheart (1995)544
Saving Private Ryan (1998)543
Jurassic Park (1993)541
Terminator 2: Judgment Day (1991)529
Sixth Sense, The (1999)514
\n", "
" ] }, "metadata": {}, "execution_count": 39 } ], "metadata": {} }, { "cell_type": "code", "execution_count": 44, "source": [ "# Print movie / user sum\r\n", "n_movies = final_df['movieId'].nunique()\r\n", "n_users = final_df['userId'].nunique()\r\n", "\r\n", "print('Number of movies:', n_movies)\r\n", "print('Number of users:', n_users) " ], "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "Number of movies: 3706\n", "Number of users: 6040\n" ] } ], "metadata": {} }, { "cell_type": "code", "execution_count": 45, "source": [ "# implement SVD with Python SurPRISE, a Python Recommendation Framework\r\n", "\r\n", "from surprise import Reader, Dataset, SVD, SVDpp\r\n", "from surprise import accuracy\r\n", "\r\n", "reader = Reader(rating_scale=(1, 5))\r\n", "dataset = Dataset.load_from_df(final_df[['userId', 'movieId', 'rating']], reader=reader)\r\n", "\r\n", "svd = SVD(n_factors=50)\r\n", "svd_plusplus = SVDpp(n_factors=50)\r\n", "\r\n", "# train with SVD\r\n", "trainset = dataset.build_full_trainset()\r\n", "svd.fit(trainset)\r\n", "# train with SVD++, ATTENTION this take a LONG TIME\r\n", "# svd_plusplus.fit(trainset)\r\n" ], "outputs": [ { "output_type": "error", "ename": "ModuleNotFoundError", "evalue": "No module named 'surprise'", "traceback": [ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[1;31mModuleNotFoundError\u001b[0m Traceback (most recent call last)", "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m\u001b[0m\n\u001b[0;32m 1\u001b[0m \u001b[1;31m# implement SVD with Python SurPRISE, a Python Recommendation Framework\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 2\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 3\u001b[1;33m \u001b[1;32mfrom\u001b[0m \u001b[0msurprise\u001b[0m \u001b[1;32mimport\u001b[0m \u001b[0mReader\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mDataset\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mSVD\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mSVDpp\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 4\u001b[0m \u001b[1;32mfrom\u001b[0m \u001b[0msurprise\u001b[0m \u001b[1;32mimport\u001b[0m \u001b[0maccuracy\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 5\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n", "\u001b[1;31mModuleNotFoundError\u001b[0m: No module named 'surprise'" ] } ], "metadata": {} } ], "metadata": { "orig_nbformat": 4, "language_info": { "name": "python", "version": "3.8.8", "mimetype": "text/x-python", "codemirror_mode": { "name": "ipython", "version": 3 }, "pygments_lexer": "ipython3", "nbconvert_exporter": "python", "file_extension": ".py" }, "kernelspec": { "name": "python3", "display_name": "Python 3.8.8 64-bit" }, "interpreter": { "hash": "53e4db133e7a886bd36ef8c79c0b5519f0af174d53fdba9ad5d5d94e6d9f4b55" } }, "nbformat": 4, "nbformat_minor": 2 }