diff --git a/edsa_recommender.py b/edsa_recommender.py index f1192112..0fb0521d 100644 --- a/edsa_recommender.py +++ b/edsa_recommender.py @@ -39,13 +39,16 @@ # Data Loading title_list = load_movie_titles('resources/data/movies.csv') +raw_movies = pd.read_csv("resources/data/movies.csv") +raw_ratings = pd.read_csv("resources/data/ratings.csv") + # App declaration def main(): # DO NOT REMOVE the 'Recommender System' option below, however, # you are welcome to add more options to enrich your app. - page_options = ["Recommender System","Solution Overview"] + page_options = ["Recommender System", "About The App", "EDA", "Team Information"] # ------------------------------------------------------------------- # ----------- !! THIS CODE MUST NOT BE ALTERED !! ------------------- @@ -100,9 +103,75 @@ def main(): # ------------------------------------------------------------------- # ------------- SAFE FOR ALTERING/EXTENSION ------------------- - if page_selection == "Solution Overview": + #if page_selection == "Solution Overview": + #st.title("Solution Overview") + #st.write("Describe your winning approach on this page") + + if page_selection == "About The App": st.title("Solution Overview") - st.write("Describe your winning approach on this page") + st.info("Predict Overview: EDSA Movie Recommendation 2022") + # You can read a markdown file from supporting resources folder + st.write("""In today’s technology driven world, recommender systems are socially and economically critical to ensure that individuals can make optimised choices surrounding the content they engage with on a daily basis. One application where this is especially true is movie recommendations; where intelligent algorithms can help viewers find great titles from tens of thousands of options. + +The goal is to construct a recommendation algorithm based on content or collaborative filtering, capable of accurately predicting how a user will rate a movie they have not yet viewed, based on their historical preferences. + +Providing an accurate and robust solution to this challenge has immense economic potential, with users of the system being personalised recommendations - generating platform affinity for the streaming services which best facilitates their audience's viewing.""") + + + st.image("resources/imgs/Image_header.png",use_column_width=True) + + st.subheader("Raw data") + if st.checkbox('Show movies data'): # data is hidden if box is unchecked + st.write(raw_movies[['movieId', 'title', 'genres']]) # will write the df to the page + + if st.checkbox('Show ratings data'): # data is hidden if box is unchecked + st.write(raw_ratings[['userId', 'movieId', 'rating', 'timestamp']]) + + + if page_selection == "EDA": + st.title("Explore Data Analysis") + + st.info(""" Exploratory Data Analysis(EDA) allows us to gain a better understanding of our data without having to make any + assumptions. EDA is a necessary component before moving on to the modeling phase since it provides context and + recommendations on how to proceed when creating the proper model. It will also aid in the proper interpretation + of the results. You will not be able to properly comprehend your data unless you use EDA.""") + + st.write("Here are the highlights of our dataset") + st.image("resources/imgs/eda screenshot.png",use_column_width=True) + st.image("resources/imgs/ratings.png",use_column_width=True) + + if page_selection == "Team Information": + title_about = """ +
+

21st Century Tech Solutions

+

We provide tailormade solutions for our clients. We pride ourselves in our ability to provide solution which are specifical designed for your needs.

+ """ + + mission = """ +
+

Our Objective

+

Provide insight from data to provide data driven solutions . 😃

+ """ + + contributors = """ +
+

Members

+

Mandlenkosi Ngidi

+

Sboniso Shandu

+

Anathi Ncayiyana

+

Tsidiso Maselela

+

Peter Selolo

+ + """ + + st.image("resources/imgs/TECHSAV.png",use_column_width=True) + st.markdown(title_about, unsafe_allow_html=True) + st.markdown(mission, unsafe_allow_html=True) + st.markdown(contributors, unsafe_allow_html=True) + + st.info("Github repo url: https://github.com/Sboniso-Shandu/unsupervised-predict-streamlit-template") + st.info("Kaggle submission url: https://www.kaggle.com/competitions/edsa-movie-recommendation-2022/submissions") + st.info("AWS EC2 instance url: ") # You may want to add more sections here for aspects such as an EDA, # or to provide your business pitch. diff --git a/recommendation_predict (2) (1) (3).ipynb b/recommendation_predict (2) (1) (3).ipynb new file mode 100644 index 00000000..39809480 --- /dev/null +++ b/recommendation_predict (2) (1) (3).ipynb @@ -0,0 +1,3450 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Movie Recommender Systems" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "dp_HIsFYlKqd" + }, + "source": [ + "\"Drawing\"" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "yFWoEjjkjzdt" + }, + "source": [ + "

Table_of_Content

\n", + "\n", + "[
1.Introduction
](#Introduction)\n", + "\n", + "[
2.Problem Statement
](#Problem_Statement)\n", + "\n", + "[
3.Importing Packages
](#Importing_Packages)\n", + "\n", + "[
4.Loading the data
](#Loading_the_data)\n", + "\n", + "[
5.Exploratory data analysis
](#Exploratory_data_analysis)\n", + "\n", + "[
6.Data cleaning and Feature engineering
](#Data_cleaning_and_Feature_engineering)\n", + "\n", + "[
7.Modeling
](#.Modeling)\n", + "\n", + "[
8.Model Performance
](#Model_Performance)\n", + "\n", + "[
9.Model Explanation
](#Model_Explanation)\n", + "\n", + "[
10.Conclussion
](#Conclussion)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "t4EmQxyEl8J0" + }, + "source": [ + "# Introduction" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "LZefiTwWl5Sw" + }, + "source": [ + "\n", + "Recommender systems are machine learning systems that help users discover new products and services. Every time you shop online, a recommendation system is guiding you towards the most likely product you might purchase.\n", + "\n", + "Recommender systems are an essential feature in our digital world, as users are often overwhelmed by choice and need help finding what they're looking for. This leads to happier customers and, of course, more sales. Recommender systems are like salesmen who know, based on your history and preferences, what you like.\n", + "\n", + "Recommender systems are so commonplace now that many of us use them without even knowing it. Because we can't possibly look through all the products or content on a website, a recommendation system plays an important role in helping us have a better user experience, while also exposing us to more inventory we might not discover otherwise. \n", + "\n", + "Some examples of recommender systems in action include product recommendations on Amazon, Netflix suggestions for movies and TV shows in your feed, recommended videos on YouTube, music on Spotify, the Facebook newsfeed and Google Ads.\n", + "\n", + "We will be developing a machine learning model that is capable of making movies recommendations for users based on the user's rating of a particular movie." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\"Drawing\"" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Problem_Statement\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Construct a recommendation algorithm based on content or collaborative filtering, capable of accurately predicting how a user will rate a movie they have not yet viewed, based on their historical preferences.\n", + "\n", + "Providing an accurate and robust solution to this challenge has immense economic potential, with users of the system being personalised recommendations - generating platform affinity for the streaming services which best facilitates their audience's viewing." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Version Control\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "we will be using commet to keep track of our experiments\n", + "\n", + "Comet.ml is a Machine Learning experimentation platform which AI researchers and data scientists use to track, compare and explain their ML experiments. It allows ML practitioners to keep track of their databases, history of performed experiments, code modifications and production models.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "id": "Qy0N2yee9pyU" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Requirement already satisfied: comet_ml in /home/explore-student/anaconda3/lib/python3.7/site-packages (3.31.6)\n", + "Requirement already satisfied: wrapt>=1.11.2 in /home/explore-student/anaconda3/lib/python3.7/site-packages (from comet_ml) (1.11.2)\n", + "Requirement already satisfied: dulwich!=0.20.33,>=0.20.6; python_version >= \"3.0\" in /home/explore-student/anaconda3/lib/python3.7/site-packages (from comet_ml) (0.20.45)\n", + "Requirement already satisfied: semantic-version>=2.8.0 in /home/explore-student/anaconda3/lib/python3.7/site-packages (from comet_ml) (2.10.0)\n", + "Requirement already satisfied: everett[ini]>=1.0.1; python_version > \"3.5\" in /home/explore-student/anaconda3/lib/python3.7/site-packages (from comet_ml) (3.0.0)\n", + "Requirement already satisfied: six in /home/explore-student/anaconda3/lib/python3.7/site-packages (from comet_ml) (1.14.0)\n", + "Requirement already satisfied: requests>=2.18.4 in /home/explore-student/anaconda3/lib/python3.7/site-packages (from comet_ml) (2.22.0)\n", + "Requirement already satisfied: wurlitzer>=1.0.2 in /home/explore-student/anaconda3/lib/python3.7/site-packages (from comet_ml) (2.0.0)\n", + "Requirement already satisfied: jsonschema!=3.1.0,>=2.6.0 in /home/explore-student/anaconda3/lib/python3.7/site-packages (from comet_ml) (3.2.0)\n", + "Requirement already satisfied: sentry-sdk>=1.1.0 in /home/explore-student/anaconda3/lib/python3.7/site-packages (from comet_ml) (1.8.0)\n", + "Requirement already satisfied: nvidia-ml-py3>=7.352.0 in /home/explore-student/anaconda3/lib/python3.7/site-packages (from comet_ml) (7.352.0)\n", + "Requirement already satisfied: requests-toolbelt>=0.8.0 in /home/explore-student/anaconda3/lib/python3.7/site-packages (from comet_ml) (0.9.1)\n", + "Requirement already satisfied: websocket-client>=0.55.0 in /home/explore-student/anaconda3/lib/python3.7/site-packages (from comet_ml) (1.3.3)\n", + "Requirement already satisfied: certifi in /home/explore-student/anaconda3/lib/python3.7/site-packages (from dulwich!=0.20.33,>=0.20.6; python_version >= \"3.0\"->comet_ml) (2019.11.28)\n", + "Requirement already satisfied: urllib3>=1.24.1 in /home/explore-student/anaconda3/lib/python3.7/site-packages (from dulwich!=0.20.33,>=0.20.6; python_version >= \"3.0\"->comet_ml) (1.25.8)\n", + "Requirement already satisfied: configobj; extra == \"ini\" in /home/explore-student/anaconda3/lib/python3.7/site-packages (from everett[ini]>=1.0.1; python_version > \"3.5\"->comet_ml) (5.0.6)\n", + "Requirement already satisfied: chardet<3.1.0,>=3.0.2 in /home/explore-student/anaconda3/lib/python3.7/site-packages (from requests>=2.18.4->comet_ml) (3.0.4)\n", + "Requirement already satisfied: idna<2.9,>=2.5 in /home/explore-student/anaconda3/lib/python3.7/site-packages (from requests>=2.18.4->comet_ml) (2.8)\n", + "Requirement already satisfied: attrs>=17.4.0 in /home/explore-student/anaconda3/lib/python3.7/site-packages (from jsonschema!=3.1.0,>=2.6.0->comet_ml) (19.3.0)\n", + "Requirement already satisfied: pyrsistent>=0.14.0 in /home/explore-student/anaconda3/lib/python3.7/site-packages (from jsonschema!=3.1.0,>=2.6.0->comet_ml) (0.15.7)\n", + "Requirement already satisfied: importlib-metadata; python_version < \"3.8\" in /home/explore-student/anaconda3/lib/python3.7/site-packages (from jsonschema!=3.1.0,>=2.6.0->comet_ml) (1.5.0)\n", + "Requirement already satisfied: setuptools in /home/explore-student/anaconda3/lib/python3.7/site-packages (from jsonschema!=3.1.0,>=2.6.0->comet_ml) (45.2.0.post20200210)\n", + "Requirement already satisfied: zipp>=0.5 in /home/explore-student/anaconda3/lib/python3.7/site-packages (from importlib-metadata; python_version < \"3.8\"->jsonschema!=3.1.0,>=2.6.0->comet_ml) (2.2.0)\n" + ] + } + ], + "source": [ + "#install comet ml\n", + "!pip install comet_ml\n" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "id": "CCiDKdwzlJ3d" + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "COMET WARNING: As you are running in a Jupyter environment, you will need to call `experiment.end()` when finished to ensure all metrics and code are logged before exiting.\n", + "COMET INFO: Couldn't find a Git repository in '/home/explore-student/unsupervised_data' nor in any parent directory. You can override where Comet is looking for a Git Patch by setting the configuration `COMET_GIT_DIRECTORY`\n", + "COMET INFO: Experiment is live on comet.ml https://www.comet.com/phillemon/recommendation-systems/21c737be26aa475490e9d5b22174f8fa\n", + "\n" + ] + } + ], + "source": [ + "#import comet\n", + "from comet_ml import Experiment\n", + "\n", + "# Create an experiment with your api key\n", + "experiment = Experiment(\n", + " api_key=\"rOl6aNOtrWiZQfN2Rag8JJNiZ\",\n", + " project_name=\"recommendation-systems\",\n", + " workspace=\"phillemon\",\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "XqNrQCp0AyZk", + "outputId": "760aea5e-6125-4a94-83e1-77cec321d8ba" + }, + "outputs": [], + "source": [ + "#from google.colab import drive\n", + "#drive.mount('/content/drive')" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "Dlx98hlqBnNA", + "outputId": "d3144460-8cb7-42c7-a288-95bc42f174c0" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Requirement already satisfied: surprise in /home/explore-student/anaconda3/lib/python3.7/site-packages (0.1)\r\n", + "Requirement already satisfied: scikit-surprise in /home/explore-student/anaconda3/lib/python3.7/site-packages (from surprise) (1.1.1)\r\n", + "Requirement already satisfied: joblib>=0.11 in /home/explore-student/anaconda3/lib/python3.7/site-packages (from scikit-surprise->surprise) (0.14.1)\r\n", + "Requirement already satisfied: six>=1.10.0 in /home/explore-student/anaconda3/lib/python3.7/site-packages (from scikit-surprise->surprise) (1.14.0)\r\n", + "Requirement already satisfied: scipy>=1.0.0 in /home/explore-student/anaconda3/lib/python3.7/site-packages (from scikit-surprise->surprise) (1.4.1)\r\n", + "Requirement already satisfied: numpy>=1.11.2 in /home/explore-student/anaconda3/lib/python3.7/site-packages (from scikit-surprise->surprise) (1.18.1)\r\n" + ] + } + ], + "source": [ + "#install surprise\n", + "!pip install surprise" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Requirement already satisfied: cufflinks in /home/explore-student/anaconda3/lib/python3.7/site-packages (0.17.3)\n", + "Requirement already satisfied: plotly>=4.1.1 in /home/explore-student/anaconda3/lib/python3.7/site-packages (from cufflinks) (5.9.0)\n", + "Requirement already satisfied: setuptools>=34.4.1 in /home/explore-student/anaconda3/lib/python3.7/site-packages (from cufflinks) (45.2.0.post20200210)\n", + "Requirement already satisfied: six>=1.9.0 in /home/explore-student/anaconda3/lib/python3.7/site-packages (from cufflinks) (1.14.0)\n", + "Requirement already satisfied: pandas>=0.19.2 in /home/explore-student/anaconda3/lib/python3.7/site-packages (from cufflinks) (1.0.1)\n", + "Requirement already satisfied: ipython>=5.3.0 in /home/explore-student/anaconda3/lib/python3.7/site-packages (from cufflinks) (7.12.0)\n", + "Requirement already satisfied: numpy>=1.9.2 in /home/explore-student/anaconda3/lib/python3.7/site-packages (from cufflinks) (1.18.1)\n", + "Requirement already satisfied: ipywidgets>=7.0.0 in /home/explore-student/anaconda3/lib/python3.7/site-packages (from cufflinks) (7.5.1)\n", + "Requirement already satisfied: colorlover>=0.2.1 in /home/explore-student/anaconda3/lib/python3.7/site-packages (from cufflinks) (0.3.0)\n", + "Requirement already satisfied: tenacity>=6.2.0 in /home/explore-student/anaconda3/lib/python3.7/site-packages (from plotly>=4.1.1->cufflinks) (8.0.1)\n", + "Requirement already satisfied: pytz>=2017.2 in /home/explore-student/anaconda3/lib/python3.7/site-packages (from pandas>=0.19.2->cufflinks) (2019.3)\n", + "Requirement already satisfied: python-dateutil>=2.6.1 in /home/explore-student/anaconda3/lib/python3.7/site-packages (from pandas>=0.19.2->cufflinks) (2.8.1)\n", + "Requirement already satisfied: backcall in /home/explore-student/anaconda3/lib/python3.7/site-packages (from ipython>=5.3.0->cufflinks) (0.1.0)\n", + "Requirement already satisfied: pexpect; sys_platform != \"win32\" in /home/explore-student/anaconda3/lib/python3.7/site-packages (from ipython>=5.3.0->cufflinks) (4.8.0)\n", + "Requirement already satisfied: prompt-toolkit!=3.0.0,!=3.0.1,<3.1.0,>=2.0.0 in /home/explore-student/anaconda3/lib/python3.7/site-packages (from ipython>=5.3.0->cufflinks) (3.0.3)\n", + "Requirement already satisfied: decorator in /home/explore-student/anaconda3/lib/python3.7/site-packages (from ipython>=5.3.0->cufflinks) (4.4.1)\n", + "Requirement already satisfied: jedi>=0.10 in /home/explore-student/anaconda3/lib/python3.7/site-packages (from ipython>=5.3.0->cufflinks) (0.14.1)\n", + "Requirement already satisfied: traitlets>=4.2 in /home/explore-student/anaconda3/lib/python3.7/site-packages (from ipython>=5.3.0->cufflinks) (4.3.3)\n", + "Requirement already satisfied: pickleshare in /home/explore-student/anaconda3/lib/python3.7/site-packages (from ipython>=5.3.0->cufflinks) (0.7.5)\n", + "Requirement already satisfied: pygments in /home/explore-student/anaconda3/lib/python3.7/site-packages (from ipython>=5.3.0->cufflinks) (2.5.2)\n", + "Requirement already satisfied: widgetsnbextension~=3.5.0 in /home/explore-student/anaconda3/lib/python3.7/site-packages (from ipywidgets>=7.0.0->cufflinks) (3.5.1)\n", + "Requirement already satisfied: nbformat>=4.2.0 in /home/explore-student/anaconda3/lib/python3.7/site-packages (from ipywidgets>=7.0.0->cufflinks) (5.0.4)\n", + "Requirement already satisfied: ipykernel>=4.5.1 in /home/explore-student/anaconda3/lib/python3.7/site-packages (from ipywidgets>=7.0.0->cufflinks) (5.1.4)\n", + "Requirement already satisfied: ptyprocess>=0.5 in /home/explore-student/anaconda3/lib/python3.7/site-packages (from pexpect; sys_platform != \"win32\"->ipython>=5.3.0->cufflinks) (0.6.0)\n", + "Requirement already satisfied: wcwidth in /home/explore-student/anaconda3/lib/python3.7/site-packages (from prompt-toolkit!=3.0.0,!=3.0.1,<3.1.0,>=2.0.0->ipython>=5.3.0->cufflinks) (0.1.8)\n", + "Requirement already satisfied: parso>=0.5.0 in /home/explore-student/anaconda3/lib/python3.7/site-packages (from jedi>=0.10->ipython>=5.3.0->cufflinks) (0.5.2)\n", + "Requirement already satisfied: ipython-genutils in /home/explore-student/anaconda3/lib/python3.7/site-packages (from traitlets>=4.2->ipython>=5.3.0->cufflinks) (0.2.0)\n", + "Requirement already satisfied: notebook>=4.4.1 in /home/explore-student/anaconda3/lib/python3.7/site-packages (from widgetsnbextension~=3.5.0->ipywidgets>=7.0.0->cufflinks) (6.0.3)\n", + "Requirement already satisfied: jupyter-core in /home/explore-student/anaconda3/lib/python3.7/site-packages (from nbformat>=4.2.0->ipywidgets>=7.0.0->cufflinks) (4.6.1)\n", + "Requirement already satisfied: jsonschema!=2.5.0,>=2.4 in /home/explore-student/anaconda3/lib/python3.7/site-packages (from nbformat>=4.2.0->ipywidgets>=7.0.0->cufflinks) (3.2.0)\n", + "Requirement already satisfied: tornado>=4.2 in /home/explore-student/anaconda3/lib/python3.7/site-packages (from ipykernel>=4.5.1->ipywidgets>=7.0.0->cufflinks) (6.0.3)\n", + "Requirement already satisfied: jupyter-client in /home/explore-student/anaconda3/lib/python3.7/site-packages (from ipykernel>=4.5.1->ipywidgets>=7.0.0->cufflinks) (5.3.4)\n", + "Requirement already satisfied: terminado>=0.8.1 in /home/explore-student/anaconda3/lib/python3.7/site-packages (from notebook>=4.4.1->widgetsnbextension~=3.5.0->ipywidgets>=7.0.0->cufflinks) (0.8.3)\n", + "Requirement already satisfied: Send2Trash in /home/explore-student/anaconda3/lib/python3.7/site-packages (from notebook>=4.4.1->widgetsnbextension~=3.5.0->ipywidgets>=7.0.0->cufflinks) (1.5.0)\n", + "Requirement already satisfied: nbconvert in /home/explore-student/anaconda3/lib/python3.7/site-packages (from notebook>=4.4.1->widgetsnbextension~=3.5.0->ipywidgets>=7.0.0->cufflinks) (5.6.1)\n", + "Requirement already satisfied: prometheus-client in /home/explore-student/anaconda3/lib/python3.7/site-packages (from notebook>=4.4.1->widgetsnbextension~=3.5.0->ipywidgets>=7.0.0->cufflinks) (0.7.1)\n", + "Requirement already satisfied: pyzmq>=17 in /home/explore-student/anaconda3/lib/python3.7/site-packages (from notebook>=4.4.1->widgetsnbextension~=3.5.0->ipywidgets>=7.0.0->cufflinks) (18.1.1)\n", + "Requirement already satisfied: jinja2 in /home/explore-student/anaconda3/lib/python3.7/site-packages (from notebook>=4.4.1->widgetsnbextension~=3.5.0->ipywidgets>=7.0.0->cufflinks) (2.11.1)\n", + "Requirement already satisfied: attrs>=17.4.0 in /home/explore-student/anaconda3/lib/python3.7/site-packages (from jsonschema!=2.5.0,>=2.4->nbformat>=4.2.0->ipywidgets>=7.0.0->cufflinks) (19.3.0)\n", + "Requirement already satisfied: pyrsistent>=0.14.0 in /home/explore-student/anaconda3/lib/python3.7/site-packages (from jsonschema!=2.5.0,>=2.4->nbformat>=4.2.0->ipywidgets>=7.0.0->cufflinks) (0.15.7)\n", + "Requirement already satisfied: importlib-metadata; python_version < \"3.8\" in /home/explore-student/anaconda3/lib/python3.7/site-packages (from jsonschema!=2.5.0,>=2.4->nbformat>=4.2.0->ipywidgets>=7.0.0->cufflinks) (1.5.0)\n", + "Requirement already satisfied: pandocfilters>=1.4.1 in /home/explore-student/anaconda3/lib/python3.7/site-packages (from nbconvert->notebook>=4.4.1->widgetsnbextension~=3.5.0->ipywidgets>=7.0.0->cufflinks) (1.4.2)\n", + "Requirement already satisfied: bleach in /home/explore-student/anaconda3/lib/python3.7/site-packages (from nbconvert->notebook>=4.4.1->widgetsnbextension~=3.5.0->ipywidgets>=7.0.0->cufflinks) (3.1.0)\n", + "Requirement already satisfied: defusedxml in /home/explore-student/anaconda3/lib/python3.7/site-packages (from nbconvert->notebook>=4.4.1->widgetsnbextension~=3.5.0->ipywidgets>=7.0.0->cufflinks) (0.6.0)\n", + "Requirement already satisfied: entrypoints>=0.2.2 in /home/explore-student/anaconda3/lib/python3.7/site-packages (from nbconvert->notebook>=4.4.1->widgetsnbextension~=3.5.0->ipywidgets>=7.0.0->cufflinks) (0.3)\n", + "Requirement already satisfied: mistune<2,>=0.8.1 in /home/explore-student/anaconda3/lib/python3.7/site-packages (from nbconvert->notebook>=4.4.1->widgetsnbextension~=3.5.0->ipywidgets>=7.0.0->cufflinks) (0.8.4)\n", + "Requirement already satisfied: testpath in /home/explore-student/anaconda3/lib/python3.7/site-packages (from nbconvert->notebook>=4.4.1->widgetsnbextension~=3.5.0->ipywidgets>=7.0.0->cufflinks) (0.4.4)\n", + "Requirement already satisfied: MarkupSafe>=0.23 in /home/explore-student/anaconda3/lib/python3.7/site-packages (from jinja2->notebook>=4.4.1->widgetsnbextension~=3.5.0->ipywidgets>=7.0.0->cufflinks) (1.1.1)\n", + "Requirement already satisfied: zipp>=0.5 in /home/explore-student/anaconda3/lib/python3.7/site-packages (from importlib-metadata; python_version < \"3.8\"->jsonschema!=2.5.0,>=2.4->nbformat>=4.2.0->ipywidgets>=7.0.0->cufflinks) (2.2.0)\n", + "Requirement already satisfied: webencodings in /home/explore-student/anaconda3/lib/python3.7/site-packages (from bleach->nbconvert->notebook>=4.4.1->widgetsnbextension~=3.5.0->ipywidgets>=7.0.0->cufflinks) (0.5.1)\n" + ] + } + ], + "source": [ + "#install cufflinks\n", + "!pip install cufflinks\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "a93c7ce8" + }, + "source": [ + "# Importing_Packages" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 17 + }, + "id": "9fbc726e", + "outputId": "1634bcb1-f745-4a87-e05b-5af77abdc271" + }, + "outputs": [ + { + "data": { + "text/html": [ + " \n", + " " + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Importing packages\n", + "\n", + "#Arrays\n", + "import numpy as np\n", + "import pandas as pd\n", + "\n", + "#Visualizations\n", + "import cufflinks as cf\n", + "import matplotlib.pyplot as plt\n", + "import seaborn as sns\n", + "%matplotlib inline\n", + "sns.set(style='whitegrid', palette='muted',\n", + " rc={'figure.figsize': (15,10)})\n", + "from plotly.offline import download_plotlyjs, init_notebook_mode, plot, iplot\n", + "init_notebook_mode(connected=True)\n", + "\n", + "#standardization and Dimensionality reduction\n", + "from sklearn.decomposition import PCA\n", + "from sklearn.preprocessing import StandardScaler\n", + "from sklearn import preprocessing\n", + "\n", + "#Modelling\n", + "from sklearn.model_selection import train_test_split\n", + "from surprise.model_selection import train_test_split\n", + "from surprise.model_selection import GridSearchCV\n", + "from sklearn.ensemble import RandomForestRegressor\n", + "from surprise.model_selection import cross_validate\n", + "from surprise import accuracy\n", + "from surprise import SVD\n", + "from surprise import SVD, NMF\n", + "from surprise import KNNBasic\n", + "from surprise import SlopeOne\n", + "from surprise import Reader, Dataset\n", + "\n", + "# Entity featurization and similarity computation\n", + "from sklearn.metrics.pairwise import cosine_similarity\n", + "from sklearn.feature_extraction.text import TfidfVectorizer\n", + "\n", + "# Libraries used during sorting procedures.\n", + "import operator # <-- Convienient item retrieval during iteration \n", + "import heapq # <-- Efficient sorting of large list\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "28db4191" + }, + "source": [ + "# Loading_the_Data" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [], + "source": [ + "# Loading the dataset and then displaying it\n", + "movies = pd.read_csv('movies.csv')\n", + "train = pd.read_csv('train.csv')\n", + "genome_scores = pd.read_csv('genome_scores.csv')\n", + "genome_tags= pd.read_csv('genome_tags.csv')\n", + "imdb = pd.read_csv('imdb_data.csv')\n", + "test = pd.read_csv('test.csv')\n", + "links = pd.read_csv('links.csv')\n", + "sample_submission = pd.read_csv('sample_submission.csv')\n", + "tags = pd.read_csv('tags.csv')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Exploratory_Data_Analysis\n", + "* non graphical EDA\n", + "* graphical EDA" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Non Graphical EDA\n", + "* Display heading of each data set\n", + "* shape of the data set\n" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "id": "e008a24c" + }, + "outputs": [], + "source": [ + "#defining a function to display the datasets\n", + "\n", + "class display(object):\n", + " \"\"\"Display HTML representation of multiple objects\"\"\"\n", + " template = \"\"\"
\n", + "

{0}

{1}\n", + "
\"\"\"\n", + " def __init__(self, *args):\n", + " self.args = args\n", + " \n", + " def _repr_html_(self):\n", + " return '\\n'.join(self.template.format(a, eval(a)._repr_html_())\n", + " for a in self.args)\n", + " \n", + " def __repr__(self):\n", + " return '\\n\\n'.join(a + '\\n' + repr(eval(a))\n", + " for a in self.args)" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 732 + }, + "id": "e10dfdfa", + "outputId": "5c1107fc-68a8-4b84-af0a-e6b0d9c0c2c0" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "lets take a look at the top 5 rows of all the loaded data sets:\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "

movies.head()

\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \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", + "
\n", + "
\n", + "
\n", + "

train.head()

\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \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
05163576694.01518349992
110634354.51206238739
214679054595.01076215539
3106362322962.01423042565
490413663.0833375837
\n", + "
\n", + "
\n", + "
\n", + "

genome_scores.head()

\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
movieIdtagIdrelevance
0110.02875
1120.02375
2130.06250
3140.07575
4150.14075
\n", + "
\n", + "
\n", + "
\n", + "

genome_tags.head()

\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
tagIdtag
01007
12007 (series)
2318th century
341920s
451930s
\n", + "
\n", + "
\n", + "
\n", + "

imdb.head()

\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
movieIdtitle_castdirectorruntimebudgetplot_keywords
01Tom Hanks|Tim Allen|Don Rickles|Jim Varney|Wal...John Lasseter81.0$30,000,000toy|rivalry|cowboy|cgi animation
12Robin Williams|Jonathan Hyde|Kirsten Dunst|Bra...Jonathan Hensleigh104.0$65,000,000board game|adventurer|fight|game
23Walter Matthau|Jack Lemmon|Sophia Loren|Ann-Ma...Mark Steven Johnson101.0$25,000,000boat|lake|neighbor|rivalry
34Whitney Houston|Angela Bassett|Loretta Devine|...Terry McMillan124.0$16,000,000black american|husband wife relationship|betra...
45Steve Martin|Diane Keaton|Martin Short|Kimberl...Albert Hackett106.0$30,000,000fatherhood|doberman|dog|mansion
\n", + "
\n", + "
\n", + "
\n", + "

links.head()

\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
movieIdimdbIdtmdbId
01114709862.0
121134978844.0
2311322815602.0
3411488531357.0
4511304111862.0
\n", + "
\n", + "
\n", + "
\n", + "

sample_submission.head()

\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Idrating
01_20111.0
11_41441.0
21_57671.0
31_67111.0
41_73181.0
\n", + "
\n", + "
\n", + "
\n", + "

tags.head()

\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
userIdmovieIdtagtimestamp
03260classic1439472355
13260sci-fi1439472256
241732dark comedy1573943598
341732great dialogue1573943604
447569so bad it's good1573943455
\n", + "
\n", + "
\n", + "
\n", + "

test.head()

\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
userIdmovieId
012011
114144
215767
316711
417318
\n", + "
\n", + "
" + ], + "text/plain": [ + "movies.head()\n", + " 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 \n", + "\n", + "train.head()\n", + " userId movieId rating timestamp\n", + "0 5163 57669 4.0 1518349992\n", + "1 106343 5 4.5 1206238739\n", + "2 146790 5459 5.0 1076215539\n", + "3 106362 32296 2.0 1423042565\n", + "4 9041 366 3.0 833375837\n", + "\n", + "genome_scores.head()\n", + " movieId tagId relevance\n", + "0 1 1 0.02875\n", + "1 1 2 0.02375\n", + "2 1 3 0.06250\n", + "3 1 4 0.07575\n", + "4 1 5 0.14075\n", + "\n", + "genome_tags.head()\n", + " tagId tag\n", + "0 1 007\n", + "1 2 007 (series)\n", + "2 3 18th century\n", + "3 4 1920s\n", + "4 5 1930s\n", + "\n", + "imdb.head()\n", + " movieId title_cast \\\n", + "0 1 Tom Hanks|Tim Allen|Don Rickles|Jim Varney|Wal... \n", + "1 2 Robin Williams|Jonathan Hyde|Kirsten Dunst|Bra... \n", + "2 3 Walter Matthau|Jack Lemmon|Sophia Loren|Ann-Ma... \n", + "3 4 Whitney Houston|Angela Bassett|Loretta Devine|... \n", + "4 5 Steve Martin|Diane Keaton|Martin Short|Kimberl... \n", + "\n", + " director runtime budget \\\n", + "0 John Lasseter 81.0 $30,000,000 \n", + "1 Jonathan Hensleigh 104.0 $65,000,000 \n", + "2 Mark Steven Johnson 101.0 $25,000,000 \n", + "3 Terry McMillan 124.0 $16,000,000 \n", + "4 Albert Hackett 106.0 $30,000,000 \n", + "\n", + " plot_keywords \n", + "0 toy|rivalry|cowboy|cgi animation \n", + "1 board game|adventurer|fight|game \n", + "2 boat|lake|neighbor|rivalry \n", + "3 black american|husband wife relationship|betra... \n", + "4 fatherhood|doberman|dog|mansion \n", + "\n", + "links.head()\n", + " movieId imdbId tmdbId\n", + "0 1 114709 862.0\n", + "1 2 113497 8844.0\n", + "2 3 113228 15602.0\n", + "3 4 114885 31357.0\n", + "4 5 113041 11862.0\n", + "\n", + "sample_submission.head()\n", + " Id rating\n", + "0 1_2011 1.0\n", + "1 1_4144 1.0\n", + "2 1_5767 1.0\n", + "3 1_6711 1.0\n", + "4 1_7318 1.0\n", + "\n", + "tags.head()\n", + " userId movieId tag timestamp\n", + "0 3 260 classic 1439472355\n", + "1 3 260 sci-fi 1439472256\n", + "2 4 1732 dark comedy 1573943598\n", + "3 4 1732 great dialogue 1573943604\n", + "4 4 7569 so bad it's good 1573943455\n", + "\n", + "test.head()\n", + " userId movieId\n", + "0 1 2011\n", + "1 1 4144\n", + "2 1 5767\n", + "3 1 6711\n", + "4 1 7318" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#print message\n", + "print(\"lets take a look at the top 5 rows of all the loaded data sets:\")\n", + "\n", + "#we will take a look at the fisrt few coulmns on the loaded data set\n", + "display('movies.head()', 'train.head()', 'genome_scores.head()',\n", + " 'genome_tags.head()'\n", + " , 'imdb.head()', 'links.head()', 'sample_submission.head()',\n", + " 'tags.head()', 'test.head()')\n" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "the dimensions of the movies data set are :(62423, 3)\n" + ] + } + ], + "source": [ + "#Non graphical EDA on movies dataset\n", + "print('the dimensions of the movies data set are :'+str(movies.shape))\n" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "the dimensions of the train data set are :(6420519, 4)\n" + ] + } + ], + "source": [ + "#Non graphical EDA on train dataset\n", + "train.shape\n", + "print('the dimensions of the train data set are :'+str(train.shape))" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "the shape shape of the imdb dataset is :(27278, 6)\n" + ] + } + ], + "source": [ + "#Non graphical EDA on imdb dataset\n", + "print('the shape shape of the imdb dataset is :'+str(imdb.shape))" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "the shape of the test dataset is :(5000019, 2)\n" + ] + } + ], + "source": [ + "#Non graphical EDA on test dataset\n", + "print('the shape of the test dataset is :'+str(test.shape))" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "the shape of the genomescores data set is :(9793557, 3)\n" + ] + } + ], + "source": [ + "#Non graphical EDA on genome_scores\n", + "print('the shape of the genomescores data set is :'+str(genome_scores.shape))" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "the shape of the genome tags data set is :(1128, 2)\n" + ] + } + ], + "source": [ + "#Non graphical eda on genome_tags\n", + "print('the shape of the genome tags data set is :'+str(genome_tags.shape))" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "the shape of the tags dataset is :(1093360, 4)\n" + ] + } + ], + "source": [ + "#Non graphical EDA on tags\n", + "print('the shape of the tags dataset is :'+str(tags.shape))" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "the shape of the links data set is :(62423, 3)\n" + ] + } + ], + "source": [ + "#Non graphical EDA on links\n", + "print('the shape of the links data set is :'+str(links.shape))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "64190e25" + }, + "source": [ + "### merging\n", + "In creating a smaller subset of the given datasets, we merge the train and\n", + "movies dataset since they have almost all the features we need to make recommendations" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 206 + }, + "id": "d5a33ccb", + "outputId": "97773400-dfee-4081-a624-a0f97a43287b" + }, + "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", + "
movieIdtitlegenresuserIdratingtimestamp
01Toy Story (1995)Adventure|Animation|Children|Comedy|Fantasy1588495.0994716786
11Toy Story (1995)Adventure|Animation|Children|Comedy|Fantasy972035.0942683155
21Toy Story (1995)Adventure|Animation|Children|Comedy|Fantasy1618713.0833104576
31Toy Story (1995)Adventure|Animation|Children|Comedy|Fantasy451174.01442256969
41Toy Story (1995)Adventure|Animation|Children|Comedy|Fantasy274315.0849667827
\n", + "
" + ], + "text/plain": [ + " movieId title genres \\\n", + "0 1 Toy Story (1995) Adventure|Animation|Children|Comedy|Fantasy \n", + "1 1 Toy Story (1995) Adventure|Animation|Children|Comedy|Fantasy \n", + "2 1 Toy Story (1995) Adventure|Animation|Children|Comedy|Fantasy \n", + "3 1 Toy Story (1995) Adventure|Animation|Children|Comedy|Fantasy \n", + "4 1 Toy Story (1995) Adventure|Animation|Children|Comedy|Fantasy \n", + "\n", + " userId rating timestamp \n", + "0 158849 5.0 994716786 \n", + "1 97203 5.0 942683155 \n", + "2 161871 3.0 833104576 \n", + "3 45117 4.0 1442256969 \n", + "4 27431 5.0 849667827 " + ] + }, + "execution_count": 19, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#merge the train and movies datasets\n", + "f1=pd.merge(movies, train, on='movieId')\n", + "f1.head()" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "99cab49a", + "outputId": "5f0d80b2-01ec-469e-e57e-49b2ae9d12d1" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "movieId False\n", + "title False\n", + "genres False\n", + "userId False\n", + "rating False\n", + "timestamp False\n", + "dtype: bool" + ] + }, + "execution_count": 20, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#checking for mismatches when we merged\n", + "#Let's double-check whether there were any mismatches here, which we can do by looking for rows with nulls\n", + "f1.isnull().any()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "***Observations:***\n", + "\n", + " it appears that there are no mismatches in our datasets meaning that our datasets are merged correctly " + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "K4styiF4sw3R", + "outputId": "51099dcf-1ac4-488e-8c42-10e97fb9e81a" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "movieId 0\n", + "title 0\n", + "genres 0\n", + "userId 0\n", + "rating 0\n", + "timestamp 0\n", + "dtype: int64" + ] + }, + "execution_count": 21, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#check for null values in the dataset\n", + "f1.isnull().sum()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "***Observations :***\n", + "\n", + " it apears that there are no null values in the merged dataset" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "2DsDMV2yRSoy", + "outputId": "f3ffc178-eea1-42a5-dde5-33ae370d5f07" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "Int64Index: 6420519 entries, 0 to 6420518\n", + "Data columns (total 6 columns):\n", + " # Column Dtype \n", + "--- ------ ----- \n", + " 0 movieId int64 \n", + " 1 title object \n", + " 2 genres object \n", + " 3 userId int64 \n", + " 4 rating float64\n", + " 5 timestamp int64 \n", + "dtypes: float64(1), int64(3), object(2)\n", + "memory usage: 342.9+ MB\n" + ] + } + ], + "source": [ + "#lets take a look at what data types to expect in the merged data\n", + "f1.info()" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "NCHHRAAtRf87", + "outputId": "50b0cf71-ce18-4317-8adc-6ff88f51bbf7" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "the shape of our merged data set is :(6420519, 6)\n" + ] + } + ], + "source": [ + "print('the shape of our merged data set is :'+str(f1.shape))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "***Observations:***\n", + "\n", + " there numerical and non-numerical data types in our data set and the dataset is comprised \n", + " of more than six million raws and onlysix columns.\n", + " This means that a lot of computational power is going ton be required" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "_6B5aMmFPYcM" + }, + "source": [ + "## ***Graphical EDA***" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### exploring the rating feature\n", + "* each rating is measured on a scale of 1 to 5,with a rating of less than 3 meaning that the users disliked the movie\n", + " and a rating of 3 or more meaning that the users liked the movie" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 534 + }, + "id": "tPj1E2q2R7SA", + "outputId": "a260b6d3-d9be-42f1-b13e-a10bde766e80" + }, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAtUAAAFxCAYAAAC81lQOAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4xLjMsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy+AADFEAAAgAElEQVR4nOzde1yUdeL+/2sA8ZSKeEBEy6xAjFIJFc8JBmlouq2HzNZVy8pjLZqoK5jaAbWPmWbaprtpamWl5SGpKNd0U8MzoVmmhoqoIJ5I5XD//vDHfCUYvHUYhrHX8/HoEdzv+577uod78PL2PfdYDMMwBAAAAOCmuTk7AAAAAODqKNUAAACAnSjVAAAAgJ0o1QAAAICdKNUAAACAnSjVAAAAgJ0o1UA59uSTTyogIMBp+4+JiVFAQICOHj1qXXb06FEFBAQoJibGabkk5z83peXw4cMaPny42rVrp4CAAIWEhDg7kmkBAQF68sknnR3jpmzdulUBAQGaM2eO0zKU53PYlX+2gLN4ODsAcKv74x+aFSpU0G233SZfX181bdpUERERat++vdzd3Ut932FhYZKkb775ptQf29FiYmK0cuVKJSYmqkGDBs6O4xB5eXkaPny4jhw5okcffVT16tVTxYoVr7vdH88pNzc3VatWTQEBAerVq5d69eoli8Vidz5XPn/Kgz/DOVySo0ePKjw8XL169dJrr73m7DglcqWsKL8o1UAZGTFihKSrRer8+fP6+eef9dlnn+njjz9WUFCQZs6cqTvvvLPQNvHx8fr999+dEVeS9I9//ENPP/20fHx8nJbBFmc/N6Xh6NGj+uWXX9SnTx9NnTr1hrcvOKdyc3N15MgRff3119q2bZuSk5MVGxtb2nGLWLdunSpXruzw/TjC/fffr3Xr1qlmzZrOjgLgFkGpBsrIyJEjiyw7ffq0pk6dqvXr12vQoEH65JNPVKtWLet4/fr1yzJiEXXr1lXdunWdmsEWZz83peHkyZOSdNPP8R/Pqe3bt2vAgAFatmyZBg0apIYNG9qdsSR33XWXQx/fkSpXruzS+QGUP8ypBpyodu3amjVrllq1aqW0tDTNnz+/0Hhxcy4Nw9DKlSvVr18/hYaG6r777lOnTp00ZMgQrVu3TtL/my967NgxHTt2TAEBAdb/rp0LXTBv8tSpU5o4caI6dOigwMBAffrpp5KKn1N9rYMHD2rYsGFq1aqVmjdvrscff1ybNm0qst6cOXMUEBCgrVu3Fhkrbo52QECAVq5cKUkKDw+3Zi+YjmDruZGk/Px8LV++XI899phatGih5s2b67HHHtOyZcuUn59fZP2C5yAzM1OTJk1S+/btFRQUpEceeUSffPJJscddkuTkZI0cOVJt2rRRUFCQOnfurMmTJ1sL9LX7HTBggCRp7ty51mO0Z47vAw88oMaNG8swDP3444+Fxq5cuaL3339fTz/9tDp37qygoCC1atVKf//73/Xf//630Lo3ev5c69qf9fr16/XXv/5VzZo1U6tWrfTCCy8oPT292Ox79uzR4MGD1aJFCwUHB+vvf/+7du7cafPcSUpK0rPPPquOHTsqKChI7dq1U58+fTR37lxTz5WtOdUF51Vubq7mz5+viIgIBQUFqVOnTpoxY4auXLli6vHNnMMFbnRfBw8eVExMjDp16qSgoCC1bdtW0dHR+vXXX01lK3DlyhW99dZb6tKli4KCghQWFqZZs2bZ3G96errmzp2rfv36qV27dgoKClL79u0VHR2tgwcPFlp3zpw5Cg8PlyStXLmy0DlU8PvlRs7JAvv379c//vEPhYWFKSgoSKGhoerVq5defvll5eTkFHlely5dqj59+ig4OFjNmjVTz5499f777xf6XWAmK2AGV6oBJ3Nzc9OwYcO0bds2rV27VhMmTChxPuysWbO0YMECNWjQQF27dlW1atV06tQp7d27V+vXr1e3bt3k5+enESNG6L333pMkDRw40Lp9YGBgocfLyspS3759VaVKFUVERMhisRS6Wm7L0aNH1a9fP91zzz3q27evTp06pXXr1unpp5/W66+/rm7dut3kM3J1WsPXX3+t/fv3629/+5uqV68uSapWrdp1tx07dqzWrFkjX19f/fWvf5XFYtHXX3+tl156Sdu3b9frr79eZJtz587p8ccfl6enpyIjI3X58mUlJCRowoQJcnNzU69evUzl/vbbb61XjyMjI1W/fn39+OOPWr58uRITE7V8+XLr3NoRI0bo2LFjWrlypVq1aqVWrVpJkvX/N8swDEmSh0fhX+9nz57Vyy+/rBYtWqht27by9vbWqVOn9O2332ro0KGaNm2aevfuLUk3dP7YsmzZMn3zzTcKCwtTy5YttWfPHq1bt0779+/XZ599Jk9PT+u6SUlJGjx4sHJzcxUREaHbb79dBw4c0N/+9jeFhoYWeeyNGzfqmWee0W233aawsDD5+PgoKytLv/76q5YtW2adFmOP6Ohobd++XR06dFCnTp20ceNGvfvuu8rMzNSrr7563e1v5By+kX1t3LhRI0eOVG5urjp37qzbb79d6enp+vLLL7VhwwYtXrxY995773XzGYah559/XomJibr99ts1YMAA5eTk6JNPPtGBAweK3SYpKUn/+te/1Lp1a0VERKhKlSo6cuSIEhIS9M0332j58uVq0qSJpKvn8d/+9jctXrxYTZo0UZcuXayPU3AO3cg5KV0t1H369JHFYlFYWJgaNGigCxcu6LffftPy5cv1/PPPq0KFCpKknJwcPfvss9q0aZPuvPNORUVFqWLFitq6daumTp2q3bt3a8aMGaazAqYYABzK39/f8Pf3L3Gdy5cvG02bNjX8/f2N3377zbp8wIABRbZt1aqV0aFDByM7O7vI42RkZBT6vnPnzkbnzp2vm23s2LFGTk5OkfFx48YZ/v7+RmpqqnVZamqqdbvXXnut0Pp79uwxmjZtaoSEhBjnz5+3Ln/zzTcNf39/Y8uWLUX2UfB448aNu+6+r1Xcc7N69WrD39/f6Nmzp3HhwgXr8osXLxq9evUy/P39jc8//7zY52DChAlGbm6udfnPP/9sBAYGGl27di12/3904cIFo1WrVkaTJk2MH374odDYggULDH9/f2PQoEGFlm/ZssXw9/c33nzzTVP7+GPmP9q2bZvRpEkT49577zXS09MLjV2+fNlIS0srss25c+eMRx55xGjZsqXx+++/Fxozc/4MGDCg0LKCn3WLFi2M/fv3Fxr7xz/+Yfj7+xtr1661LsvLyzMeeughw9/f39iwYUOh9ZctW2Y91mvPnREjRhj+/v7Gvn37imT642vAFlvPfcF51atXL+PMmTPW5RcvXjS6dOliNGnSxDh58qSpfZg9h83uKysrywgJCTFatWpl/Pzzz4Ue68CBA0bz5s2Nnj17msr2+eefG/7+/kafPn2MS5cuWZefOXPGCA8PL/Zne/r06UKv6wL79u0zmjdvbgwZMqTQcluv7QI3ek6++uqrhr+/v/HVV18V2SYrK8vIy8uzfl9wHk6ZMqXQ6zo3N9cYP358kce5XlbADKZ/AOWAp6envLy8JElnzpy57voeHh7F3i3E29v7hvddoUIFjRs3rsiVzeupVq2ahg8fXmjZfffdp+7du+vcuXP66quvbjiLvQqma0RHR6tq1arW5VWqVNHYsWMlSStWrCiyXeXKlTV+/PhCz+ndd9+t4OBgHTx4UBcuXLjuvhMTE5WVlaVu3boVuS3e4MGD5efnp82bN+v48eM3dWzFmTNnjubMmaNZs2bp+eef16BBg2QYhsaNG1dknranp6fq1atX5DGqVaumxx57TGfPntXevXtLLVtx03MKrjpeu58dO3boyJEjat26tTp16lRo/b59+6pRo0Y291HcnVJu5jVQnDFjxlhfk9LVc6h79+7Kz89XcnJyqezjRve1atUqnTt3TqNGjdLdd99d6DHuuece9e7dWykpKfrll1+uu8+CaQ0vvPBCoefRy8tLw4YNK3abWrVq6bbbbiuyvEmTJmrdurW2bt1aZApGSW72nKxUqVKRZTVq1JCb29VKk5+fr/fff1916tQp8rp2d3dXTEyMLBaLVq9ebTorYAbTP4Bywvj//9n+erp3764lS5bokUce0cMPP6yWLVuqRYsWpqZGFMfPz8/UdI8/atq0abF/wLZq1UorV65USkqK6WkTpSUlJUVubm7FTqFo2bKl3N3dtW/fviJjd9xxR7HHUvAH/vnz54sd/+O+JRU7XcHDw0MtW7bUsWPHlJKSUmpvsvzj/GGLxaKXX35Zjz32WLHr//zzz1q4cKF++OEHnTp1SpcvXy40bmu+88247777iizz9fWVdPWf/QsU/DweeOCBIuu7ubkpODhYhw8fLrS8e/fu+vLLL9WnTx917dpVoaGhCg4OLrag3aygoCBT+ctyX7t27ZJ0dRpEcXPvC56ngwcPFindf1TwWinueS9pCtKGDRv0wQcfKDk5WWfOnFFubm6h8TNnztzQG29v5Jzs1q2bFi9erOHDhysyMlJt27ZVcHCwbr/99kLbHDp0SFlZWWrUqJHefvvtYvdbqVKlG56DDlwPpRooBy5fvmz9w/N6V9rGjx+vhg0b6pNPPtE777yjd955Rx4eHurYsaNiYmJ0xx133NC+69Spc1OZa9euXeJyM1d3S9v58+dVo0aNQvN1C3h4eKhmzZrKyMgoMlYw37W4baSrt0E0s2/J9vNZsLxgvdLw008/SZKys7O1a9cuTZw4UXFxcapfv77atGlTaN1du3Zp4MCBysvLU2hoqMLCwnTbbbfJzc1N+/btU2Jiouk34ZlR3F/yCq4YXvsmsYLnw9b5VNxf+CIiIrRgwQItWrRIn376qT788ENJ0r333qvo6Gi1a9fO7vzFnRPF5S8NZveVlZUlSfroo49KfLzs7Ozr7rPgtVIwB/lats7hxYsX6+WXX1aNGjXUtm1b+fr6qnLlytb3Lezfv/+GzqEbPSfvv/9+LV26VPPnz1dCQoI+++wzSdKdd96pESNGKCoqStL/e54OHz5c4htXL168aDorYAalGigHtm/frtzcXNWuXfu6HxLh7u6ugQMHauDAgcrIyND27du1du1arV+/Xr/88ovWrl1bbKm05WY/JOT06dMlLr/2ym7BPoorp6VZMqtVq6azZ88qJyenSFnIzc3VmTNnrnvF2Z59S9KpU6eKHS9YfrP/olCSKlWqqG3btnr77bf1l7/8RTExMVq/fn2he0i//fbbunTpkhYvXqzWrVsX2n7BggVKTEws9VxmFPw8bJ1Pxf0lSJIefPBBPfjgg8rOztbu3bu1YcMGLV++XM8884xWrVp13Su1rqjg3Pnss8+sbwi057FsvVaKO4dzc3M1Z84c1alTR59++mmRq9EFV9FvxM2cky1atNCCBQt05coVJScn67vvvtP777+v6OhoeXt7q23bttbn6aGHHjJ9NxigNDCnGnCy/Px86z9RFlxpMatWrVqKiIjQ7NmzFRoaqt9++63QO/fd3NxMXWW9GSkpKcVejd62bZukq9NDCtSoUUOSlJaWVmR9W/NTr50faVZgYKDy8/OVlJRUZOyHH35QXl5eoVylqeAuAQXHf63c3Fxt375dkhy2f+nq3NbevXvrxIkT+s9//lNo7MiRI/Ly8ipSXqTiM0uOPX8KFDwfBc/PtfLz87Vjx44St69SpYratGmj8ePH65lnnlFOTo42btzokKw36mbO4ZI0a9ZMUvHP1Y1q2rSp8vPzi32s4s6HM2fO6Ny5c2rRokWRQn3x4sUit3CU/t/Vdlvn0M2ckwU8PT0VHBys0aNHa+LEiZJkLeGNGzdW9erVtWvXLtNzvK+XFTCDUg04UUZGhl544QVt27ZN9evX1zPPPFPi+leuXNH3339fZP51Tk6OdfrItVcnvby8lJmZqUuXLpV69vPnz+utt94qtGzv3r1avXq1qlWrpoceesi6/P7775d09c1R187BTEtLK/IY12aXdENv7CuYS/z6668X+rTF33//3Xorvb/+9a+mH+9GdOnSRV5eXlq7dm2Rq3bvvfeeUlNT1bZtW4d/aM2wYcNUsWJFLVq0qNB8XD8/P2VlZWn//v2F1l+xYkWx9xaXHHv+FCiYE7t169Yi9yb+8MMPi8ynlqTvv/++2EwFV7WLeyObM9zMOVySv/zlL6pevbrmzp2rPXv2FBnPz88v9l7wth5Lkt54441C85izsrKKnYdcq1YtVa5cWT/++GOhaRM5OTl6+eWXi32DdfXq1WWxWIr9y7R04+dkUlJSsf+y9cefu4eHhwYMGKBTp05p2rRpxZ4rJ0+eLPSGzutlBcxg+gdQRgreWJSfn2/9mPLt27crJydH999/v2bOnHnd+dSXLl3S3//+d/n5+alZs2aqX7++Ll++rP/97386ePCgwsLCCn1KXJs2bbR371499dRTCgkJkaenp5o0aVLsB1DcqJYtW+rjjz/Wnj17FBwcbL1PdX5+vqZMmVJomkWzZs3UsmVL/fDDD+rdu7dCQ0N1+vRpffvtt2rfvn2xf5C1adNGCxcu1KRJkxQZGakqVaqoevXq1g9MKU737t2VmJioL774Qo888oi6dOline959OhRde3aVT169LD72ItTtWpVvfzyy3r++ec1YMAAPfzww9b7VG/atEl16tTRlClTHLLva/n4+Khv375avHix3n33XUVHR0u6eq/pTZs2qX///tb7mycnJ2v79u2KjIxUQkJCkcdy5PlTwM3NTdOmTdNTTz2lYcOGWe9T/dNPP2nz5s3q2LGjNm7caL3qK0mvvfaajh07platWsnPz08VKlTQjz/+qC1btsjPz0+PPPJIqeWzx82cwyWpWbOm3nzzTQ0fPlx9+vRRmzZtdPfdd8vNzU1paWnauXOnsrKyTN3FJSoqSuvWrdM333yjqKgohYeHKzc3V+vXr9d9992n3377rdD6bm5uevLJJ/XOO++oe/fuCg8PV05OjrZu3aqzZ89a7/5xrapVq6pZs2ZKSkpSdHS07rzzTrm5uSksLExNmjS54XNy0aJF2rx5s1q1aqWGDRuqSpUq+uWXX7Rx40bVqFFDffv2ta47bNgw7d+/Xx988IG+/fZbhYaGysfHRxkZGTpy5Ih27NihF154wTpN6HpZATMo1UAZKZjbV6FCBVWtWlV+fn7q2bOnIiIi1L59+0KlwZbKlStrzJgx2rp1q3bu3Kmvv/5aVatW1e23367JkycXuevDc889p3Pnzunbb7/Vjh07lJeXp169epVKKWrQoIFeeuklzZw5Ux988IGuXLmipk2bavjw4erQoUOR9efNm6fp06crMTFRS5YsUaNGjTR27Fi1a9dOX3zxRZH1O3TooJiYGH300Uf6z3/+o5ycHPn5+V23kPzf//2fWrZsqU8++cT6Bra77rpLgwcP1uOPP273cZekS5cuWrZsmRYsWKBNmzbpwoULql27tvr166dhw4bJx8fHofsv8Mwzz2jFihVasmSJBg4cqNq1a6tjx46aP3++3n77ba1bt07u7u66//77tXjxYqWmphZbqh15/lyrdevWev/99/XGG29ow4YNkq7+RWzx4sXW255d+5e0Z555Rl9//bWSk5P1/fffy2KxqH79+nr22Wc1cOBA63QjZ7vZc7gkbdq00eeff65FixZp06ZNSkpKUoUKFVS3bl2FhoYqMjLS1ONYLBbNnj1b77zzjlauXKn3339fdevW1WOPPabhw4cXe/eW0aNHy9vbWytWrNCHH36oatWqqW3btnr++edtfhLo9OnT9eqrr2rTpk1au3atDMNQvXr11KRJkxs+J/v3768aNWpo9+7d1vPRx8dH/fv316BBg+Tn52ddt0KFCpo3b54+++wzrVy5Uhs2bFB2drZq1qypBg0aaPTo0erevbvprIAZFsPsfbwAAChj/fr10549e5SUlKQqVao4Ow4A2MScagCAU/3+++86d+5ckeWffvqpdu7cqXbt2lGoAZR7TP8AADjV8ePH1atXL7Vt21Z33HGH8vLylJKSou3bt6t69eqKiYlxdkQAuC6mfwAAnOrs2bOaPn269VP1cnJyVLt2bbVp00bPPfdckU/MA4DyiFINAAAA2Ik51aUkNzdXR48eLXQPXgAAAPw5UKpLyYkTJxQeHq4TJ044OwoAAADKGKUaAAAAsBOlGgAAALATpRoAAACwE6UaAAAAsBOlGgAAALATpRoAAACwE6UaAAAAsBOlGgAAALATpRoAAACwE6UaAAAAsBOlGgAAALATpRoAAACwE6UaAAAAsBOlGgAAlJqcnBxnRyg1t9KxwPE8nB0AAADcOipUqKAJEyY4O0apeOWVV5wdAS6EK9UAAACAnSjV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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "#Display a catplot that show how each rating performs\n", + "with sns.axes_style('white'):\n", + " g = sns.catplot(\"rating\", data=f1, aspect=2.0,kind='count')\n", + " g.set_ylabels(\"Total number of ratings ( in millions )\")\n", + " plt.title(\"Distribution of Ratings in the dataset\", fontsize = 20)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "koBZRCNMTzuD" + }, + "source": [ + "**Observations:**\n", + "\n", + "majority of the users gave a recommendation of 4 with fewer individuals giving a rating of less than 3\n", + "this means that there are more more rating for people who love a movie than those who disliked the movie.\n", + "this makes sense because in the real world a person is more likely to come back for more of the product if \n", + "they enjoyed and less likely to find interest in something that does not satisfy them.\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "xdc_AlniMZ-S" + }, + "source": [ + "### Next we will explore each feature of the dataset deeply to see how each movie is rated and also check on the most rated movies" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": { + "id": "j17ERQuSKTOn" + }, + "outputs": [], + "source": [ + "# Get the avarage rating for each movie in the data \n", + "average_ratings= f1.groupby(['movieId','genres']).mean()['rating'].reset_index()" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": { + "id": "XFsnoGobTMF3" + }, + "outputs": [], + "source": [ + "f1 = f1.merge(average_ratings, on = 'movieId')" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 112 + }, + "id": "9gWxLoE2MkcI", + "outputId": "b27eb5ca-a674-4513-9f15-d65033c86908" + }, + "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", + "
movieIdtitlegenres_xuserIdrating_xtimestampgenres_yrating_y
01Toy Story (1995)Adventure|Animation|Children|Comedy|Fantasy1588495.0994716786Adventure|Animation|Children|Comedy|Fantasy3.889255
11Toy Story (1995)Adventure|Animation|Children|Comedy|Fantasy972035.0942683155Adventure|Animation|Children|Comedy|Fantasy3.889255
\n", + "
" + ], + "text/plain": [ + " movieId title genres_x \\\n", + "0 1 Toy Story (1995) Adventure|Animation|Children|Comedy|Fantasy \n", + "1 1 Toy Story (1995) Adventure|Animation|Children|Comedy|Fantasy \n", + "\n", + " userId rating_x timestamp genres_y \\\n", + "0 158849 5.0 994716786 Adventure|Animation|Children|Comedy|Fantasy \n", + "1 97203 5.0 942683155 Adventure|Animation|Children|Comedy|Fantasy \n", + "\n", + " rating_y \n", + "0 3.889255 \n", + "1 3.889255 " + ] + }, + "execution_count": 27, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#verify that the above code is applies we review the fisrt two raws\n", + "f1.head(2)" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 206 + }, + "id": "1oo15s9QTq4d", + "outputId": "ce110735-7e4a-4f72-96a6-377a06f09f36" + }, + "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", + "
movieIdtitlegenresuserIdratingtimestamp
01Toy Story (1995)Adventure|Animation|Children|Comedy|Fantasy1588495.0994716786
11Toy Story (1995)Adventure|Animation|Children|Comedy|Fantasy972035.0942683155
21Toy Story (1995)Adventure|Animation|Children|Comedy|Fantasy1618713.0833104576
31Toy Story (1995)Adventure|Animation|Children|Comedy|Fantasy451174.01442256969
41Toy Story (1995)Adventure|Animation|Children|Comedy|Fantasy274315.0849667827
\n", + "
" + ], + "text/plain": [ + " movieId title genres \\\n", + "0 1 Toy Story (1995) Adventure|Animation|Children|Comedy|Fantasy \n", + "1 1 Toy Story (1995) Adventure|Animation|Children|Comedy|Fantasy \n", + "2 1 Toy Story (1995) Adventure|Animation|Children|Comedy|Fantasy \n", + "3 1 Toy Story (1995) Adventure|Animation|Children|Comedy|Fantasy \n", + "4 1 Toy Story (1995) Adventure|Animation|Children|Comedy|Fantasy \n", + "\n", + " userId rating timestamp \n", + "0 158849 5.0 994716786 \n", + "1 97203 5.0 942683155 \n", + "2 161871 3.0 833104576 \n", + "3 45117 4.0 1442256969 \n", + "4 27431 5.0 849667827 " + ] + }, + "execution_count": 28, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#remove the duplicate features\n", + "f1.drop(columns=['rating_y','genres_y'],inplace=True) # Delete the duplicated columns\n", + "\n", + "f1.rename(columns={'genres_x':'genres','rating_x':'rating'},inplace=True) # Rename the columns\n", + "\n", + "# Show the first 5 observations\n", + "f1.head()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### exploring the genre feature" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array(['Adventure|Animation|Children|Comedy|Fantasy',\n", + " 'Adventure|Children|Fantasy', 'Comedy|Romance', ...,\n", + " 'Animation|Children|Comedy|Fantasy|Horror',\n", + " 'Children|Comedy|Fantasy|Mystery',\n", + " 'Comedy|Horror|Mystery|Sci-Fi|Western'], dtype=object)" + ] + }, + "execution_count": 29, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#display a dataframe of the unique genres\n", + "f1['genres'].unique()\n" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "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", + "
movieIdgenre
01Adventure
11Animation
21Children
31Comedy
41Fantasy
\n", + "
" + ], + "text/plain": [ + " movieId genre\n", + "0 1 Adventure\n", + "1 1 Animation\n", + "2 1 Children\n", + "3 1 Comedy\n", + "4 1 Fantasy" + ] + }, + "execution_count": 30, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#Each movie has got several genres in it separated by '|'\n", + "#This code picks out each genre attached to a movie and adds to a list then converts that to dataframe that matches each genre \n", + "genres = pd.DataFrame(f1['genres'].\n", + " str.split(\"|\"). #removes '|' and splits the genres\n", + " tolist(),\n", + " index=f1['movieId']).stack()\n", + "genres = genres.reset_index([0, 'movieId']) #creates a new idex column\n", + "genres.columns = ['movieId', 'genre']\n", + "genres.head()" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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U8G/Iz548KDGjx+vlJQUeXh4yNnZWadOndKyZcu0adMmffHFF6pdu3aB283N/fffrytXrig5OVlOTk4qW7Zstu0F6SldtGiRpk6dKpvNJkkqWbKkLl++rP3792v//v2KiIjQ559/rgceeCDXNtasWaOxY8fKarWqZMmSysjIUHx8vBYtWqQdO3Zo2bJl8vT0LPB5rl+/XqNHjzbuAU9PT1mtVh06dEiHDh3SihUrtGDBAvn4+BjHeHt7Ky0tTRcvXpTVapWHh0e26+Hq6lrgOkwmk7p06aLQ0FCFh4erQYMG2bZHR0crLi5OlSpVumFbTqZMmaJFixYZbZcsWVJJSUnavXu3du/erdWrV2vOnDnZ7tng4GC9//77WrdunV5//XU5Ozvn2Pbq1aslXf0ioHz58vk+xy1btujVV19VamqqpKvXydXVVfHx8VqxYoUiIyP13nvvqUuXLvluU5KWLl0qm80mFxcXDR06tEDH5mbWrFmaO3eucc+6u7vLarXq6NGjRoifP39+npOdff7555oxY4akq/e81WrV77//rtDQUO3du1cLFy7M9RrbbDaNGDFCmzZtkpOTk0qWLHnD742UlBSNHDlSW7ZsMd7z8vJSUlKSoqOjFR0drcjISH366acqXbp0tmPfeOONbM/ne3h4KD09XSdOnNCJEye0ZcsWtWrVSv/6178KduEA3BHoqQYA3KBFixbGP06zhoDmx8SJE2WxWNS8eXOtWbNGsbGx+umnn3Tw4EGtWbNGL730UrbQEB4enq2HdseOHdn+jB8//obPiI2N1cKFCzVo0CDt3LlTe/fu1c8//5zv3sYsEyZM0L/+9S8tX75c+/fv188//6wFCxaofPnyunDhgl588cUce1XttWPHDo0bN06S9PDDD99wrs8//3y+2tmyZYumTJkim82mNm3aKCoqStHR0dq3b5+mTZsmT09PHT16VMOHD8+x91SSEhMT9cYbb6hLly7aunWrcfyECRPk6uqqX3/9VZ9//nmBz/G///2vXn/9dVksFtWvX1+RkZHat2+fDhw4oE8++UTlypXTqVOn9MILLxgzfEtX74MdO3aoXr16kqSBAwdmuzb169cvcC3S1R5oJycnbdy4MdvnZX1m1j45Tch3rcWLFxuBulevXtq+fbt++uknRUdHa+zYsXJxcdHu3bv15ptvZjuuc+fOcnZ21tmzZ2+YyyDLlStXtGnTJkkqUPg9ePCgXnrpJaWmpqpXr15av369Dhw4oP3792vLli16+umnZbVaNW7cOP3yyy/5bleSdu/eLUmqVauWHnzwwQIdm5NFixZpzpw58vDw0MiRI/Xjjz/q559/1oEDBxQeHq7GjRvr7NmzGjp06A3/nbIcOXJEH3zwgYYMGaKdO3ca1/8///mPpKujCLJGHuTk22+/1ffff6/Ro0frp59+0t69exUdHa3mzZsb+7z++uvasmWLKleurA8++EAxMTGKiYnRgQMHNHfuXFWsWFH79+/XG2+8ka3t6OhohYeHy8nJSaNGjdKePXuM3ym7d+/WggUL1LVrV7u+HAJwZyBUAwBu4OnpqYoVK0q6OpQ3P/755x+dOHFC0tVeverVqxvb3NzcVL16db344ovq1q3bLdWWmpqq5557Tq+99prR22s2mws8OZKzs7MWLlyounXrSrra+9i8eXN9/vnncnV11d9//62wsLBbqrUoZPXUBQQEKDQ01PjvZDab1aVLF2P7/v379d133+XYxuXLl9WxY0e99957xgzj7u7u6tu3rzHUd926dQWubebMmbJarapcubK++OIL1ahRQ5Lk5OSkwMBAzZ8/Xy4uLvrzzz+L5dqWL19ejRs3VmpqarbJ61JSUrRx40Y5OTndNMheuXLF+OKnU6dOeuedd4zZuD08PDRgwABjePb69euzBdgHHnhATZo0kSRFRkbm2H5UVJRSUlJUokQJPfnkk/k+t3feeUdWq1XDhg3TO++8Ix8fH+OLsPLly+utt97Ss88+q/T0dH3yySf5bjc9PV1xcXGSpJo1a+b7uNwkJibqo48+kslk0pw5czRkyBDj+jk7O8vPz08LFixQ7dq1lZCQoOXLl+fYzqVLlzRs2DC9+uqrxt97Ly8vDR8+XE888YSkvO/Z1NRUjRkzRgMHDjRGE3h6ehqjObZu3aqoqCiVK1dOX331lTp16mTs5+bmpjZt2mjx4sXy8PBQVFSUDh8+bLS9f/9+SVLTpk01ePBglSlTxtjm7e2t5s2ba+rUqYXyBQWA2xOhGgCQo6zhjfl9vtbT09MYTnn27Nkiq8vJyUmDBw++5XZ69+6t++6774b3fXx8jHCzfv36W/6cwnTkyBHjOdlhw4blONQ1MDDQ+KIgr5CR27DerHWeT5w4YUwclh+XLl3Sjz/+KEl6/vnnc1zOrFatWmrXrt1NaytMWV/iXPvs7IYNG5SamqqmTZvedNmyHTt2GPMKvPjiiznu8/TTTxtB8frzCg4OlnQ1POc08iErbLdt2zbXxx2ud+TIEf3yyy9ydXXVwIEDc90v6wuDXbt25Tpq4XrXzqFw/RDna02YMEHNmjW74c/112jNmjW6fPmy/Pz8jC8Yrufi4qJOnTpJknEPXc9sNud6rln37NGjR3Ott3Tp0urVq1eu27PCfFBQUK7h96GHHlKjRo0kSdu3bzfeL1WqlKSrXyDk9zoDuLvwTDUAIEdZzz7mV4kSJdSkSRPt2LFDgwYNUu/evfX444+rZs2aMpvNhVZXpUqVcgzDBdW4ceM8t61du1ZHjx6V1Wq9bYZtxsbGSroaQvKaEKpp06Y6ePCgsf/1ypQpo8qVK+e47drnsC9dupTvtb7/+9//GvdM06ZNc92vWbNm2rBhQ7Fd23bt2qlUqVLGM9RVqlQxhn7nZ9RE1jV8+OGHc12f3dnZWY0bNzYeebj+8z09PZWSkqJvv/0222MK586d086dOyX9L3znR0xMjCQpMzNT7du3z3W/rICXmpqqCxcuFMrfmyxJSUk6d+7cDe9f/yVcVq2//vqrmjVrlmt7V65ckaRsE7Vd69FHH831Gf+sezavLwDr1KmT5++hrDq/+eabXEcVSFfP+/o6mzZtKjc3Nx06dEh9+/ZVt27d1LhxY2MUCYC7Hz3VAIAcXbp0SZKyDWW8mffee081atRQYmKi5s6dq549e6p+/frq06ePPv/88xtmErdHYQWDvIZiZm1LT0+/5ZmwC1PWDMne3t55BoSsNZ7/+eefHLfnNQHZtb3fec10nFtt0u11bd3c3Ixl4lauXKm4uDjt27dPpUuXVtu2bW96fNY1vNnQ3dyuubu7uzHy4fqwtnbtWqWnp6tcuXJ5Bs7rnTlzRtLV0Hzu3Llc/1y77nZ+Rx1c+/c9r/8+M2fONCYZO3r0qLGEWW61XrlyJc9as3rxs8L19fJzz6anp+e6z/UTA17LarUa1yrry4Lc/mTN4H1tnRUrVtR7770nDw8P7d+/X+PHj1fbtm3VpEkTvfzyy4qKiirwl5QA7iz0VAMAbpCSkqKTJ09KutoznF/ly5fXypUrtWPHDm3btk379u3T0aNHtW/fPu3bt0/z58/Xxx9/nOsw0PzIbXbfgrrZ5FR3g9v9HIurvpCQEH399ddatWqVEbw6depUoBEU+a01p/2CgoIUERGhvXv36tSpU8aQ86xZv7MmNMuvrB7oatWqacOGDfk+Lj9cXFxUpUoVxcXFZXtu2F6ZmZmSrj5uMXHixFtuz155Xd+sGqWrXxZ06NChwO0HBQWpZcuW2rhxozFR2alTp7RhwwZt2LBBDRo00KeffprvIf4A7iz0VAMAbrB9+3bjH+55DTPOiZOTk1q0aKHx48crIiJCe/bs0YwZM1S+fHldvHhRo0aNynUd5eKUkJCQ67asdapdXFyyPVea9Q/zvNabLcwZw6+X1dt2/vz5PK9h1rnl1TtX2K79rPxe26xnUYta3bp1Vb16dSUkJOjLL7+UlP+1qbNGRpw6dSrP/fK65o0bN1b58uWVmZmpNWvWSJJ+++03/fe//5VUsKHf0v+Wnjt58qSxnFZhyno04tChQ7mu2Z5fWbUeO3bslusqKm5ubipZsqSkvJ/LvpkyZcqod+/emjlzprZu3arvvvtOQ4YMkclkUnR0dLaVDgDcXQjVAIBsLBaLPv30U0lX14LNzxDZvHh5ealz586aNGmSpKvPkV77D+xr14otziGSe/bsuek2X1/fbM/8ZgXsf/75J9dQe+DAgVzbzTpXe8/Tz89P0tVhrnv37s11v127dkm6+hxpcaldu7Zxflmfn5OsZ4ivv7ZFLStEW61W+fr6GtfyZrL2S0hI0B9//JHjPhkZGcY9k9M1N5lM6ty5s6T/DQHP+l9fX19jlvT8ylpizGq15jrD+614+umnZTKZCjxzeE6yaj1w4ID++uuvwiivSGTVuXHjxmw917eiUqVKGjlypDEJW9a9D+DuQ6gGABiuXLmisWPH6tChQ5KkIUOG5Ls38Wa9z25ubsbP1w7FvHY4ZNZz3MUhLCws23PAWX7//Xdj3eCnnnoq27as8GOz2XIMM1euXDHWM85J1rnae541atTQI488Ikn65JNPcpxpeNu2bUawz3qWuDiUKlXKWPN3wYIFOT7De+TIEX377beSZASN4hIcHKyBAwdq4MCBGjlyZL6Pa9asmfGc8ezZs3PcJywszHh2OLdrntUb/dtvv+mXX34xeqwLsjZ1ljp16qhWrVqSpI8++ijH+/haBZ3LwNfX15jE7euvv9bixYsLXGOW4OBglShRQhkZGXrnnXfynB07MzOzWH8HXKtnz56SpLi4uJuu0Z6amprt993NfveVKFFCUvYvEAHcXfjbDQD3uMzMTB07dkwLFy5Ux44dtXbtWklX/zFckKWr9u/fr86dO2vRokU6fvy40dtjs9m0b98+vf3225KuTuh07RrWVapUMXosly9fXmy91enp6Ro4cKAOHjxo1Llz504NGjRIFotFDz/8sPr06ZPtmIceekgBAQGSrq7FvXPnTiMkxMbGasCAAXkGnEcffVTS1SHi9i7XNWrUKElSdHS0hg8fbjz7brVatXr1ar366quSpHr16t3yKIOCeuWVV+Tq6qoTJ07o+eefN4bSZmZmatu2bRo8eLDS09NVqVKlPJc3Kgply5bV6NGjNXr0aLVq1Srfx5UoUUIvvfSSpKsTi02YMMGY9fry5cv66quvNGXKFElShw4dcu0B9/HxMba9/fbbOnXqlJydne36csFkMmnixIkym836+++/1aNHD23cuDHbFxmnT59WZGSknnvuOWPt8oKYMGGCGjZsKEl699139fzzz2vz5s3G7NfS1f+uf/zxhz7//HNt27Ytx3bKlStnfImxdetWPffcc4qJiTH+3thsNh0/flwLFy5Up06dtGXLlgLXWhjatm1rLPf2wQcf6K233so2MsFisejAgQOaPn26Wrdune3v+TvvvKMRI0Zo06ZN2SaqS0lJMZ7ll1Sg+w7AnYWJygDgHnPtLMMWi0XJycnZhjt6e3vr5ZdfVu/evQvc9rFjxzRlyhRNmTJFrq6u8vT0VHJysjE5lJeXlz744INsPdXu7u4KDg7WihUrNH36dM2ePVve3t4ymUx68sknNXr06Fs429y98847Gj9+vHr06CEPDw/ZbDYjlJQqVUqhoaE5Tir05ptvqm/fvjp79qyee+45ubm5ydnZWampqbr//vv1/vvva8iQITl+ZuXKldWkSRPt2rVLr7zyisaPH2/0gvbr108DBgy4ad2tW7fW2LFjNXXqVEVFRSkqKkqlSpXS5cuXjdm6q1evro8//rjQJnXLr1q1aun999/X66+/rpiYGAUFBcnLy0tWq9V4Dv3hhx/WvHnz8pzN+XbzzDPP6OTJk1q0aJGWLVumb775RqVKlVJKSopxbzdq1Ejvvvtunu106dJFsbGxxrJbTZo0ybaEWUHUrVtX8+bN06uvvqr4+HiNGDFCzs7OKlmy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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "#Plotting out the distribution of genres.\n", + "fig, ax = plt.subplots(figsize=(15, 10))\n", + "sns.countplot(y='genre',\n", + " data=genres,\n", + " palette='CMRmap',\n", + " order=genres['genre'].\n", + " value_counts().index)\n", + "plt.xticks(rotation=90)\n", + "plt.xlabel('Count', size=20)\n", + "plt.ylabel('Genre', size=20)\n", + "plt.title('Distribution of Movie Genres', size=25)\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Observations:**\n", + "\n", + " Drama is the most popular genre followed by comedy and action" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### exploring the title feature" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "metadata": { + "id": "rYLSrZpdXpsc" + }, + "outputs": [], + "source": [ + "#Function to get the first top 10 movie titles by ratings\n", + "def plot_by_ratings(df,column, n):\n", + " plt.figure(figsize=(10,6))\n", + " data = df[str(column)].value_counts().head(n)\n", + " ax = sns.barplot(x = data, order= data.index, y = data.index, palette='rocket', edgecolor=\"black\")\n", + " for p in ax.patches:\n", + " ax.text(p.get_x() + p.get_width()/2., p.get_height(), '%d' % int(p.get_height()), fontsize=11, ha='center', va='bottom')\n", + " plt.title(f'Top {n} {column.title()} by Number of Ratings', fontsize=14)\n", + " plt.xlabel('Number of ratings')\n", + " plt.ylabel('Movie Title')\n", + " plt.xticks(rotation=90)\n", + " plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 436 + }, + "id": "i5ivXtHCYuTW", + "outputId": "4b2797be-1301-4f6f-cd83-4fd7ef92fdf4" + }, + "outputs": [ + { + "data": { + "image/png": "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0KxZM55//nnT9c8//1zsd307Fy9epFevXuTk5AAQGhqKj48PHh4exMXFmdX99ttvCQoKwt/fn379+nHmzJlileVZsmSJWbvJycn06NGDrKysUo9DRERE5EFiU9YBlIVLly4xZcoUIiIicHV1xWg0cvz48bIOq8xMmDCBtm3bcunSJXx9fXnuued4+umnyzqsIkVERFChQgXc3NwAaNeuHe3atbsnfXXt2pWuXbsC8O677+Ll5UW/fv3uej9Lly6lX79+WFnl/jtFu3bt6N+/P3379jWr9+eff/LOO+/wxRdf4ObmRmRkJJMnT2bVqlVFluU5evQoP/30E9WqVTPdc3Fx4emnnyYyMtI0VhERERFLYJEzRElJSdjY2ODs7AyAwWDgySefNKuzZs0aunbtSrt27di1a5fp/qhRowgODsbf35833niDP//8E4CRI0eyc+dOAFasWIG3tzfZ2dkA+Pr6kpCQwIkTJ+jZsycvvfQSXbp0MfuQevHiRQYNGkSnTp147bXX+OuvvwCIiYmhZ8+eBAYG4u/vz/bt203PhISEEBoaSu/evWnXrh1z5swpcLzbt2+na9euJCYmFvleKleujJubG+fPnzfdi4iIoHv37gQHB9O/f39OnDgBQEZGBhMnTqRjx47079+fw4cPm7W1YsUKunXrRlBQEIMHD+by5ctA7mzYiBEjGDRoEO3bt2f48OH88ssv9O/fnxdffNFslickJITp06cTEhJC+/btmTdvHpA7YxMbG8u0adMICAhgz549+Waoli9fTpcuXejSpQtjx441zfgtXryYkSNHFviuS2P//v0F/hwuXbrEsGHD6NatG/7+/ixbtqzA59PT0/nqq69o37696V7Tpk1xdXXNV/fUqVNUrFjRlAy2adOG6OhokpOTiyyD3J/b1KlTmTRpEgaDwazdLl268OWXX5buRYiIiIg8YCwyIapfvz4NGzbkhRdeYNiwYXz66adcuXLFrI6TkxPh4eHMmjWLadOmme6PHz+eTZs2sXXrVurWrcuKFSsAaNGiBTExMQDs3buXevXqceTIES5dukRaWhpubm6EhYXx/PPPs2XLFrZt20a3bt1M7cbGxjJ37lx27txJVlYWW7duBcDT05OwsDA2b97M6tWrCQ0NNSVhABcuXGDt2rVs3ryZL7/8kpMnT5qNY8WKFXz55Zd8+umnVK1a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ly6kpKSQk5Nj+i6i+yU5OZmePXsWOxkSEREReVgoIZK/rTVr1pR1CPfdvfjC1+JwcXExLesTERERsSQWeaiCiIiIiIgIKCESERERERELpoRIREREREQslhIiERERERGxWEqIRERERETEYumUOREpldNJv3Lh4oWyDkNEREQeQFWrupZ1CEqIRKR0EhIS8n3BmSU4cOAA3t7eZR1GmdDYNXZLo7Fb5tjBssdvSWPXkjkREREREbFYSohERERERMRiacmciIhIMSQkJDBx4kSysrJwcHAgIyODc+fOAVC7dm0WLFhArVq1itXOu+++S0pKCs7OzoSGhhbruZK0UVA9o9FYqv4L6/vW+0OHDmXx4sWlGqeIyP2gGSIREZFimDRpEh06dGDXrl1kZmZy/vx53n//fd5//30yMjKYOHFisdvp06cPu3btok+fPsV+riRtFFSvtP0X9vyt90eMGFHqcYqI3A9KiERERG7jjz/+4JdffqFly5b88ccfJCYmcuPGDVq2bEmXLl24dOkSsbGxJCcnF6udLl26ANClSxd++eWX2z5XkjYKqnf06FFiY2NL3H9hff/+++9m91u0aMHVq1dp2bJliccpInK/aMmciJSKm5sbFy7o2G15uNnb21O1alWaNWuGvb09rq6u2NjYUKNGDdLT06lZsyYGg4Fq1aqRnp5+23ZsbP7///zWrFnzts+VpI2C6uUtWStp/4X13aRJE1xcXEz37e3tqVGjhun9lGScIvJwcK3qyvkL58s6jCIZjEajsayDEJEHT3p6OrGxsUz/1wdcuXylrMMRuacyyCDF5gqVs6qQQQZXbJLJJpuKWZWww45LNhcxYqRClgt22BWrnTyXbC7inFWhyOdK0kZB9S7aJAJQJatqifovrG+nLCdSbVJN9zPIIMnmsun9lGScIvJw+DbhG/4O6Ube5xYvL698XxeiJXMiIiK3YY012WRjxGj6O4AVVhgxkv3//mONdbHbAUzP3u65krRRUL0cckrVf2F922Jndt/q/328yPu/JRmniMj9ooRIRETkNqyxxtZoy1+Gv7DGGmtj7gf7DENG7j2jNXZGu2IlRHntAPxl+Atbo+0dJ0TFaaOwenZGuxL3X1ibttia3c8wZGDAQIYho8TjFBG5X7SHSEREpBj+ke1MivUVrhmuYjAasDZak2Kdu1zUxmiDc7bzHbdj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iMjDQDNEIiIiIiJisZQQiYiIiIiIxVJCJCIiIiIiFksJkYiIiIiIWCwlRCIiIiIiYrGUEImIiIiIiMXSsdsiUiob43dx4cKFsg5DRERE7pNqrtXKOoS7SgmRiJRKQkJCmX2hbFk6cOAA3t7eZR1GmdDYNXZLo7Fb5tjBssdvSWPXkjkREREREbFYSohERERERMRiKSESERERERGLpYRIREREREQslg5VEJFScXNz0ylzIiIi98njrtU4e/5cWYfxUFFCJCKlMso9gL9crpZ1GCIiIhbhvaNhZR3CQ0dL5kRERERExGIpIRIREREREYulhEhERERERCyWEiIREREREbFYSohERERERMRiKSESERERERGLpYRIREREREQslhIiERERERGxWEqISmHnzp0EBgYSEBBAp06dGDVqlKksICCAGzduAODj40NcXFxZhXlbV65coVevXgQEBLBy5UqzsqtXr7JixQqzeyEhIXzzzTel6nPfvn0EBweXqo2i3I0Y83Tv3p2AgAB8fX3x9PQkICCAgIAAxo4de1fH8cEHH/DVV18BcOzYMXr16sXTTz/NsGHDzOqlpaUxZswY/P396dSpE6tWrSpWWVFtrl27lo8//viujENERETkQWJT1gE8qC5dusSUKVOIiIjA1dUVo9HI8ePHTeWRkZFlGN2diYmJoXz58nzxxRf5yq5evcrKlSsZNGhQGUT29/Dll18CcPbsWbp27Wr2s923b99d6SMxMZGYmBjGjh0LgIuLC2PHjuXYsWPs2bPHrO7HH3+Mra0tW7Zs4a+//qJXr154e3vTqFGjIsuKarNHjx507tyZvn374uTkdFfGJCIiIvIgUEJUQklJSdjY2ODs7AyAwWDgySefNJV7eHhw8OBBHB0dzZ67dOkS06ZN4/z586Snp+Pn58fgwYOB3JmkgIAA9uzZw+XLlxkwYAD9+vUDID4+nunTp3P58mUABgwYQFBQUJHt3Sw7O5s5c+bw/fffA9C6dWtGjx7Njz/+yKxZs0hNTSUgIID33nuPpk2bmp6bOnUq165dIyAggEceecSUNO3fv5/ly5dz6dIlOnfuzOjRo287vuK4fPkyI0eOJC0tjfT0dNq0acOYMWMAWLx4MSdOnCA1NZWTJ0/SoEEDXnvtNWbOnMn58+dp374977zzjqmtPXv28Mknn5CYmEjnzp0ZOXIkAEuWLGHbtm3Y29tjMBj47LPPKF++fLFjLOjdTpw4kUOHDmEwGJg/fz516tQBICIigrCwMLKzs3FycmLy5MnUrl07Xxvh4eF07NgRg8EAQJUqVahSpQrx8fH56h4/fpygoCAMBgOPPvoozZo1Y+vWrTRq1KjIsqLatLW15bnnnmPHjh306NGjxO9CRERE5EGjhKiE6tevT8OGDXnhhRdo3rw5TZo0ISAggAoVKhT53DvvvMO//vUvnnnmGTIyMnjllVd46qmneO655wC4ceMG69ev5+zZs/j7+xMUFIS9vT3/+te/GD58OJ07dwZyl7kVp70869ev59ixY2zatAmAQYMGsX79evr06cOwYcP49ttvWbRoUb54J06cmG9WBODChQusXbuWtLQ0XnzxRbp160atWrWKHU9hypcvz7Jly3B0dCQzM5OBAweye/dunn/+eQCOHj1KeHg4jz76KEFBQcydO5eVK1eSlZVFu3bt6NmzJ7Vq1QJyk8jVq1eTnp5Or169aNy4MU2aNGHVqlXExMTg4OBAamoqDg4OxYqtML///jszZsxg6tSpfPTRRyxdupS5c+fyv//9j507d7J27Vrs7Oz47rvvGDduXIEzcfv372fgwIHF6q9Bgwbs2rWLF198kWvXrvH999/j5uZ227Lbady4Md99950SIhEREbEoSohKyMrKiqVLlxIXF8ePP/7I119/zapVq9i6datp1uhW169fZ//+/SQnJ5vupaWlER8fb0oYfH19AahevTrly5cnMTGRnJwcsrKyTMkQQIUKFYrVXp6YmBiCgoKws7MDIDg4mK+//po+ffqUaPydOnXCysqKcuXKUadOHU6fPk3lypWLHU9hsrOzmTVrFocOHcJoNJKUlMTx48dNCVGrVq0oV64ckDsLV79+fezs7LCzs8PNzY3Tp0+bEqLAwEBsbGywsbHB19eXvXv38vzzz+Pm5sbbb79N69ateeGFF0q9RMzNzQ1PT08AGjVqZNq7FBUVxfHjx+nevTsARqORq1evFthGYmIiFStWLFZ/r732GrNmzaJr1664uLjQvHlzU4JcVNntVKxYkcTExGLVFREREXlYKCEqJXd3d9zd3enbty++vr7s37+fDh06FFg3JycHg8HAxo0bsbW1LbCOvb296e/W1tZkZ2cX2ndx2stjNBpNy7Hy3Hp9JwqK807iKczq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oQPR0dE0b94cgP/973+MHDmS1NRUjEYj27dvZ/r06bRu3ZrDhw8zffp0rKysqFChAsuWLeORRx4BKHGZ0Whk7969DB48+K6NX0RERORBYDDefJb2LZo0acLBgwfvZzwiZeLo0aOEhYWV6oju0khNTaV37958+eWXZbJs7fvvv2fLli13NBucnp5ObGws8SNXkZl09R5GJyIiYhn6/bKWIj6a31cHDhzA29u7rMO4a/I+t3h5eZltd4BifjGryMOuQYMGZZYMATg5OfHuu+9y9uzZMuk/NTWV0aNHl0nfIiIiImWpyFPmMjIyWLhwYZENvPXWW3c1IBFLVZbHXXfu3LnM+hYREREpS7c9dvtuncQlIiIiIiLyd1NkQmRnZ8eMGTPuVywiIiIiIiL3VZF7iP4um7pERERERETuhSIToqZNm96vOERERERERO67IhOiFStW3K8401FdAQAAIABJREFURERERERE7jsduy0iIiIiIhbrtqfMiYgUZfhvm7lw4UJZhyEiIvLAq+5araxDsEhKiESkVBISEvJ947MleNi+wftOaOwau6XR2C1z7KDxW4piJ0Q//PAD27dvJzk5mWXLlnHkyBFSU1Np0eL/snfn4TWd6//H3zszMddMWlMT00EQaiZVgsSOoKIVQ3wpWlRRGi2l1NRqSZv2aFUHRc1pKO1pndZQUw0/dQ5VQ4kpaEwJCUn27w9X1pFm2miyyfq8rutcZ+/1rOF+9k63da/nWfdqlpfxiYiIiIiI5Bm77iH64osveP3116lSpQq7du0CwMPDg7lz5+ZpcCIiIiIiInnJroTos88+Y+HChQwePBgnp9ubVKtWjePHj+dpcCIiIiIiInnJroQoMTGRChUqAGCxWABISUnB1dU17yITERERERHJY3bdQ+Tn58f8+fMZOnSosezzzz+nadOmeRaYiDwcqlatqipzIiJiSl4VKnLyzGlHhyH3ya6E6NVXX2XIkCEsX76cxMREOnbsSJEiRfjwww/zOj4RecAtb9IF26Wrjg5DREQk37XatMzRIcjfwK6EqGzZsqxcuZL9+/dz5swZKlSoQL169Yz7iURERERERB5Gdpfdtlgs1K9fn/r16+dlPCIiIiIiIvkm24SoU6dOrF+/HoA2bdoYxRT+6scff8yTwERERERERPJatgnRG2+8YbyePXt2vgQjIiIiIiKSn7JNiBo3bmy8rlGjBqVKlcqXgERERERERPKLXVUR2rVrx6BBg4iOjub69et5HZOIiIiIiEi+sCsh+ve//03btm1ZunQpLVq04KWXXmLjxo2kpKTkdXwiIiIiIiJ5xq6EqFSpUjz77LMsWbKEdevWUbNmTd555x1atmyZ1/GJiIiIiIjkmbt+kNDFixe5ePEily5dolixYnZts379eoKDg7FarQQEBDB69GijLTIykps3b95tGJn8/PPPdOrUyXh/7do1ateuzZdffmksW7BgAWPHjr3vY9kjMjKSZs2aYbVajf99/vnnuW43d+5cvvnmm78tDh8fHxITE+9qm8jISGbOnElcXBy+vr5cvZrxoZvbt2+nffv22Gy2u44nNTWVVq1aMWzYsBzXCwsLo1mzZhliDwsL49///vddHzM3p06domnTphmWJSYm4uPj87cfKyefffYZCxYsACAuLo6wsDAaNWpESEhIhvVSU1OZNm0agYGBdOzYkRkzZhjfxeeff57hb65hw4ZMnz4917affvqJiRMn5mNvRURERB4Mdj2H6MiRI6xdu5a1a9eSnJxMp06diIqKol69erlue/78eSZPnszq1aupUKECNpuNQ4cOGe3vvfce4eHhuLm53VXgKSkpuLj8L/yGDRsSGxvLxYsXKV26NLt376Zu3brs2LGDZ599FoCdO3fy1FNP3ddx7kZwcDDjxo27q21Gjhx5T8fKC+XKlaNx48asW7eO3r17G8tXr15NSEhItqXYc7Jp0ybKli3L7t27je8qO4UKFWLhwoW88MIL9xT/w+TGjRt88cUXrF27FoDChQszYsQIEhISiIyMzLDuihUrOHbsGKtXr8ZisTBkyBC++eYbunTpQt++fenbty8At27donXr1gQGBgLk2NamTRvmzp3LyZMnefTRR/Or2yIiIiIOZ9cIUe/evblw4QJvvPEGmzZtIiIiwq5kCG6PKLm4uFCiRAng9gNea9WqBcDkyZMBCA0NxWq1cvXqVWJiYujZsyfBwcEEBwezbds2Y1/+/v68//77hIWFZbqa7eHhQb169di5cydwO/np06cPv/32G3D7qvru3buNkYCZM2fSvXt3unbtSr9+/Th9+jTwv9GCyMhIevfuzfLly/n+++8JCgrCarUSGBjIjh077Op7dsaPH8+rr75K//796dixI6+++qoxSjZ+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9evHihUr7C6gkpyczIEDB0h640NslzIXdRARESnoWm1adk/PZXwY7N6927i4XBCkn7fUrVsXd3f3DG12TZmbOHEinp6eWK1WfH19CQ4OplChQrz22mt5ErCIGb322mtcuHDBIceOjY3l9ddfv+dqkiIiIiIPK7tGiNKlpaVx6dIlSpYsaUzXERFz0giRiIiYnUaIHh45jRDleA/RmTNnslx+Z2neihUr/g0hioiIiIiI5L8cEyJ/f3/jJvissl+LxcLBgwfzJjIREREREZE8lmNC5OPjQ3JyMt26daNr166ULVs2v+ISERERERHJczkmRNHR0Rw+fJjVq1fzzDPPUK1aNaxWKx06dNADHEVERERE5KGXa2UEb29vxo0bxw8//ED//v358ccfadmyJf/5z3/yIz4REREREZE8Y3epuD/++INdu3axb98+atWqRbFixfIyLhERERERkTyX45S5y5cvs27dOlavXk1iYiJWq5VFixapspyIGHruXMfZs2cdHYaIiEi+86qgc+KCIMeEqFWrVlSuXBmr1Ur9+vUBOHHiBCdOnDDWadasWd5GKCIPtOPHj2eq528GBe35DHdDfVffzUZ9N2ffQf03ixwTojJlypCcnMyyZctYtmxZpnaLxcIPP/yQZ8GJiIiIiIjkpRwToo0bN+ZXHCIiIiIiIvnO7qIKIiIiIiIiBY0SIhERERERMa0cp8yJiOSmatWqqjInIiL55tGKFTlx+rSjw5ACRAmRiNyX73t2xunaFUeHISIiJlFr4QpHhyAFjKbMiYiIiIiIaSkhEhERERER01JCJCIiIiIipqWESERERERETEsJkYiIiIiImJYSIhERERERMS0lRCIiIiIiYlpKiCTP+fv7c/jwYYcd32q1kpSUZPf6p06donbt2litVoKCgujVqxcHDx686+Pu2LGDkJAQu9aNi4sjNDSUtLQ0AGbOnIm/vz8+Pj6ZPrsff/yRbt26ERQURJ8+fYiNjbWrbdiwYXTt2pXg4GCeeeYZo083b94kJCSEa9eu3XUfRURERB52SojkgZOSkvK37i86OhoPD4+72qZo0aJER0cTExND586diYiIuKvt77YPUVFR9OnTByen2/9JPvnkk3z55ZdUqlQpw3pXrlxh3LhxzJkzh5iYGHr27Mnrr7+eaxvcTrK+/vpr1qxZQ3h4uNEnNzc3unbtysKFC+8qZhEREZGCQAmR5Ju/jhTd+d7f35/333+fsLAwJk6cyIULFwgLCyMkJIQuXbowa9YsY7vvv/+eoKAgrFYrgYGB7NixA4D33nuPgIAArFYrwcHBXL16FQAfHx8SExMBOHr0KOHh4QQFBREUFMTq1atzjbtFixYcP34cwEg0goODCQ4OZtu2bRn6c2cf7nT16lX69u3Lp59+mmn/ycnJbNiwgaeeespY1rhxYypUqJBp3RMnTlC6dGmqVq0KQJs2bdiyZQvx8fE5tsHtJC9dQkICFovFeB8YGMiKFXryt4iIiJiPi6MDEEl34cIFvvjiC+B2kvDhhx/i6enJrVu3GDhwIJs2baJ169bMmzePSZMm0bhxY1JTU7lx4wZXrlxhwYIFbNu2DQ8PDxISEjKNCqWkpDBs2DBefPFFOnXqBMClS5dyjWvDhg3UqlULgJYtWxIYGIjFYuHYsWP079+fTZs2ZdmH9ETt9OnTDB8+nMGDBxMQEJBp/7/++iuPPfYY7u7uucZStWpVLl68yP79+6lXrx4xMTEAnD17Nse2UqVKATBhwgS2bt2KzWbj448/NvZbunRpXF1dOXr0KNWrV881DhEREZGCQgmRPDCCg4ON16mpqcyaNYu9e/dis9m4ePEihw4donXr1jzxxBPMmDGDgIAAWrdujbe3N6mpqVStWpWxY8fSqlUr2rZtS5EiRTLs//jx46SkpBjJEEDJkiWzjOXatWtYrVZsNhteXl7MmDEDgNjYWEaPHk1cXBwuLi5cvHiRCxcuUKZMmUx9gNsJUt++fZk5cyaNGzfO8ljnzp3jkUceseszKlq0KO+88w7Tp08nOTmZ1q1bU6xYMVxcXHJsSzdt2jQA1qxZw6xZs/joo4+MtjJlyhAXF6eESERERExFCZHkG2dnZ6NoANweBbpT4cKFjdcLFy7k6tWrLF++HHd3d1577TVj/YiICH777Te2b9/OyJEjGTBgAE8//TTLli1jz549bN++nZCQED7++GNq1qxp7NNms9kda/o9RH/10ksvMX78eNq3b09aWhr169fP0I87+wBQvHhxypcvz6ZNm7JNiDw8PLh586bdsTVv3pzmzZsDcPHiRRYsWICXl1eubXcKDg5m4sSJXLp0yUgKk5OT7RqlEhERESlIdA+R5JtHH32UX3/9FYBt27Zx8eLFbNe9du0aZcqUwd3dnbi4OH744Qej7dixY/j4+NCvXz+6du3Kr7/+SkJCAvHx8TRp0oQRI0bg7e3N77//nmGf1apVw8XFhfXr1xvL7Jky99e4KleuDMCKFStyTWTc3NyIiori6NGjTJ06NcukzNvb27hHyR4XLlwAIC0tjTlz5hAaGmokYtm1JSYmcvbsWWMfGzdupHjx4pQoUQK4PSIXGxuLt7e33XGIiIiIFAQaIZI8l5KSgru7OyNHjmT8+PEsX76chg0bUrFixWy3CQsLY+TIkQQHB1O+fHmaNWtmtL399tucOHECZ2dnihUrxrRp00hISGD48OEkJSVhs9moXbs2HTp0yLBPFxcXoqKimDJlClFRUVgsFsLDwzNNc8vJK6+8wrBhwyhXrhxNmjQxEoqcuLm5MXfuXMaOHctrr73GlClTjGpycDtRLFq0KMeOHaNatWoATJ06le+++46LFy8yYMAASpQowbp16wB499132bNnD7du3aJFixaMGTPG2Fd2bTdu3GDkyJHcuHEDJycnihcvzocffmgUVtizZw/169fPUHhBRERExAwstruZRyRyl86fP0+nTp3YunXrXZe+NpO1a9eyb98+Xn31VYccf/To0XTv3t2YbmeP5ORkDhw4QKHPP8Dp2pU8jE5EROR/ai1ccVfT4O/H7t27adSoUb4c60FT0Pqeft5St27dTLcIaIRI8sznn3/O4sWLGTdunJKhXAQGBnL58mXS0tIyjB7lh5s3b9K4ceO7SoZERERECgolRJJn+vbtS9++fR0dxkOjT58+Djmum5sbvXv3dsixRURERBxNRRVERERERMS0lBCJiIiIiIhpKSESERERERHTUkIkIiIiIiKmpYRIRERERERMSwmRiIiIiIiYlspui8h9ab/8G86ePevoMERExCQerVjR0SFIAaOESETuy/HjxzM98dkMCtoTvO+G+q6+m436bs6+i3loypyIiIiIiJiWEiIRERERETEtJUQiIiIiImJaSohERERERMS0lBCJiIiIiIhpqcqciNyXqlWrquy2iIjJPVqpEidOnXJ0GCL3RAmRiNyXLS+H4ZyU4OgwRETEgaq8EuXoEETumabMiYiIiIiIaSkhEhERERER01JCJCIiIiIipqWESERERERETEsJkYiIiIiImJYSIhERERERMS0lRCIiIiIiYlpKiOSurF+/nuDgYKxW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06hRI0eH4RAFre/p5y1169bNcIsGaMqcyAPDy8uLAQMGcP78eYcc39nZmcGDBzvk2CIiIiKOoilzIg+QTp06OezYPXv2dNixRURERBxFI0QiIiIiImJaSohERERERMS0lBCJiIiIiIhpKSESERERERHTUkIkIiIiIiKmpYRIRERERERMS2W3ReS+tJz1BWfPnnV0GCIi4kCPVqrk6BBE7pkSIhG5L8ePH8/0xGczKGhP8L4b6rv6bjbquzn7LuahKXMiIiIiImJaSohERERERMS0lBCJiIiIiIhpKSESERERERHTUlEFEbkvVatWVZU5ERGTetSrMidOxjo6DJH7ooRIRO7LzvcjcElJcnQYIiLiABWeHuvoEETum6bMiYiIiIiIaSkhEhERERER01JCJCIiIiIipqWESERERERETEsJkYiIiIiImJYSIhERERERMS0lRCIiIiIiYlpKiERERERExLT0YFZxOH9/f9zc3HB3dyc5OZnGjRszadIkXF1d8+X4YWFhhIeH065duzw7xo4dO7h16xYtW7bMdp3vv/+en3/+mYkTJ3Lz5k2GDh3KgQMHjO3v9M9//pOYmBhSUlKoX78+b7zxBm5ubjm2nTp1ig4dOvD4448b+/n0008pWbIkP/30Ez/88ANTpkzJg96LiIiIPLg0QiQPhHnz5hEdHc26des4cuQI//rXvzKtk5aWhs1mc0B09yclJYWdO3eydevWHNebO3cugwcPBsDJyYmBAwfy6aefZlpvy5YtrF27lmXLlrF+/XpcXV2N9XJqAyhatCjR0dHG/0qWLAlAmzZtOHDgACdPnvxb+iwiIiLysFBCJA+U5ORkkpOTKVasGACRkZGMGTOGYcOGYbVauXr1KjNnzqR79+507dqVfv36cfr0aQAiIiL47LPPjH0dPnyYJ598EpvNRkJCAhMmTKBHjx4EBQUxdepUUlNTjXV37txJ7969efLJJ3nrrbeM5efPn2fEiBHGdh9++KHRll0cp06domnTpkRGRtK7d2+WLFnC0qVLWbNmDVarlfnz52fq9y+//EKJEiUoX748AC4uLjRv3pyiRYtmWvfQoUM0btyYwoULY7FYaN26NTExMbm25SYgIICVK1fata6IiIhIQaGESB4II0aMwGq10qJFCypXrpxhatkvv/zC1KlTiYmJoXjx4gwaNIiVK1fy9ddfExgYaCQwISEhrFmzxthu1apVdOvWDYvFwvTp0/Hz82PFihVER0cTHx+f4eT/7NmzfPnll6xZs4bly5fzxx9/ADBu3DjCwsJYsWIFK1euZNOmTcZIT3ZxAFy+fJnq1auzZMkSwsLCCA0NJTg4mOjoaGMU6E47duygfv36dn1WderU4eeffyY+Pp6UlBTWr19vJGM5tQEkJiYSEhJCSEgIH3/8cYYRN19fX7Zt22ZXDCIiIiIFhe4hkgfCvHnz8Pb2Jjk5meHDh/Ppp5/Sv39/AFq3bk2pUqWMdTdt2sTixYu5fv06KSkpxvLGjRuTmJjIoUOHqFGjBmvXruWrr74CYOPGjezfv5+FCxcCkJSURLly5YxtAwICcHJyomjRolSvXp2TJ09StmxZdu7cSXx8vLFeYmIiR48epUWLFtnGAeDu7k6nTp3s7n9cXBzVqlWza91mzZrxzDPPMHDgQNzd3XniiSeM+61yaitbtiw//fQTjzzyCH/++SdDhw6lePHi9OzZE4DSpUtz7tw5u2MWERERKQiUEMkDxd3dnbZt2/Ljjz8aCZGnp6fRfvr0aaZPn86KFSvw8vJiz549jBkzxmi3Wq2sWbOGJk2aUL16dSpVqgSAzWYjKioKLy+vbI+bztnZmdTUVNLS0rBYLKxYsSJTgYfc4ihUqBAWi+Wu+p2cnGz3+v369aNfv34AfPPNNxmSqeza3NzceOSRRwB45JFHCAoKYs+ePUZClJycjIeHh90xiIiIiBQEmjInD5S0tDR27dpFlSpVsmxPSEjA1dWVMmXKkJaWxtKlSzO0d+vWjbVr17J8+XJCQkKM5f7+/syfP9+4byg+Pp7Y2NgcYylSpAiNGjXKcM/P2bNnuXDhQq5xZLWva9euZdvu7e3N8ePHc9zHnS5cuADAlStX+Oijjxg4cGCubX/++Se3bt0C4MaNG2zcuJGaNWsa2x07dizDexEREREz0AiRPBBGjBiBu7s7t27d4vHHH+f555/Pcj0fHx8CAgLo0qULFStWxM/Pj19++cVor1ixIjVq1GDnzp3MmTPHWB4REcHs2bOxWq1YLBZcXV2JiIjIdsQo3VtvvcX06dMJCgoCbo9WTZs2Ldc4/qp9+/ZER0djtVrp0qVLpvuI2rVrx4cffkhaWhpOTrevU3Tv3p24uDiuXr1K69atadWqFdOmTQMgPDyctLQ0UlJSePbZZ2nfvr2xr+zadu/ezbx583ByciIlJYW2bdvSp08fY7vNmzfToUOHHD8PERERkYLGYnsY6xiLFEATJ06kVatWPPXUU/l+7EuXLtGvXz9WrFhhPM8oN8nJyRw4cIByJ7fhkpKUxxGKiMiDqMLTYx/KR2LYa/fu3TRq1MjRYThEQet7+nlL3bp1M9wqAZoyJ/LAePHFF0lKckxiERsby+uvv253MiQiIiJSUGjKnMgDolSpUsbUvPxWr149hxxXRERExNE0QiQiIiIiIqalhEhERERERExLCZGIiIiIiJiWEiIRERERETEtJUQiIiIiImJaqjInIvelyfNvcvbsWUeHISIiDvCoV2VHhyBy35QQich9OX78eKYHnJlBQXtg3d1Q39V3s1Hfzdl3MQ9NmRMREREREdNSQiQiIiIiIqalhEhERERERExLCZGIiIiIiJiWEiIRERERETEtVZkTkftStWpVld0WETGBxx714o8TJx0dhsjfTgmRiNyXvV9/giupjg5DRETy2CN+gY4OQSRPaMqciIiIiIiYlhIiERERERExLSVEIiIiIiJiWkqIRERERETEtJQQiYiIiIiIaSkhEhERERER01JCJCIiIiIipqWESB5Y/v7+BAQEYLVasVqtvPnmmwDMnTuXb775JtftIyMjmTlzZpZtO3bsYMuWLTluv3nzZkJDQ+nQoQOdO3fmueee47fffgPAx8eHxMTEXGOwdz2AgwcPMnToUOP96NGjadmyZZb7WLlyJUFBQXTp0oUhQ4Zw+fLl+2qLj4/n6aefJiUlxa5YRURERAoKJUTyQJs3bx7R0dFER0cTEREBwMiRI+ncufN97Xfnzp1s3bo12/YtW7YwYcIEJkyYwHfffcc333zDyJEjuXDhwn0dNydvv/02gwcPNt736NGD6OjoTOsdPXqUd999l88++4x169ZRr1495syZc19tpUqVon79+lkeT0RERKQgU0IkD53x48ezaNEiAK5du8bw4cMJCAigX79+vPzyyxlGheLi4hg0aBABAQEMHjyYGzdu8Ntvv7F06VLWrFmD1Wpl/vz5mY7x/vvvM2zYMP7xj38Yy2rXrk3Lli0zrfvXEZy/vv/kk08IDQ2lY8eOfPvtt1n26cyZMxw/fhxfX19jWbNmzXjkkUcyrXv48GFq1apFqVKlAGjTpg0xMTH31QYQ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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Function applied to merged data\n", + "plot_by_ratings(f1,'title',10)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "83auA-MUtvEd" + }, + "source": [ + "# Preprocessing and Feature Engineering\n", + "\n", + "The goal of dimensionality reduction is to reduce the number of features in a dataset while minimising the amount of data loss" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "BT-3rXMYtvgN" + }, + "source": [ + "#### For pre processing we wil perform :\n", + "\n", + "* Scaling\n", + "* Principle component Analysis\n", + "* Cosine similarity check\n", + "* Recommender systems\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "HnWLzi6WCRl9" + }, + "source": [ + "The Dataset contain too large values.To reduce computational power, we are going to be looking at the top ten movies and selecting only those with a rating of more than 2000" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "9HFTUYIWCDtB", + "outputId": "2f23824a-5b83-4feb-80e4-3fb35f94721c" + }, + "outputs": [], + "source": [ + "#Filtering applied to train dataset\n", + "#pre_scaled=train.groupby(\"movieId\").filter(lambda x:x['rating'].count() >=2000)\n", + "#print(\"the filtered dataset consist of :\")\n", + "#pre_scaled.shape[0]" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 206 + }, + "id": "W1jFexN_b9A2", + "outputId": "a1d1f3fc-5059-44ab-9ed8-9be970f42c69" + }, + "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", + "
movieIdtitlegenresuserIdratingtimestamp
01Toy Story (1995)Adventure|Animation|Children|Comedy|Fantasy1588495.0994716786
11Toy Story (1995)Adventure|Animation|Children|Comedy|Fantasy972035.0942683155
21Toy Story (1995)Adventure|Animation|Children|Comedy|Fantasy1618713.0833104576
31Toy Story (1995)Adventure|Animation|Children|Comedy|Fantasy451174.01442256969
41Toy Story (1995)Adventure|Animation|Children|Comedy|Fantasy274315.0849667827
\n", + "
" + ], + "text/plain": [ + " movieId title genres \\\n", + "0 1 Toy Story (1995) Adventure|Animation|Children|Comedy|Fantasy \n", + "1 1 Toy Story (1995) Adventure|Animation|Children|Comedy|Fantasy \n", + "2 1 Toy Story (1995) Adventure|Animation|Children|Comedy|Fantasy \n", + "3 1 Toy Story (1995) Adventure|Animation|Children|Comedy|Fantasy \n", + "4 1 Toy Story (1995) Adventure|Animation|Children|Comedy|Fantasy \n", + "\n", + " userId rating timestamp \n", + "0 158849 5.0 994716786 \n", + "1 97203 5.0 942683155 \n", + "2 161871 3.0 833104576 \n", + "3 45117 4.0 1442256969 \n", + "4 27431 5.0 849667827 " + ] + }, + "execution_count": 35, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "f1.head()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "eJyMyATTLBfX" + }, + "source": [ + "Labels are not used in an unsupervised learning environment" + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "metadata": {}, + "outputs": [], + "source": [ + "# create short list of unwanted columns\n", + "labels = ['title', 'genres']\n", + "\n", + "# declare the features to be all columns, less the unwanted ones from above\n", + "features = [col for col in train.columns if col not in labels]" + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "aWkKramfx31x", + "outputId": "791296df-389e-4861-fd38-88c211b49652" + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/explore-student/anaconda3/lib/python3.7/site-packages/sklearn/preprocessing/_data.py:173: UserWarning:\n", + "\n", + "Numerical issues were encountered when centering the data and might not be solved. Dataset may contain too large values. You may need to prescale your features.\n", + "\n" + ] + } + ], + "source": [ + "# Scaling the movies_df\n", + "# declare the features to be all columns from our movies_df\n", + "#features = [col for col in f1.columns]\n", + "\n", + "# create scaler object\n", + "scaler = StandardScaler()\n", + "\n", + "# define scaled data frame variable\n", + "scaled_df = train.copy()\n", + "scaled_df[features] = preprocessing.scale(scaled_df[features])" + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 628 + }, + "id": "BMC8o_cxybqZ", + "outputId": "7141bade-461d-481f-f0ea-f53f7c94dad9" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "Text(0, 0.5, 'Cumulative explained variance')" + ] + }, + "execution_count": 38, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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T1bTpk0VFhamnj176vDhw5KkN954Q1OmTFFUVJQ8PT01depUHTp0qMrRv4uteyGenp46evSoCgsL1axZM3Xs2NGp9xEAULsofwCAK9KhQwcNGDBAL7300mWvGxQUVHnb19dXktSiRYvKx3x8fFRUVFR5v2XLlpW3/fz81KxZM+Xk5Cg9PV379u1T9+7dK/+8++67OnnyZOXyNpvtojlycnLUrFkz+fv7Vz4WFhZW5bTJS8nMzFSbNm0u+LotW7aUxfL/f93+9+v+93vwy5/f19e3yhfq/PfPERYWppycnMpttWrVqvI5Pz8/BQQEVNlWcHBw5e1GjRpVvrcZGRmVp992795dsbGxMgzDqXUv5LnnntOOHTs0cOBAxcfH67vvvrvosgAA1/E0OwAAoP6bMWOG/vCHP2jixImVj/385SglJSWVpeqXZaw6srKyKm8XFRXpzJkzCgkJkc1mU48ePbRy5cpqvW5ISIjOnDmjwsLCyqyZmZkKDQ11an2bzVblCOUvXzcrK0sOh6OyAGZmZioyMrJaOX9e/2cZGRkKCQmp3NYvj9QVFxcrPz/fqZ/BZrNp6tSp+v3vf3/ZeTw8PM57rHPnzlqxYoXKy8u1evVq/fnPf9aOHTsu+7UBADWLI38AgCsWERGh4cOH6/XXX698LDAwUKGhodq8ebPsdrs2btyotLS0K9rOjh079O2336qsrEzPPvusrr32WtlsNg0YMEDJycnatGmTysvLVV5ern379unYsWNOva7NZlNMTIyWLl2q0tJSHT58WBs3btSIESOcWv/WW2/Va6+9pqSkJBmGoZSUFKWnp6tz585q1KiRXnnlFZWXl2v37t3avn27hg8fXu33YM2aNcrKylJ+fn7ll79I0ogRI/TWW2/p0KFDKisr09KlS9W5c2eFh4f/6muOHTtWL730ko4cOSJJKigo0HvvvedUnqCgIGVnZ6usrEySVFZWpnfeeUcFBQXy8vKSn5+frFZrNX9aAEBNovwBAGrEvffee94pinPnztWrr76qnj176ujRo4qJibmibcTFxWn58uXq2bOnDhw4oCVLlkiS/P399eqrr2rbtm3q16+f+vbtq2eeeaaykDhj6dKlSk9PV79+/XTfffdp+vTp6tOnj1Pr3njjjZo6daoeeughde3aVffee6/OnDkjb29vrVixQp999pmuu+46Pfnkk1q8eLGioqKq9fNL/3kPJk6cqMGDB6t169aaNm2aJKlXr166//77NX36dPXt21dpaWlatmyZU685ZMgQTZo0SQ8++KC6du2quLg4ffbZZ06te91116l9+/bq27evevbsKUnavHmzBg0apK5du+qNN97Q4sWLq/fDAgBqlIdh/OJ7ngEAQJ01aNAgzZs3T7179zY7CgCgHuLIHwAAAAC4AcofAAAAALgBTvsEAAAAADfAkT8AAAAAcAOUPwAAAABwA5Q/AAAAAHADlD8AAAAAcAOUPwAAAABwA5Q/AAAAAHAD/w/AKVoczRbDmAAAAABJRU5ErkJggg==\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# define PCA object\n", + "pca = PCA()\n", + "\n", + "# fit the PCA model to our data and apply the dimensionality reduction \n", + "prin_comp = pca.fit_transform(scaled_df[features])\n", + "\n", + "# create a dataframe containing the principal components\n", + "pca_df = pd.DataFrame(data = prin_comp)\n", + "\n", + "\n", + "\n", + "# plot line graph of cumulative variance explained\n", + "plt.plot(np.cumsum(pca.explained_variance_ratio_))\n", + "plt.xlabel('Number of components')\n", + "plt.ylabel('Cumulative explained variance')" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "SgRnjlus0tOx" + }, + "source": [ + "Looking at the graph, it appears roughly 3 components will explain 87% of the data. That is a significant reduction - from 6 features down to 3. Interestingly, it appears that close to 100% of the variance is explained by the first 3 components, itself a significant reduction" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "h8r82sFh0vXR" + }, + "source": [ + "Next we will determine how many principal components will be required to explain 85% of the variance in our dataset." + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "KYWgZkOlyvVY", + "outputId": "386a40a1-f8cd-47c0-918a-2231e821881d" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "88.0 % of variance explained by 3 components.\n" + ] + } + ], + "source": [ + "pca_85 = PCA(.85)\n", + "pca_85.fit_transform(scaled_df[features])\n", + "print(round(pca_85.explained_variance_ratio_.sum()*100, 1),\n", + " \"% of variance explained by\",\n", + " pca_85.n_components_,\n", + " \"components.\")" + ] + }, + { + "cell_type": "code", + "execution_count": 40, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "yIBU88nt1HrC", + "outputId": "ea5297d0-119b-4882-a5ba-776c78c6beb4" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "array([0.38015568, 0.25049091, 0.24958896])" + ] + }, + "execution_count": 40, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#Let's take a look at the variance explained by the first few components\n", + "pca.explained_variance_ratio_[:3]" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "HjBG_eXQ1fac" + }, + "source": [ + "#### Observations from pca\n", + "The first component explains 38%, with the 2nd following closely behind at 25% and the 3rd at 25%. Together, the 86% of the variance is explained by the first three components." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "enxPbphxDFa_" + }, + "source": [ + "Putting Our Dimensionality Reduction to Use\n", + "We have seen that just 3 components of an original 6 can be used to explain 88% of the variance in our dataset. Let us now utilise our reduced dataset, consisting of just 3 components, by using it to build a predictive regressor model.\n", + "\n", + "We will use the feature named rating as the response variable (the one that we will try to predict). This feature was used in our initial PCA, so we will have to make some changes to the dataset to ensure it is not included this time.\n", + "\n", + "PCA requires features to be scaled. But we don't need to scale the response variable which we will use for prediction, as it is not used in PCA. This is good, because leaving the response as is means any predicted values and associated errors are easier to interpret" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### cosine similarity pre processing" + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "metadata": {}, + "outputs": [], + "source": [ + "#make a copy of the movies dataframe to work with\n", + "movies_copy = movies.copy()" + ] + }, + { + "cell_type": "code", + "execution_count": 42, + "metadata": {}, + "outputs": [], + "source": [ + "#filter movies dataset to take only 20000 movies to reduce computational power \n", + "r_movies = movies_copy[0:20000]" + ] + }, + { + "cell_type": "code", + "execution_count": 43, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0 Adventure|Animation|Children|Comedy|Fantasy\n", + "1 Adventure|Children|Fantasy\n", + "2 Comedy|Romance\n", + "3 Comedy|Drama|Romance\n", + "4 Comedy\n", + " ... \n", + "19995 Comedy\n", + "19996 Documentary\n", + "19997 Documentary\n", + "19998 Crime|Horror|Mystery\n", + "19999 Drama\n", + "Name: genres, Length: 20000, dtype: object" + ] + }, + "execution_count": 43, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#select and display the desired column to be used for checking similarity(genres column)\n", + "r2_movies = r_movies['genres']\n", + "r2_movies" + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0 Toy Story (1995)\n", + "1 Jumanji (1995)\n", + "2 Grumpier Old Men (1995)\n", + "3 Waiting to Exhale (1995)\n", + "4 Father of the Bride Part II (1995)\n", + " ... \n", + "19995 Joker (2012)\n", + "19996 Gitmo (2005)\n", + "19997 My Avatar and Me (Min Avatar og mig) (2010)\n", + "19998 Blood Beast Terror, The (1968)\n", + "19999 Othello (1981)\n", + "Name: title, Length: 20000, dtype: object" + ] + }, + "execution_count": 44, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#creating indices used to keep track of numbering of all entities in the movie column\n", + "\n", + "titles = r_movies['title']\n", + "indices = pd.Series(r_movies.index, index=r_movies['title'])\n", + "titles" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We now need a mechanism to convert these textual features into a format which enables us to compute their relative similarities to one another. This will allow us to translate our string-based collection of tags and authors into numerical vectors" + ] + }, + { + "cell_type": "code", + "execution_count": 45, + "metadata": {}, + "outputs": [], + "source": [ + "#converting textual data to numerical\n", + "tf = TfidfVectorizer(analyzer='word', ngram_range=(1,2),\n", + " min_df=0, stop_words='english')\n", + "\n", + "# Produce a feature matrix, where each row corresponds to a movie,\n", + "# with TF-IDF features as columns \n", + "tf_tag_ti_gen_matrix = tf.fit_transform(r2_movies)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Modelling " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Content based filtering" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Content-based filtering is one popular technique of recommendation or recommender systems. The content or attributes of the things you like are referred to as \"content.\" \n", + "\n", + "Here, the system uses your features and likes in order to recommend you with things that you might like. It uses the information provided by you over the internet and the ones they are able to gather and then they curate recommendations according to that. \n", + "The goal behind content-based filtering is to classify products with specific keywords, learn what the customer likes, look up those terms in the database, and then recommend similar things.\n", + "\n", + "This type of recommender system is hugely dependent on the inputs provided by users, some common examples included Google, Wikipedia, etc. For example, when a user searches for a group of keywords, then Google displays all the items consisting of those keywords. The below video explains how a content-based recommender works." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Advantages\n", + "\n", + "* The model doesn't need any data about other users, since the recommendations are specific to this user. This makes it easier to scale to a large number of users.\n", + "* The model can capture the specific interests of a user, and can recommend niche items that very few other users are interested in.\n", + "\n", + "#### Disadvantages\n", + "\n", + "* Since the feature representation of the items are hand-engineered to some extent, this technique requires a lot of domain knowledge. Therefore, the model can only be as good as the hand-engineered features.\n", + "* The model can only make recommendations based on existing interests of the user. In other words, the model has limited ability to expand on the users' existing interests." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We are going to compute the similarity between each vector within our matrix.\n", + "This is done by making use of the cosine_similarity function \n", + "provided to us by sklearn" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "cosine_sim_tags = cosine_similarity(tf_tag_ti_gen_matrix, \n", + " tf_tag_ti_gen_matrix)\n", + "print (cosine_sim_tags.shape)" + ] + }, + { + "cell_type": "code", + "execution_count": 49, + "metadata": {}, + "outputs": [], + "source": [ + "def content_generate_top_N_recommendations(movie_title, N=10):\n", + " # Convert the string movie title to a numeric index for our \n", + " # similarity matrix\n", + " b_idx = indices[movie_title]\n", + " \n", + " # Extract all similarity values computed with the reference book title\n", + " sim_scores = list(enumerate(cosine_sim_tags[b_idx]))\n", + " \n", + " # Sort the values, keeping a copy of the original index of each value\n", + " sim_scores = sorted(sim_scores, key=lambda x: x[1], reverse=True)\n", + " \n", + " # Select the top-N values for recommendation\n", + " sim_scores = sim_scores[1:N]\n", + " \n", + " # Collect indexes \n", + " movie_indices = [i[0] for i in sim_scores]\n", + " # Convert the indexes back into titles \n", + " return titles.iloc[movie_indices]" + ] + }, + { + "cell_type": "code", + "execution_count": 50, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "6 Sabrina (1995)\n", + "38 Clueless (1995)\n", + "63 Two if by Sea (1996)\n", + "67 French Twist (Gazon maudit) (1995)\n", + "116 If Lucy Fell (1996)\n", + "120 Boomerang (1992)\n", + "127 Pie in the Sky (1996)\n", + "178 Mallrats (1995)\n", + "184 Nine Months (1995)\n", + "Name: title, dtype: object" + ] + }, + "execution_count": 50, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#tyjk\n", + "content_generate_top_N_recommendations(\"Grumpier Old Men (1995)\")" + ] + }, + { + "cell_type": "code", + "execution_count": 51, + "metadata": {}, + "outputs": [], + "source": [ + "def content_generate_rating_estimate(movie_title, userId, rating_data, k=20, threshold=0.0):\n", + " # Convert the movie title to a numeric index for our \n", + " # similarity matrix\n", + " b_idx = indices[movie_title]\n", + " neighbors = [] # <-- Stores our collection of similarity values \n", + " \n", + " # Gather the similarity ratings between each movie the user has rated\n", + " # and the reference movie \n", + " for index, row in rating_data[rating_data['userId']==userId].iterrows():\n", + " sim = cosine_sim_tags[b_idx-1, indices[row['title']]-1]\n", + " neighbors.append((sim, row['rating']))\n", + " # Select the top-N values from our collection\n", + " k_neighbors = heapq.nlargest(k, neighbors, key=lambda t: t[0])\n", + "\n", + " # Compute the weighted average using similarity scores and \n", + " # user item ratings. \n", + " simTotal, weightedSum = 0, 0\n", + " for (simScore, rating) in k_neighbors:\n", + " # Ensure that similarity ratings are above a given threshold\n", + " if (simScore > threshold):\n", + " simTotal += simScore\n", + " weightedSum += simScore * rating\n", + " try:\n", + " predictedRating = weightedSum / simTotal\n", + " except ZeroDivisionError:\n", + " # Cold-start problem - No ratings given by user. \n", + " # We use the average rating for the reference item as a proxy in this case \n", + " predictedRating = np.mean(rating_data[rating_data['title']==movie_title]['rating'])\n", + " return predictedRating" + ] + }, + { + "cell_type": "code", + "execution_count": 52, + "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", + "
movieIdtitlegenresuserIdratingtimestamp
418540252I.Q. (1994)Comedy|Romance3144.0843573423
637220356Forrest Gump (1994)Comedy|Drama|Romance|War3144.0843572792
727277383Wyatt Earp (1994)Western3144.0843576295
801395457Fugitive, The (1993)Thriller3145.0843572769
854016497Much Ado About Nothing (1993)Comedy|Romance3145.0843574174
880655515Remains of the Day, The (1993)Drama|Romance3143.0843574119
951580552Three Musketeers, The (1993)Action|Adventure|Comedy|Romance3143.0843575928
\n", + "
" + ], + "text/plain": [ + " movieId title \\\n", + "418540 252 I.Q. (1994) \n", + "637220 356 Forrest Gump (1994) \n", + "727277 383 Wyatt Earp (1994) \n", + "801395 457 Fugitive, The (1993) \n", + "854016 497 Much Ado About Nothing (1993) \n", + "880655 515 Remains of the Day, The (1993) \n", + "951580 552 Three Musketeers, The (1993) \n", + "\n", + " genres userId rating timestamp \n", + "418540 Comedy|Romance 314 4.0 843573423 \n", + "637220 Comedy|Drama|Romance|War 314 4.0 843572792 \n", + "727277 Western 314 4.0 843576295 \n", + "801395 Thriller 314 5.0 843572769 \n", + "854016 Comedy|Romance 314 5.0 843574174 \n", + "880655 Drama|Romance 314 3.0 843574119 \n", + "951580 Action|Adventure|Comedy|Romance 314 3.0 843575928 " + ] + }, + "execution_count": 52, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "f1[f1['userId'] == 314][3:10]" + ] + }, + { + "cell_type": "code", + "execution_count": 53, + "metadata": {}, + "outputs": [], + "source": [ + "#let us see how our defined model performs" + ] + }, + { + "cell_type": "code", + "execution_count": 54, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Title - Batman Forever (1995)\n", + "---\n", + "Actual rating: \t\t 4.0\n", + "Predicted rating: \t 4.013880327536618\n" + ] + } + ], + "source": [ + "title = \"Batman Forever (1995)\"\n", + "actual_rating = f1[(f1['userId'] == 314) & (f1['title'] == title)]['rating'].values[0]\n", + "pred_rating = content_generate_rating_estimate(movie_title=title, userId=314, rating_data=f1)\n", + "print (f\"Title - {title}\")\n", + "print (\"---\")\n", + "print (f\"Actual rating: \\t\\t {actual_rating}\")\n", + "print (f\"Predicted rating: \\t {pred_rating}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Collaborative filtering" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Methods for recommender systems that are primarily based on previous interactions between users and the target items are known as collaborative filtering methods. \n", + "\n", + "As a result, all past data about user interactions with target objects will be fed into a collaborative filtering system. This information is usually recorded as a matrix, with the rows representing users and the columns representing items.\n", + "\n", + "The basic premise of such systems is that the users' previous data should be sufficient to generate a prediction. That is, we don't require anything other than historical data, no more user input, no current trending data, and so on." + ] + }, + { + "cell_type": "code", + "execution_count": 55, + "metadata": {}, + "outputs": [], + "source": [ + "#Trainset split\n", + "train_df = train.copy()\n", + "train_df.drop('timestamp', axis=1, inplace=True)\n", + "# reduce the dataset by making a subset of the original data set\n", + "subset = train_df[:100000]\n", + "reader = Reader(rating_scale=(subset['rating'].min(), subset['rating'].max()))\n", + "data = Dataset.load_from_df(subset[['userId', 'movieId', 'rating']], reader)\n", + "trainset, testset = train_test_split(data, test_size=.25, random_state=42)" + ] + }, + { + "cell_type": "code", + "execution_count": 56, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "RMSE: 1.1601\n" + ] + } + ], + "source": [ + "nmf = NMF()\n", + "\n", + "# Train the algorithm on the trainset, and predict ratings for the testset\n", + "nmf.fit(trainset)\n", + "predictions = nmf.test(testset)\n", + "\n", + "# Compute RMSE\n", + "nmf_rmse = accuracy.rmse(predictions)" + ] + }, + { + "cell_type": "code", + "execution_count": 57, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "7hzsOVumbSES", + "outputId": "bce019ec-8f32-4a7d-d7f3-dce3715a24d4" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "RMSE: 0.9831\n" + ] + } + ], + "source": [ + "svd = SVD()\n", + "\n", + "# Train the algorithm on the trainset, and predict ratings for the testset\n", + "svd.fit(trainset)\n", + "predictions = svd.test(testset)\n", + "\n", + "# Compute RMSE\n", + "svd_rmse = accuracy.rmse(predictions)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Why collaborative filtering is better than content-based filtering?\n", + "\n", + "Content-based filtering :\n", + "* Content-based filtering does not require other users' data during recommendations to one user. \n", + "\n", + "Collaborative filtering System: \n", + "* Collaborative does not need the features of the items to be given. Every user and item is described by a feature vector or embedding. It creates embedding for both users and items on its own.\n", + "\n", + "\n", + "* What happens when there isn’t enough information provided by a user to make item recommendations? Well, in these cases we can use data provided by other users with similar preferences. Methods within this category make use of the history of past choices of a group of users in order to elicit recommendations.And that makes Collaborative filtering a powerful technique" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Hyperparameter Optimization" + ] + }, + { + "cell_type": "code", + "execution_count": 58, + "metadata": {}, + "outputs": [], + "source": [ + "def tune_SVM_model(X_train, y_train):\n", + " # your code here\n", + " D = {'C':[0.1, 1, 10], 'gamma': [0.01, 0.1, 1]}\n", + "\n", + " from sklearn.metrics import make_scorer\n", + "\n", + " grid_SVM = GridSearchCV(SVC(), param_grid = D, scoring=make_scorer(custom_scoring_function, greater_is_better = False), cv=5)\n", + " grid_SVM.fit(X_train, y_train)\n", + "\n", + " return grid_SVM" + ] + }, + { + "cell_type": "code", + "execution_count": 59, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "***Best score:***\n", + "0.9673233296506473\n", + "***Best parameters:***\n", + "{'n_epochs': 40, 'n_factors': 600, 'init_std_dev': 0.005, 'random_state': 42}\n" + ] + } + ], + "source": [ + "param_grid = {'n_epochs':[40], #[10,20,30,40,50,60],\n", + " 'n_factors':[600], #[100,200,300,400,500,600],\n", + " 'init_std_dev':[0.005], #[0.001,0.005,0.05,0.1],\n", + " 'random_state':[42]} \n", + "grid_SVD = GridSearchCV(SVD, cv=5, measures=['rmse'], param_grid=param_grid, n_jobs=-1)\n", + "grid_SVD.fit(data)\n", + "print('***Best score:***')\n", + "print(grid_SVD.best_score['rmse'])\n", + "print('***Best parameters:***')\n", + "print(grid_SVD.best_params['rmse'])" + ] + }, + { + "cell_type": "code", + "execution_count": 60, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Processing epoch 0\n", + "Processing epoch 1\n", + "Processing epoch 2\n", + "Processing epoch 3\n", + "Processing epoch 4\n", + "Processing epoch 5\n", + "Processing epoch 6\n", + "Processing epoch 7\n", + "Processing epoch 8\n", + "Processing epoch 9\n", + "Processing epoch 10\n", + "Processing epoch 11\n", + "Processing epoch 12\n", + "Processing epoch 13\n", + "Processing epoch 14\n", + "Processing epoch 15\n", + "Processing epoch 16\n", + "Processing epoch 17\n", + "Processing epoch 18\n", + "Processing epoch 19\n", + "Processing epoch 20\n", + "Processing epoch 21\n", + "Processing epoch 22\n", + "Processing epoch 23\n", + "Processing epoch 24\n", + "Processing epoch 25\n", + "Processing epoch 26\n", + "Processing epoch 27\n", + "Processing epoch 28\n", + "Processing epoch 29\n", + "Processing epoch 30\n", + "Processing epoch 31\n", + "Processing epoch 32\n", + "Processing epoch 33\n", + "Processing epoch 34\n", + "Processing epoch 35\n", + "Processing epoch 36\n", + "Processing epoch 37\n", + "Processing epoch 38\n", + "Processing epoch 39\n", + "RMSE: 0.9734\n" + ] + } + ], + "source": [ + "svd = SVD(n_epochs = 40, n_factors = 600, init_std_dev = 0.005, random_state=42, verbose=True)\n", + "svd.fit(trainset)\n", + "predictions = svd.test(testset)\n", + "\n", + "# Compute RMSE\n", + "svd_rmse = accuracy.rmse(predictions)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Model Performance" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Appendix section" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### comet logs" + ] + }, + { + "cell_type": "code", + "execution_count": 61, + "metadata": {}, + "outputs": [ + { + "ename": "NameError", + "evalue": "name 'precision_score' is not defined", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0;31m# Saving each metric to add to a dictionary for logging\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0;31m# = f1_score(y_test, lrm.predict(X_test), average='weighted')\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 3\u001b[0;31m \u001b[0mprecision\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mprecision_score\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0my_test\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mlrm\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpredict\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mX_test\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0maverage\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m'weighted'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 4\u001b[0m \u001b[0mrecall\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mrecall_score\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0my_test\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mlrm\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpredict\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mX_test\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0maverage\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m'weighted'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'f1:\\t\\t'\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0mstr\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mf1\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mNameError\u001b[0m: name 'precision_score' is not defined" + ] + } + ], + "source": [ + "# Saving each metric to add to a dictionary for logging\n", + "# = f1_score(y_test, lrm.predict(X_test), average='weighted')\n", + "precision = precision_score(y_test, lrm.predict(X_test), average='weighted')\n", + "recall = recall_score(y_test, lrm.predict(X_test), average='weighted')\n", + "print('f1:\\t\\t' + str(f1))\n", + "print('precision:\\t' + str(precision))\n", + "print('recall:\\t\\t' + str(recall))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create dictionaries for the data we want to log\n", + "params = {\"random_state\": 1,\n", + " \"model_type\": \"logreg\",\n", + " }\n", + "metrics = {\"precision\": precision,\n", + " \"recall\": recall,\n", + " \"f1\": f1\n", + " }" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Log our parameters and results\n", + "experiment.log_parameters(params)\n", + "experiment.log_metrics(metrics)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Prepare data for Kaggle submission" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 206 + }, + "id": "0Bp0qVK2euqo", + "outputId": "4102f24e-06e6-4c2f-90bc-e0e0b2593eeb" + }, + "outputs": [], + "source": [ + "test.head()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "H6UrgFyuhfIg" + }, + "outputs": [], + "source": [ + "train_df = train\n", + "test_df = test" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Train model on whole dataset\n", + "reader = Reader(rating_scale=(train_df['rating'].min(), train_df['rating'].max()))\n", + "data = Dataset.load_from_df(train_df[['userId', 'movieId', 'rating']], reader)\n", + "trainset = data.build_full_trainset()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#hypertuned Model\n", + "svd = SVD(n_epochs = 40, n_factors = 600, init_std_dev = 0.005, random_state=42, verbose=True)\n", + "svd.fit(trainset)\n", + "predictions = svd.test(testset)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Compute RMSE\n", + "svd_rmse = accuracy.rmse(predictions)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create Kaggle submission file\n", + "predictions = []\n", + "for i, row in test_df.iterrows():\n", + " x = (svd.predict(row.userId, row.movieId))\n", + " pred = x[3]\n", + " predictions.append(pred)\n", + "test_df['Id'] = test_df['userId'].map(str) +'_'+ test_df['movieId'].map(str)\n", + "results = pd.DataFrame({\"Id\":test_df['Id'],\"rating\": predictions})\n", + "results.to_csv(\"Team_CB6.csv\", index=False)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "YQ5GWoclg8U9", + "outputId": "1a8556d7-b4cd-4b87-b21d-c94e128b0691" + }, + "source": [ + "# Train model on whole dataset\n", + "reader = Reader(rating_scale=(train_df['rating'].min(), train_df['rating'].max()))\n", + "data = Dataset.load_from_df(train_df[['userId', 'movieId', 'rating']], reader)\n", + "trainset = data.build_full_trainset()\n", + "\n", + "#hypertuned Model\n", + "svd = SVD(n_epochs = 40, n_factors = 600, init_std_dev = 0.005, random_state=42, verbose=True)\n", + "svd.fit(trainset)\n", + "predictions = svd.test(testset)\n", + "\n", + "# Compute RMSE\n", + "svd_rmse = accuracy.rmse(predictions)\n", + "\n", + "# Create Kaggle submission file\n", + "predictions = []\n", + "for i, row in test_df.iterrows():\n", + " x = (svd.predict(row.userId, row.movieId))\n", + " pred = x[3]\n", + " predictions.append(pred)\n", + "test_df['Id'] = test_df['userId'].map(str) +'_'+ test_df['movieId'].map(str)\n", + "results = pd.DataFrame({\"Id\":test_df['Id'],\"rating\": predictions})\n", + "results.to_csv(\"Team_CB6.csv\", index=False)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 424 + }, + "id": "7IP92cbwf8h9", + "outputId": "7f5e3c6c-74f9-4750-8865-7265db53100a" + }, + "outputs": [], + "source": [ + "pd.read_csv(\"Team_CB6.csv\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#end the commet experiment\n", + "experiment.end()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Pickling" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#Save model to pickle file\n", + "filename = \"SVD_model.pkl\"\n", + "outfile = open(filename, 'wb')\n", + "\n", + "pickle.dump(predictions, outfile)\n", + "outfile.close()\n", + "\n", + "loaded_model = pickle.load(open(\"SVD_model.pkl\",\"rb\"))\n", + "\n", + "#Converting predictions to a pkl file\n", + "results.to_pickle('SVD_model.pkl')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "References\n", + "https://developers.google.com/machine-learning/recommendation/content-based/basics\n", + "https://towardsdatascience.com/introduction-to-recommender-systems-1-971bd274f421\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Conclussion" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "CKvabYfURNK1" + }, + "source": [ + "# THE END" + ] + } + ], + "metadata": { + "colab": { + "name": "recommendation_predict.ipynb", + "provenance": [] + }, + "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.7.6" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/resources/imgs/TECHSAV.png b/resources/imgs/TECHSAV.png new file mode 100644 index 00000000..dec8f061 Binary files /dev/null and b/resources/imgs/TECHSAV.png differ diff --git a/resources/imgs/TECHSAVE.png b/resources/imgs/TECHSAVE.png new file mode 100644 index 00000000..ea1ecc13 Binary files /dev/null and b/resources/imgs/TECHSAVE.png differ diff --git a/resources/imgs/eda screenshot.png b/resources/imgs/eda screenshot.png new file mode 100644 index 00000000..c7fda007 Binary files /dev/null and b/resources/imgs/eda screenshot.png differ diff --git a/resources/imgs/ratings.png b/resources/imgs/ratings.png new file mode 100644 index 00000000..e5bc51ce Binary files /dev/null and b/resources/imgs/ratings.png differ