main 7e9b1dce2acf cached
6 files
1.0 MB
481.9k tokens
1 requests
Download .txt
Showing preview only (1,073K chars total). Download the full file or copy to clipboard to get everything.
Repository: rposhala/Recommender-System-on-MovieLens-dataset
Branch: main
Commit: 7e9b1dce2acf
Files: 6
Total size: 1.0 MB

Directory structure:
gitextract_6b3qicba/

├── Images/
│   └── .gitkeep
├── Item_based_Collaborative_Recommender_System_using_KNN.ipynb
├── Knowledge_based_Recommender_System.ipynb
├── README.md
├── Recommender_System_using_SVD.ipynb
└── Recommender_System_using_Softmax_DNN.ipynb

================================================
FILE CONTENTS
================================================

================================================
FILE: Images/.gitkeep
================================================



================================================
FILE: Item_based_Collaborative_Recommender_System_using_KNN.ipynb
================================================
{
  "nbformat": 4,
  "nbformat_minor": 0,
  "metadata": {
    "colab": {
      "name": "Item-based-Collaborative-Recommender-System-using-KNN.ipynb",
      "provenance": [],
      "collapsed_sections": [
        "jVJu1rsTx0F3"
      ],
      "authorship_tag": "ABX9TyM1K937XEBtUiFWogHB4DtZ",
      "include_colab_link": true
    },
    "kernelspec": {
      "name": "python3",
      "display_name": "Python 3"
    }
  },
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "view-in-github",
        "colab_type": "text"
      },
      "source": [
        "<a href=\"https://colab.research.google.com/github/rposhala/Recommender-System-on-MovieLens-dataset/blob/main/Item_based_Collaborative_Recommender_System_using_KNN.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "bwSPLalV6Rca"
      },
      "source": [
        "import os\n",
        "import numpy as np\n",
        "import pandas as pd\n",
        "import matplotlib.pyplot as plt\n",
        "from scipy.sparse import csr_matrix\n",
        "from sklearn.neighbors import NearestNeighbors"
      ],
      "execution_count": 113,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "HKw5H628aSY9"
      },
      "source": [
        "DATASET_LINK='http://files.grouplens.org/datasets/movielens/ml-100k.zip'"
      ],
      "execution_count": 114,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "gavevc8waXW_",
        "outputId": "138b5e41-3605-4838-f1f7-9eac9315c9c6",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 67
        }
      },
      "source": [
        "!wget -nc http://files.grouplens.org/datasets/movielens/ml-100k.zip\n",
        "!unzip -n ml-100k.zip"
      ],
      "execution_count": 115,
      "outputs": [
        {
          "output_type": "stream",
          "text": [
            "File ‘ml-100k.zip’ already there; not retrieving.\n",
            "\n",
            "Archive:  ml-100k.zip\n"
          ],
          "name": "stdout"
        }
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "d4WNkFXcauZ3"
      },
      "source": [
        "## Loading MovieLens dataset"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "3jZ7lU8RafYz"
      },
      "source": [
        "Loading u.info     -- The number of users, items, and ratings in the u data set."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "dEj5ZJQzaX-7",
        "outputId": "b73df5ec-cf04-491f-ad79-e2b9a8c26b16",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 34
        }
      },
      "source": [
        "overall_stats = pd.read_csv('ml-100k/u.info', header=None)\n",
        "print(\"Details of users, items and ratings involved in the loaded movielens dataset: \",list(overall_stats[0]))"
      ],
      "execution_count": 116,
      "outputs": [
        {
          "output_type": "stream",
          "text": [
            "Details of users, items and ratings involved in the loaded movielens dataset:  ['943 users', '1682 items', '100000 ratings']\n"
          ],
          "name": "stdout"
        }
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "aFzpbJ_Hap8V"
      },
      "source": [
        "Loading u.data     -- The full u data set, 100000 ratings by 943 users on 1682 items.\n",
        "\n",
        "---\n",
        "\n",
        "\n",
        "\n",
        "              Each user has rated at least 20 movies.  Users and items are\n",
        "              numbered consecutively from 1.  The data is randomly ordered. This is a tab separated list of \n",
        "\t         user id | item id | rating | timestamp. \n",
        "              The time stamps are unix seconds since 1/1/1970 UTC "
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "NXg9Sj7ralr4",
        "outputId": "0c8ac301-e92f-4682-df49-9c21c137dcd0",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 195
        }
      },
      "source": [
        "## same item id is same as movie id, item id column is renamed as movie id\n",
        "column_names1 = ['user id','movie id','rating','timestamp']\n",
        "dataset = pd.read_csv('ml-100k/u.data', sep='\\t',header=None,names=column_names1)\n",
        "dataset.head() "
      ],
      "execution_count": 117,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/html": [
              "<div>\n",
              "<style scoped>\n",
              "    .dataframe tbody tr th:only-of-type {\n",
              "        vertical-align: middle;\n",
              "    }\n",
              "\n",
              "    .dataframe tbody tr th {\n",
              "        vertical-align: top;\n",
              "    }\n",
              "\n",
              "    .dataframe thead th {\n",
              "        text-align: right;\n",
              "    }\n",
              "</style>\n",
              "<table border=\"1\" class=\"dataframe\">\n",
              "  <thead>\n",
              "    <tr style=\"text-align: right;\">\n",
              "      <th></th>\n",
              "      <th>user id</th>\n",
              "      <th>movie id</th>\n",
              "      <th>rating</th>\n",
              "      <th>timestamp</th>\n",
              "    </tr>\n",
              "  </thead>\n",
              "  <tbody>\n",
              "    <tr>\n",
              "      <th>0</th>\n",
              "      <td>196</td>\n",
              "      <td>242</td>\n",
              "      <td>3</td>\n",
              "      <td>881250949</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>1</th>\n",
              "      <td>186</td>\n",
              "      <td>302</td>\n",
              "      <td>3</td>\n",
              "      <td>891717742</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>2</th>\n",
              "      <td>22</td>\n",
              "      <td>377</td>\n",
              "      <td>1</td>\n",
              "      <td>878887116</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>3</th>\n",
              "      <td>244</td>\n",
              "      <td>51</td>\n",
              "      <td>2</td>\n",
              "      <td>880606923</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>4</th>\n",
              "      <td>166</td>\n",
              "      <td>346</td>\n",
              "      <td>1</td>\n",
              "      <td>886397596</td>\n",
              "    </tr>\n",
              "  </tbody>\n",
              "</table>\n",
              "</div>"
            ],
            "text/plain": [
              "   user id  movie id  rating  timestamp\n",
              "0      196       242       3  881250949\n",
              "1      186       302       3  891717742\n",
              "2       22       377       1  878887116\n",
              "3      244        51       2  880606923\n",
              "4      166       346       1  886397596"
            ]
          },
          "metadata": {
            "tags": []
          },
          "execution_count": 117
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "M2lYi6toa9tA",
        "outputId": "01b6797c-12cf-479f-fc6e-1889e088e8af",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 34
        }
      },
      "source": [
        "len(dataset), max(dataset['movie id']),min(dataset['movie id'])"
      ],
      "execution_count": 118,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "(100000, 1682, 1)"
            ]
          },
          "metadata": {
            "tags": []
          },
          "execution_count": 118
        }
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "9C9qVRfcbE0k"
      },
      "source": [
        "Loading u.item     -- Information about the items (movies); this is a tab separated\n",
        "\n",
        "              list of\n",
        "              movie id | movie title | release date | video release date |\n",
        "              IMDb URL | unknown | Action | Adventure | Animation |\n",
        "              Children's | Comedy | Crime | Documentary | Drama | Fantasy |\n",
        "              Film-Noir | Horror | Musical | Mystery | Romance | Sci-Fi |\n",
        "              Thriller | War | Western |\n",
        "              The last 19 fields are the genres, a 1 indicates the movie\n",
        "              is of that genre, a 0 indicates it is not; movies can be in\n",
        "              several genres at once.\n",
        "              The movie ids are the ones used in the u.data data set.\n"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "ZaMNuf9fbA0V",
        "outputId": "d0d0ced1-9bfb-404a-d0d4-e168cddc6ea0",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 420
        }
      },
      "source": [
        "d = 'movie id | movie title | release date | video release date | IMDb URL | unknown | Action | Adventure | Animation | Children | Comedy | Crime | Documentary | Drama | Fantasy | Film-Noir | Horror | Musical | Mystery | Romance | Sci-Fi | Thriller | War | Western'\n",
        "column_names2 = d.split(' | ')\n",
        "column_names2"
      ],
      "execution_count": 119,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "['movie id',\n",
              " 'movie title',\n",
              " 'release date',\n",
              " 'video release date',\n",
              " 'IMDb URL',\n",
              " 'unknown',\n",
              " 'Action',\n",
              " 'Adventure',\n",
              " 'Animation',\n",
              " 'Children',\n",
              " 'Comedy',\n",
              " 'Crime',\n",
              " 'Documentary',\n",
              " 'Drama',\n",
              " 'Fantasy',\n",
              " 'Film-Noir',\n",
              " 'Horror',\n",
              " 'Musical',\n",
              " 'Mystery',\n",
              " 'Romance',\n",
              " 'Sci-Fi',\n",
              " 'Thriller',\n",
              " 'War',\n",
              " 'Western']"
            ]
          },
          "metadata": {
            "tags": []
          },
          "execution_count": 119
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "Cv_sboAHbMp7",
        "outputId": "db4cb56c-afa3-4ad4-bef6-fd6937eaddf1",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 758
        }
      },
      "source": [
        "items_dataset = pd.read_csv('ml-100k/u.item', sep='|',header=None,names=column_names2,encoding='latin-1')\n",
        "items_dataset"
      ],
      "execution_count": 120,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/html": [
              "<div>\n",
              "<style scoped>\n",
              "    .dataframe tbody tr th:only-of-type {\n",
              "        vertical-align: middle;\n",
              "    }\n",
              "\n",
              "    .dataframe tbody tr th {\n",
              "        vertical-align: top;\n",
              "    }\n",
              "\n",
              "    .dataframe thead th {\n",
              "        text-align: right;\n",
              "    }\n",
              "</style>\n",
              "<table border=\"1\" class=\"dataframe\">\n",
              "  <thead>\n",
              "    <tr style=\"text-align: right;\">\n",
              "      <th></th>\n",
              "      <th>movie id</th>\n",
              "      <th>movie title</th>\n",
              "      <th>release date</th>\n",
              "      <th>video release date</th>\n",
              "      <th>IMDb URL</th>\n",
              "      <th>unknown</th>\n",
              "      <th>Action</th>\n",
              "      <th>Adventure</th>\n",
              "      <th>Animation</th>\n",
              "      <th>Children</th>\n",
              "      <th>Comedy</th>\n",
              "      <th>Crime</th>\n",
              "      <th>Documentary</th>\n",
              "      <th>Drama</th>\n",
              "      <th>Fantasy</th>\n",
              "      <th>Film-Noir</th>\n",
              "      <th>Horror</th>\n",
              "      <th>Musical</th>\n",
              "      <th>Mystery</th>\n",
              "      <th>Romance</th>\n",
              "      <th>Sci-Fi</th>\n",
              "      <th>Thriller</th>\n",
              "      <th>War</th>\n",
              "      <th>Western</th>\n",
              "    </tr>\n",
              "  </thead>\n",
              "  <tbody>\n",
              "    <tr>\n",
              "      <th>0</th>\n",
              "      <td>1</td>\n",
              "      <td>Toy Story (1995)</td>\n",
              "      <td>01-Jan-1995</td>\n",
              "      <td>NaN</td>\n",
              "      <td>http://us.imdb.com/M/title-exact?Toy%20Story%2...</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>1</td>\n",
              "      <td>1</td>\n",
              "      <td>1</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>1</th>\n",
              "      <td>2</td>\n",
              "      <td>GoldenEye (1995)</td>\n",
              "      <td>01-Jan-1995</td>\n",
              "      <td>NaN</td>\n",
              "      <td>http://us.imdb.com/M/title-exact?GoldenEye%20(...</td>\n",
              "      <td>0</td>\n",
              "      <td>1</td>\n",
              "      <td>1</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>1</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>2</th>\n",
              "      <td>3</td>\n",
              "      <td>Four Rooms (1995)</td>\n",
              "      <td>01-Jan-1995</td>\n",
              "      <td>NaN</td>\n",
              "      <td>http://us.imdb.com/M/title-exact?Four%20Rooms%...</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>1</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>3</th>\n",
              "      <td>4</td>\n",
              "      <td>Get Shorty (1995)</td>\n",
              "      <td>01-Jan-1995</td>\n",
              "      <td>NaN</td>\n",
              "      <td>http://us.imdb.com/M/title-exact?Get%20Shorty%...</td>\n",
              "      <td>0</td>\n",
              "      <td>1</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>1</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>1</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>4</th>\n",
              "      <td>5</td>\n",
              "      <td>Copycat (1995)</td>\n",
              "      <td>01-Jan-1995</td>\n",
              "      <td>NaN</td>\n",
              "      <td>http://us.imdb.com/M/title-exact?Copycat%20(1995)</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>1</td>\n",
              "      <td>0</td>\n",
              "      <td>1</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>1</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>...</th>\n",
              "      <td>...</td>\n",
              "      <td>...</td>\n",
              "      <td>...</td>\n",
              "      <td>...</td>\n",
              "      <td>...</td>\n",
              "      <td>...</td>\n",
              "      <td>...</td>\n",
              "      <td>...</td>\n",
              "      <td>...</td>\n",
              "      <td>...</td>\n",
              "      <td>...</td>\n",
              "      <td>...</td>\n",
              "      <td>...</td>\n",
              "      <td>...</td>\n",
              "      <td>...</td>\n",
              "      <td>...</td>\n",
              "      <td>...</td>\n",
              "      <td>...</td>\n",
              "      <td>...</td>\n",
              "      <td>...</td>\n",
              "      <td>...</td>\n",
              "      <td>...</td>\n",
              "      <td>...</td>\n",
              "      <td>...</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>1677</th>\n",
              "      <td>1678</td>\n",
              "      <td>Mat' i syn (1997)</td>\n",
              "      <td>06-Feb-1998</td>\n",
              "      <td>NaN</td>\n",
              "      <td>http://us.imdb.com/M/title-exact?Mat%27+i+syn+...</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>1</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>1678</th>\n",
              "      <td>1679</td>\n",
              "      <td>B. Monkey (1998)</td>\n",
              "      <td>06-Feb-1998</td>\n",
              "      <td>NaN</td>\n",
              "      <td>http://us.imdb.com/M/title-exact?B%2E+Monkey+(...</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>1</td>\n",
              "      <td>0</td>\n",
              "      <td>1</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>1679</th>\n",
              "      <td>1680</td>\n",
              "      <td>Sliding Doors (1998)</td>\n",
              "      <td>01-Jan-1998</td>\n",
              "      <td>NaN</td>\n",
              "      <td>http://us.imdb.com/Title?Sliding+Doors+(1998)</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>1</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>1</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>1680</th>\n",
              "      <td>1681</td>\n",
              "      <td>You So Crazy (1994)</td>\n",
              "      <td>01-Jan-1994</td>\n",
              "      <td>NaN</td>\n",
              "      <td>http://us.imdb.com/M/title-exact?You%20So%20Cr...</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>1</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>1681</th>\n",
              "      <td>1682</td>\n",
              "      <td>Scream of Stone (Schrei aus Stein) (1991)</td>\n",
              "      <td>08-Mar-1996</td>\n",
              "      <td>NaN</td>\n",
              "      <td>http://us.imdb.com/M/title-exact?Schrei%20aus%...</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>1</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "      <td>0</td>\n",
              "    </tr>\n",
              "  </tbody>\n",
              "</table>\n",
              "<p>1682 rows × 24 columns</p>\n",
              "</div>"
            ],
            "text/plain": [
              "      movie id                                movie title  ... War  Western\n",
              "0            1                           Toy Story (1995)  ...   0        0\n",
              "1            2                           GoldenEye (1995)  ...   0        0\n",
              "2            3                          Four Rooms (1995)  ...   0        0\n",
              "3            4                          Get Shorty (1995)  ...   0        0\n",
              "4            5                             Copycat (1995)  ...   0        0\n",
              "...        ...                                        ...  ...  ..      ...\n",
              "1677      1678                          Mat' i syn (1997)  ...   0        0\n",
              "1678      1679                           B. Monkey (1998)  ...   0        0\n",
              "1679      1680                       Sliding Doors (1998)  ...   0        0\n",
              "1680      1681                        You So Crazy (1994)  ...   0        0\n",
              "1681      1682  Scream of Stone (Schrei aus Stein) (1991)  ...   0        0\n",
              "\n",
              "[1682 rows x 24 columns]"
            ]
          },
          "metadata": {
            "tags": []
          },
          "execution_count": 120
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "VFhUx9zsbQpD",
        "outputId": "d6bf0a5a-4dd8-4923-9b91-c50a04bef417",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 195
        }
      },
      "source": [
        "movie_dataset = items_dataset[['movie id','movie title']]\n",
        "movie_dataset.head()"
      ],
      "execution_count": 121,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/html": [
              "<div>\n",
              "<style scoped>\n",
              "    .dataframe tbody tr th:only-of-type {\n",
              "        vertical-align: middle;\n",
              "    }\n",
              "\n",
              "    .dataframe tbody tr th {\n",
              "        vertical-align: top;\n",
              "    }\n",
              "\n",
              "    .dataframe thead th {\n",
              "        text-align: right;\n",
              "    }\n",
              "</style>\n",
              "<table border=\"1\" class=\"dataframe\">\n",
              "  <thead>\n",
              "    <tr style=\"text-align: right;\">\n",
              "      <th></th>\n",
              "      <th>movie id</th>\n",
              "      <th>movie title</th>\n",
              "    </tr>\n",
              "  </thead>\n",
              "  <tbody>\n",
              "    <tr>\n",
              "      <th>0</th>\n",
              "      <td>1</td>\n",
              "      <td>Toy Story (1995)</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>1</th>\n",
              "      <td>2</td>\n",
              "      <td>GoldenEye (1995)</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>2</th>\n",
              "      <td>3</td>\n",
              "      <td>Four Rooms (1995)</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>3</th>\n",
              "      <td>4</td>\n",
              "      <td>Get Shorty (1995)</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>4</th>\n",
              "      <td>5</td>\n",
              "      <td>Copycat (1995)</td>\n",
              "    </tr>\n",
              "  </tbody>\n",
              "</table>\n",
              "</div>"
            ],
            "text/plain": [
              "   movie id        movie title\n",
              "0         1   Toy Story (1995)\n",
              "1         2   GoldenEye (1995)\n",
              "2         3  Four Rooms (1995)\n",
              "3         4  Get Shorty (1995)\n",
              "4         5     Copycat (1995)"
            ]
          },
          "metadata": {
            "tags": []
          },
          "execution_count": 121
        }
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Wr2cmp5impC7"
      },
      "source": [
        "Looking at length of original items_dataset and length of unique combination of rows in items_dataset after removing movie id column"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "iIwj68LWGeQX",
        "outputId": "1df25549-276e-49fc-950f-139f79f493e2",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 34
        }
      },
      "source": [
        "## looking at length of original items_dataset and length of unique combination of rows in items_dataset after removing movie id column\n",
        "len(items_dataset.groupby(by=column_names2[1:])),len(items_dataset)"
      ],
      "execution_count": 122,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "(1664, 1682)"
            ]
          },
          "metadata": {
            "tags": []
          },
          "execution_count": 122
        }
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "AfBNIWO7mqjc"
      },
      "source": [
        "We can see there are 18 extra movie id's for already mapped movie title and the same duplicate movie id is assigned to the user in the user-item dataset."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "nwdvxUdkbiPK"
      },
      "source": [
        "## Merging required datasets"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "-fKazhqFbcAq",
        "outputId": "636990d0-c78b-4b1e-f269-dec12c317de3",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 195
        }
      },
      "source": [
        "merged_dataset = pd.merge(dataset, movie_dataset, how='inner', on='movie id')\n",
        "merged_dataset.head()"
      ],
      "execution_count": 123,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/html": [
              "<div>\n",
              "<style scoped>\n",
              "    .dataframe tbody tr th:only-of-type {\n",
              "        vertical-align: middle;\n",
              "    }\n",
              "\n",
              "    .dataframe tbody tr th {\n",
              "        vertical-align: top;\n",
              "    }\n",
              "\n",
              "    .dataframe thead th {\n",
              "        text-align: right;\n",
              "    }\n",
              "</style>\n",
              "<table border=\"1\" class=\"dataframe\">\n",
              "  <thead>\n",
              "    <tr style=\"text-align: right;\">\n",
              "      <th></th>\n",
              "      <th>user id</th>\n",
              "      <th>movie id</th>\n",
              "      <th>rating</th>\n",
              "      <th>timestamp</th>\n",
              "      <th>movie title</th>\n",
              "    </tr>\n",
              "  </thead>\n",
              "  <tbody>\n",
              "    <tr>\n",
              "      <th>0</th>\n",
              "      <td>196</td>\n",
              "      <td>242</td>\n",
              "      <td>3</td>\n",
              "      <td>881250949</td>\n",
              "      <td>Kolya (1996)</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>1</th>\n",
              "      <td>63</td>\n",
              "      <td>242</td>\n",
              "      <td>3</td>\n",
              "      <td>875747190</td>\n",
              "      <td>Kolya (1996)</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>2</th>\n",
              "      <td>226</td>\n",
              "      <td>242</td>\n",
              "      <td>5</td>\n",
              "      <td>883888671</td>\n",
              "      <td>Kolya (1996)</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>3</th>\n",
              "      <td>154</td>\n",
              "      <td>242</td>\n",
              "      <td>3</td>\n",
              "      <td>879138235</td>\n",
              "      <td>Kolya (1996)</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>4</th>\n",
              "      <td>306</td>\n",
              "      <td>242</td>\n",
              "      <td>5</td>\n",
              "      <td>876503793</td>\n",
              "      <td>Kolya (1996)</td>\n",
              "    </tr>\n",
              "  </tbody>\n",
              "</table>\n",
              "</div>"
            ],
            "text/plain": [
              "   user id  movie id  rating  timestamp   movie title\n",
              "0      196       242       3  881250949  Kolya (1996)\n",
              "1       63       242       3  875747190  Kolya (1996)\n",
              "2      226       242       5  883888671  Kolya (1996)\n",
              "3      154       242       3  879138235  Kolya (1996)\n",
              "4      306       242       5  876503793  Kolya (1996)"
            ]
          },
          "metadata": {
            "tags": []
          },
          "execution_count": 123
        }
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "ELmLkEQBnxv1"
      },
      "source": [
        "A dataset is created from the existing merged dataset by grouping the unique user id and movie title combination and the ratings by a user to the same movie in different instances (timestamps) are averaged and stored in the new dataset."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "zd2jR0cFouee"
      },
      "source": [
        "Example of a multiple rating scenario by an user to a specific movie:"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "HQ6owSOikYMq",
        "outputId": "496ac596-719b-4ad3-bf8f-79cae6e0e88d",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 106
        }
      },
      "source": [
        "merged_dataset[(merged_dataset['movie title'] == 'Chasing Amy (1997)') & (merged_dataset['user id'] == 894)]"
      ],
      "execution_count": 124,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/html": [
              "<div>\n",
              "<style scoped>\n",
              "    .dataframe tbody tr th:only-of-type {\n",
              "        vertical-align: middle;\n",
              "    }\n",
              "\n",
              "    .dataframe tbody tr th {\n",
              "        vertical-align: top;\n",
              "    }\n",
              "\n",
              "    .dataframe thead th {\n",
              "        text-align: right;\n",
              "    }\n",
              "</style>\n",
              "<table border=\"1\" class=\"dataframe\">\n",
              "  <thead>\n",
              "    <tr style=\"text-align: right;\">\n",
              "      <th></th>\n",
              "      <th>user id</th>\n",
              "      <th>movie id</th>\n",
              "      <th>rating</th>\n",
              "      <th>timestamp</th>\n",
              "      <th>movie title</th>\n",
              "    </tr>\n",
              "  </thead>\n",
              "  <tbody>\n",
              "    <tr>\n",
              "      <th>4800</th>\n",
              "      <td>894</td>\n",
              "      <td>246</td>\n",
              "      <td>4</td>\n",
              "      <td>882404137</td>\n",
              "      <td>Chasing Amy (1997)</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>22340</th>\n",
              "      <td>894</td>\n",
              "      <td>268</td>\n",
              "      <td>3</td>\n",
              "      <td>879896041</td>\n",
              "      <td>Chasing Amy (1997)</td>\n",
              "    </tr>\n",
              "  </tbody>\n",
              "</table>\n",
              "</div>"
            ],
            "text/plain": [
              "       user id  movie id  rating  timestamp         movie title\n",
              "4800       894       246       4  882404137  Chasing Amy (1997)\n",
              "22340      894       268       3  879896041  Chasing Amy (1997)"
            ]
          },
          "metadata": {
            "tags": []
          },
          "execution_count": 124
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "p5XS_3dPhCVb",
        "outputId": "f122409a-556b-4dd7-eeb0-1c98b280c81d",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 195
        }
      },
      "source": [
        "refined_dataset = merged_dataset.groupby(by=['user id','movie title'], as_index=False).agg({\"rating\":\"mean\"})\n",
        "\n",
        "refined_dataset.head()"
      ],
      "execution_count": 125,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/html": [
              "<div>\n",
              "<style scoped>\n",
              "    .dataframe tbody tr th:only-of-type {\n",
              "        vertical-align: middle;\n",
              "    }\n",
              "\n",
              "    .dataframe tbody tr th {\n",
              "        vertical-align: top;\n",
              "    }\n",
              "\n",
              "    .dataframe thead th {\n",
              "        text-align: right;\n",
              "    }\n",
              "</style>\n",
              "<table border=\"1\" class=\"dataframe\">\n",
              "  <thead>\n",
              "    <tr style=\"text-align: right;\">\n",
              "      <th></th>\n",
              "      <th>user id</th>\n",
              "      <th>movie title</th>\n",
              "      <th>rating</th>\n",
              "    </tr>\n",
              "  </thead>\n",
              "  <tbody>\n",
              "    <tr>\n",
              "      <th>0</th>\n",
              "      <td>1</td>\n",
              "      <td>101 Dalmatians (1996)</td>\n",
              "      <td>2.0</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>1</th>\n",
              "      <td>1</td>\n",
              "      <td>12 Angry Men (1957)</td>\n",
              "      <td>5.0</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>2</th>\n",
              "      <td>1</td>\n",
              "      <td>20,000 Leagues Under the Sea (1954)</td>\n",
              "      <td>3.0</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>3</th>\n",
              "      <td>1</td>\n",
              "      <td>2001: A Space Odyssey (1968)</td>\n",
              "      <td>4.0</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>4</th>\n",
              "      <td>1</td>\n",
              "      <td>Abyss, The (1989)</td>\n",
              "      <td>3.0</td>\n",
              "    </tr>\n",
              "  </tbody>\n",
              "</table>\n",
              "</div>"
            ],
            "text/plain": [
              "   user id                          movie title  rating\n",
              "0        1                101 Dalmatians (1996)     2.0\n",
              "1        1                  12 Angry Men (1957)     5.0\n",
              "2        1  20,000 Leagues Under the Sea (1954)     3.0\n",
              "3        1         2001: A Space Odyssey (1968)     4.0\n",
              "4        1                    Abyss, The (1989)     3.0"
            ]
          },
          "metadata": {
            "tags": []
          },
          "execution_count": 125
        }
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "W_HNZ2j9dP5O"
      },
      "source": [
        "## Exploratory data analysis\n",
        "\n",
        "*   Plot the counts of each rating\n",
        "*   Plot rating frequency of each movie"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "i_cInoHOrk4o"
      },
      "source": [
        "**Plot the counts of each rating**\n",
        "\n",
        "we first need to get the counts of each rating from ratings data"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "qkoNLoyabl42",
        "outputId": "e71b61e0-1106-4cc1-f4af-b4cbce4d6400",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 50
        }
      },
      "source": [
        "# num_users = len(refined_dataset.rating.unique())\n",
        "# num_items = len(refined_dataset.movieId.unique())\n",
        "num_users = len(refined_dataset['user id'].value_counts())\n",
        "num_items = len(refined_dataset['movie title'].value_counts())\n",
        "print('Unique number of users in the dataset: {}'.format(num_users))\n",
        "print('Unique number of movies in the dataset: {}'.format(num_items))\n"
      ],
      "execution_count": 126,
      "outputs": [
        {
          "output_type": "stream",
          "text": [
            "Unique number of users in the dataset: 943\n",
            "Unique number of movies in the dataset: 1664\n"
          ],
          "name": "stdout"
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "Ea3fORd-r24Z",
        "outputId": "1aed76ea-4851-436e-943a-1eb45473905b",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 343
        }
      },
      "source": [
        "rating_count_df = pd.DataFrame(refined_dataset.groupby(['rating']).size(), columns=['count'])\n",
        "rating_count_df"
      ],
      "execution_count": 127,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/html": [
              "<div>\n",
              "<style scoped>\n",
              "    .dataframe tbody tr th:only-of-type {\n",
              "        vertical-align: middle;\n",
              "    }\n",
              "\n",
              "    .dataframe tbody tr th {\n",
              "        vertical-align: top;\n",
              "    }\n",
              "\n",
              "    .dataframe thead th {\n",
              "        text-align: right;\n",
              "    }\n",
              "</style>\n",
              "<table border=\"1\" class=\"dataframe\">\n",
              "  <thead>\n",
              "    <tr style=\"text-align: right;\">\n",
              "      <th></th>\n",
              "      <th>count</th>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>rating</th>\n",
              "      <th></th>\n",
              "    </tr>\n",
              "  </thead>\n",
              "  <tbody>\n",
              "    <tr>\n",
              "      <th>1.0</th>\n",
              "      <td>6083</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>1.5</th>\n",
              "      <td>3</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>2.0</th>\n",
              "      <td>11334</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>2.5</th>\n",
              "      <td>6</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>3.0</th>\n",
              "      <td>27060</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>3.5</th>\n",
              "      <td>19</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>4.0</th>\n",
              "      <td>34042</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>4.5</th>\n",
              "      <td>16</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>5.0</th>\n",
              "      <td>21130</td>\n",
              "    </tr>\n",
              "  </tbody>\n",
              "</table>\n",
              "</div>"
            ],
            "text/plain": [
              "        count\n",
              "rating       \n",
              "1.0      6083\n",
              "1.5         3\n",
              "2.0     11334\n",
              "2.5         6\n",
              "3.0     27060\n",
              "3.5        19\n",
              "4.0     34042\n",
              "4.5        16\n",
              "5.0     21130"
            ]
          },
          "metadata": {
            "tags": []
          },
          "execution_count": 127
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "BbcBMiiC0GIl",
        "outputId": "b777075a-17f1-44a5-d239-808d729274a4",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 539
        }
      },
      "source": [
        "ax = rating_count_df.reset_index().rename(columns={'index': 'rating score'}).plot('rating','count', 'bar',\n",
        "    figsize=(12, 8),\n",
        "    title='Count for Each Rating Score',\n",
        "    fontsize=12)\n",
        "\n",
        "ax.set_xlabel(\"movie rating score\")\n",
        "ax.set_ylabel(\"number of ratings\")"
      ],
      "execution_count": 128,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "Text(0, 0.5, 'number of ratings')"
            ]
          },
          "metadata": {
            "tags": []
          },
          "execution_count": 128
        },
        {
          "output_type": "display_data",
          "data": {
            "image/png": "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jq/rNOA0gIULF9amHZ0kSZIGMffNF2/R/V333mdt0f1tilNOOYWXvvSl3O9+99vsfU317RJnMvEc87FQvF1VraQ35WVBX/sCYGm3vLS/LcmO3T6XDtBXkiRJ08zZZ5/NAQccwIIFC3jZy17Gddddx9Oe9jQOOOAADj30UH7yk58AcMwxx/Cv//qv9/SbPbs3GePyyy/nqU99Ki984QuZN28eRx11FFXFqaeeyg033MAhhxzCIYccstl1Di2YJ3lAkiOSzE4yI8kzgJcAX0xyUJJHJNkuyW7AqcDlVTU2BeVs4IQku3QXdR4LnNm1XQg8OsnhSWYBbweWVNW1A/SVJEnSNLJ06VJOOukkvvSlL7F48WL+7u/+jje84Q0cffTRLFmyhKOOOorjjz9+0v18+9vf5pRTTuG73/0uP/rRj7jyyis5/vjjedCDHsRll13GZZddttm1DnPEvIDXANcDK4EPAH9SVRcBDwUuoTfF5L/ozTt/SV/fd9C7oHMZ8GXg5LHbHVbVcuBw4N3dfg8CjhikryRJkqaXL33pS7zoRS9i9913B2DXXXfl61//OkceeSQAL3vZy7jiiism3c/jH/949t57b7bbbjsOPPBArrvuui1e69DmmHcB+inraTsXOHcDfdcBr+heE7VfCsxbT9sG+0qSJEkTmTlzJnfffTcAd999N7fffvs9bTvssMM9yzNmzODOOyd6FM/mmeo55pIkSdKUedrTnsb555/PihW951v+4he/4IlPfCL/8i//AsA555zDwQcfDMDcuXO56qqrALjooou44447Jt3/nDlzWL16wvuMbLQpuSuLJEmSNArz58/nrW99K095ylOYMWMGv/3bv83f//3f8/KXv5yTTz6ZPfbYg49//OMAHHvssTzvec9jwYIFHHbYYey4446T7v+4447jsMMOu2eu+eZIlXcJhN7tEhctWjT5hpIkSRrINddcwyMf+chRlzEyEx1/kquqauFE2zuVRZIkSWqAwVySJElqgMFckiRJaoAXf0qSpM2ypR+zviW08Kh29VQVSUZdxpTblOs4HTGXJEnSUMyaNYsVK1ZsUkjdmlUVK1asYNasWRvVzxFzSZIkDcXee+/N9ddfz/Lly0ddypSbNWsWe++990b1MZhLkiRpKLbffnse8pCHjLqMrYZTWSRJkqQGGMwlSZKkBhjMJUmSpAYY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\n",
            "text/plain": [
              "<Figure size 864x576 with 1 Axes>"
            ]
          },
          "metadata": {
            "tags": [],
            "needs_background": "light"
          }
        }
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "zM7NoOXG1vYU"
      },
      "source": [
        "We can see that number of 1.5, 2.5, 3.5, 4.5 ratings by the users are comparitively negligible."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "cXYlt0OFxP1z"
      },
      "source": [
        "Ratings for the movies not seen by a user is by default considered as 0. Lets calculate and add it to the existing dataframe."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "lgyPInMAwQAv",
        "outputId": "10191306-986d-469f-dd46-5be593208c7f",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 34
        }
      },
      "source": [
        "total_count = num_items * num_users\n",
        "zero_count = total_count-refined_dataset.shape[0]\n",
        "zero_count"
      ],
      "execution_count": 129,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "1469459"
            ]
          },
          "metadata": {
            "tags": []
          },
          "execution_count": 129
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "avyj8_8ewjA_",
        "outputId": "8e6b1763-1ea6-45ed-e86c-8ec1216e1fe4",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 343
        }
      },
      "source": [
        "# append counts of zero rating to df_ratings_cnt\n",
        "rating_count_df = rating_count_df.append(\n",
        "    pd.DataFrame({'count': zero_count}, index=[0.0]),\n",
        "    verify_integrity=True,\n",
        ").sort_index()\n",
        "rating_count_df"
      ],
      "execution_count": 130,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/html": [
              "<div>\n",
              "<style scoped>\n",
              "    .dataframe tbody tr th:only-of-type {\n",
              "        vertical-align: middle;\n",
              "    }\n",
              "\n",
              "    .dataframe tbody tr th {\n",
              "        vertical-align: top;\n",
              "    }\n",
              "\n",
              "    .dataframe thead th {\n",
              "        text-align: right;\n",
              "    }\n",
              "</style>\n",
              "<table border=\"1\" class=\"dataframe\">\n",
              "  <thead>\n",
              "    <tr style=\"text-align: right;\">\n",
              "      <th></th>\n",
              "      <th>count</th>\n",
              "    </tr>\n",
              "  </thead>\n",
              "  <tbody>\n",
              "    <tr>\n",
              "      <th>0.0</th>\n",
              "      <td>1469459</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>1.0</th>\n",
              "      <td>6083</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>1.5</th>\n",
              "      <td>3</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>2.0</th>\n",
              "      <td>11334</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>2.5</th>\n",
              "      <td>6</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>3.0</th>\n",
              "      <td>27060</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>3.5</th>\n",
              "      <td>19</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>4.0</th>\n",
              "      <td>34042</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>4.5</th>\n",
              "      <td>16</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>5.0</th>\n",
              "      <td>21130</td>\n",
              "    </tr>\n",
              "  </tbody>\n",
              "</table>\n",
              "</div>"
            ],
            "text/plain": [
              "       count\n",
              "0.0  1469459\n",
              "1.0     6083\n",
              "1.5        3\n",
              "2.0    11334\n",
              "2.5        6\n",
              "3.0    27060\n",
              "3.5       19\n",
              "4.0    34042\n",
              "4.5       16\n",
              "5.0    21130"
            ]
          },
          "metadata": {
            "tags": []
          },
          "execution_count": 130
        }
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Ofd8LQcVxvYA"
      },
      "source": [
        "Number of times no rating was given (forged as 0 in this case) is a lot more than other ratings."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "f7ngnrerysBV"
      },
      "source": [
        "So let's take log transform for count values and then we can plot them to compare"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "ACZx4jhKxtGH",
        "outputId": "43772624-dd68-4665-dab7-776df6fb0200",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 343
        }
      },
      "source": [
        "# add log count\n",
        "rating_count_df['log_count'] = np.log(rating_count_df['count'])\n",
        "rating_count_df"
      ],
      "execution_count": 131,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/html": [
              "<div>\n",
              "<style scoped>\n",
              "    .dataframe tbody tr th:only-of-type {\n",
              "        vertical-align: middle;\n",
              "    }\n",
              "\n",
              "    .dataframe tbody tr th {\n",
              "        vertical-align: top;\n",
              "    }\n",
              "\n",
              "    .dataframe thead th {\n",
              "        text-align: right;\n",
              "    }\n",
              "</style>\n",
              "<table border=\"1\" class=\"dataframe\">\n",
              "  <thead>\n",
              "    <tr style=\"text-align: right;\">\n",
              "      <th></th>\n",
              "      <th>count</th>\n",
              "      <th>log_count</th>\n",
              "    </tr>\n",
              "  </thead>\n",
              "  <tbody>\n",
              "    <tr>\n",
              "      <th>0.0</th>\n",
              "      <td>1469459</td>\n",
              "      <td>14.200405</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>1.0</th>\n",
              "      <td>6083</td>\n",
              "      <td>8.713253</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>1.5</th>\n",
              "      <td>3</td>\n",
              "      <td>1.098612</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>2.0</th>\n",
              "      <td>11334</td>\n",
              "      <td>9.335562</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>2.5</th>\n",
              "      <td>6</td>\n",
              "      <td>1.791759</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>3.0</th>\n",
              "      <td>27060</td>\n",
              "      <td>10.205812</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>3.5</th>\n",
              "      <td>19</td>\n",
              "      <td>2.944439</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>4.0</th>\n",
              "      <td>34042</td>\n",
              "      <td>10.435350</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>4.5</th>\n",
              "      <td>16</td>\n",
              "      <td>2.772589</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>5.0</th>\n",
              "      <td>21130</td>\n",
              "      <td>9.958449</td>\n",
              "    </tr>\n",
              "  </tbody>\n",
              "</table>\n",
              "</div>"
            ],
            "text/plain": [
              "       count  log_count\n",
              "0.0  1469459  14.200405\n",
              "1.0     6083   8.713253\n",
              "1.5        3   1.098612\n",
              "2.0    11334   9.335562\n",
              "2.5        6   1.791759\n",
              "3.0    27060  10.205812\n",
              "3.5       19   2.944439\n",
              "4.0    34042  10.435350\n",
              "4.5       16   2.772589\n",
              "5.0    21130   9.958449"
            ]
          },
          "metadata": {
            "tags": []
          },
          "execution_count": 131
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "J2LE9usIy1Mz",
        "outputId": "b0bd7926-7d36-4e9d-ec5b-f9f090ef228d",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 343
        }
      },
      "source": [
        "rating_count_df = rating_count_df.reset_index().rename(columns={'index': 'rating score'})\n",
        "rating_count_df"
      ],
      "execution_count": 132,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/html": [
              "<div>\n",
              "<style scoped>\n",
              "    .dataframe tbody tr th:only-of-type {\n",
              "        vertical-align: middle;\n",
              "    }\n",
              "\n",
              "    .dataframe tbody tr th {\n",
              "        vertical-align: top;\n",
              "    }\n",
              "\n",
              "    .dataframe thead th {\n",
              "        text-align: right;\n",
              "    }\n",
              "</style>\n",
              "<table border=\"1\" class=\"dataframe\">\n",
              "  <thead>\n",
              "    <tr style=\"text-align: right;\">\n",
              "      <th></th>\n",
              "      <th>rating score</th>\n",
              "      <th>count</th>\n",
              "      <th>log_count</th>\n",
              "    </tr>\n",
              "  </thead>\n",
              "  <tbody>\n",
              "    <tr>\n",
              "      <th>0</th>\n",
              "      <td>0.0</td>\n",
              "      <td>1469459</td>\n",
              "      <td>14.200405</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>1</th>\n",
              "      <td>1.0</td>\n",
              "      <td>6083</td>\n",
              "      <td>8.713253</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>2</th>\n",
              "      <td>1.5</td>\n",
              "      <td>3</td>\n",
              "      <td>1.098612</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>3</th>\n",
              "      <td>2.0</td>\n",
              "      <td>11334</td>\n",
              "      <td>9.335562</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>4</th>\n",
              "      <td>2.5</td>\n",
              "      <td>6</td>\n",
              "      <td>1.791759</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>5</th>\n",
              "      <td>3.0</td>\n",
              "      <td>27060</td>\n",
              "      <td>10.205812</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>6</th>\n",
              "      <td>3.5</td>\n",
              "      <td>19</td>\n",
              "      <td>2.944439</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>7</th>\n",
              "      <td>4.0</td>\n",
              "      <td>34042</td>\n",
              "      <td>10.435350</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>8</th>\n",
              "      <td>4.5</td>\n",
              "      <td>16</td>\n",
              "      <td>2.772589</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>9</th>\n",
              "      <td>5.0</td>\n",
              "      <td>21130</td>\n",
              "      <td>9.958449</td>\n",
              "    </tr>\n",
              "  </tbody>\n",
              "</table>\n",
              "</div>"
            ],
            "text/plain": [
              "   rating score    count  log_count\n",
              "0           0.0  1469459  14.200405\n",
              "1           1.0     6083   8.713253\n",
              "2           1.5        3   1.098612\n",
              "3           2.0    11334   9.335562\n",
              "4           2.5        6   1.791759\n",
              "5           3.0    27060  10.205812\n",
              "6           3.5       19   2.944439\n",
              "7           4.0    34042  10.435350\n",
              "8           4.5       16   2.772589\n",
              "9           5.0    21130   9.958449"
            ]
          },
          "metadata": {
            "tags": []
          },
          "execution_count": 132
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "vb5wAmR4zg7s",
        "outputId": "8b822e7a-4e99-460e-e78f-2e4fa97bf9af",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 539
        }
      },
      "source": [
        "ax = rating_count_df.plot('rating score', 'log_count', 'bar', figsize=(12, 8),\n",
        "    title='Count for Each Rating Score (in Log Scale)',\n",
        "    logy=True,\n",
        "    fontsize=12,)\n",
        "\n",
        "ax.set_xlabel(\"movie rating score\")\n",
        "ax.set_ylabel(\"number of ratings\")"
      ],
      "execution_count": 133,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "Text(0, 0.5, 'number of ratings')"
            ]
          },
          "metadata": {
            "tags": []
          },
          "execution_count": 133
        },
        {
          "output_type": "display_data",
          "data": {
            "image/png": "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XWTZWrs+yRP79/zvdJ/3cRv4vrNqrV2c5Mx04enf0100eWm6YQk3ZfUhBx/r/7u8qjZmOrcXpBvnuzzdz/Gk9MNRZnFdut77H6QbTvCOJEe01lb9nF+UblzvN5NclW6Melp3MeqbkvxLuuB4/3QXts6qtXZ+klekuwj0p+kuvHvJOj7DcUlesEbP8e3xvCQ/H3l8d13nWn++/Va6oTvX9vt9Mmtvx58leWe68+aadOOvn9Va+14/ZOTQdL3KP0hyebqpGZPuQuB90/3l4vQkJ6/jM7w73YW0/1FV16e7iHL0H38vSBfAgTlSqw8VA2Ahqu6mMN9srf3JpGvZEFX1z+kuODxlvTvPg6r6UpL3tdb+cdK1rKmq7p5u6sKHttbWNU4duB2Ea4AFqKr2T/KTJJcleVK6v1D8emvtaxMtbMpU1WPSzWhyTWZ6he/XD5cBFiCzhQAsTPdIN7zgLumGIBwhWG+UB6Ubl33HJN9L8mzBGhY2PdcAADAQFzQCAMBAhGsAABjIZjPm+q53vWtbunTppMsAAGAz95WvfOWa1trdZtu22YTrpUuX5vzzz590GQAAbOaqaq03YjIsBAAABiJcAwDAQIRrAAAYyGYz5hoAYKH75S9/mcsvvzw33eQO90NYvHhxdt5552y11VZjv0a4BgDYTFx++eXZfvvts3Tp0lTVpMuZaq21LF++PJdffnl23XXXsV9nWAgAwGbipptuyl3uchfBegBVlbvc5S4b/FcA4RoAYDMiWA9nY9pSuAYAgIEYcw0AsJlaevTpgx5v2bFPXe8+2223XW644YZB33cunXLKKXngAx+YPffcc5Dj6bkGAGDBOuWUU/L1r399sOMJ1wAADK61lqOOOiq/9mu/lr322isnnXRSkmTlypU58sgjs/vuu+eJT3xinvKUp+TjH//4Wo9z3nnn5ZGPfGT23nvvHHDAAbn++utz00035aUvfWn22muvPPShD83nPve5JMnxxx+fV7/61be99pBDDsnnP//5JF2P+hvf+MbsvffeecQjHpErr7wy55xzTk499dQcddRR2WefffLd7373dn9uw0IAABjcySefnAsuuCAXXnhhrrnmmuy///559KMfnbPPPjvLli3L17/+9Vx11VXZY4898rKXvWzWY9x888057LDDctJJJ2X//ffPddddl2233Tbvfve7U1W5+OKL881vfjNPetKTcumll66znhtvvDGPeMQj8ra3vS1/+Id/mPe///055phj8rSnPS2HHHJInv3sZw/yufVcAwAwuLPOOivPe97zsuWWW2annXbKYx7zmJx33nk566yz8pznPCdbbLFF7nGPe+Rxj3vcWo/xrW99K/e85z2z//77J0l22GGHLFq0KGeddVZe+MIXJkl233333Pe+911vuN56661zyCGHJEke9rCHZdmyZcN80DUI1wAAbBYWLVqUlStX3rY8Okf1VlttddvUeltuuWVuueWWOalBuAYAYHAHHXRQTjrppNx66625+uqrc+aZZ+aAAw7IgQcemH/5l3/JypUrc+WVV942Jno2D3rQg3LFFVfkvPPOS5Jcf/31ueWWW3LQQQflhBNOSJJceuml+cEPfpAHPehBWbp0aS644IKsXLkyP/zhD/PlL395vXVuv/32uf766wf5zIkx1wAAm61xps6bK8985jNz7rnnZu+9905V5R3veEfucY975FnPelY++9nPZs8998x97nOf7LvvvlmyZMmsx9h6661z0kkn5TWveU1+/vOfZ9ttt80ZZ5yRI488MkcccUT22muvLFq0KMcff3y22WabHHjggdl1112z5557Zo899si+++673jqf+9zn5hWveEXe85735OMf/3juf//7367PXa2123WATcV+++3Xzj///EmXAQAwMd/4xjeyxx57TLqM9brhhhuy3XbbZfny5TnggANy9tln5x73uMeky5rVbG1aVV9pre032/56rgEAmFeHHHJIrr322tx8881505vetMkG640hXI8Y+i5GG2OSf74BAJgPs42zfuYzn5nLLrtstXVvf/vbc/DBB89TVcMQrgEAmLhPfOITky5hEGYLAQDYjGwu19NtCjamLYVrAIDNxOLFi7N8+XIBewCttSxfvjyLFy/eoNcZFgIAsJnYeeedc/nll+fqq6+edCmbhcWLF2fnnXfeoNcI1wAAm4mtttoqu+6666TLWNAMCwEAgIEI1wAAMBDhGgAABiJcAwDAQIRrAAAYiHANAAADEa4BAGAgwjUAAAxEuAYAgIEI1wAAMBDhGgAABiJcAwDAQIRrAAAYiHANAAADEa4BAGAgwjUAAAxEuAYAgIEI1wAAMBDhGgAABiJcAwDAQIRrAAAYiHANAAADEa4BAGAgwjUAAAxEuAYAgIEI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\n",
            "text/plain": [
              "<Figure size 864x576 with 1 Axes>"
            ]
          },
          "metadata": {
            "tags": [],
            "needs_background": "light"
          }
        }
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "J5oRl9LZ2KiW"
      },
      "source": [
        "We have already observed from the before bar plot that ratings 3 and 4 are given in more numbers by the users. Even the above graph suggests the same.\n",
        "\n",
        " Take away from this plot is by the number of missing ratings, we can estimate the level of sparsity in the matrix we are going to form. "
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "ezYrpsCM2LC7"
      },
      "source": [
        "**Plot rating frequency of all movies**"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "YqfWKYCEz782",
        "outputId": "93b3ac8c-a39f-44e5-9c2f-39ce2d9b6b55",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 195
        }
      },
      "source": [
        "refined_dataset.head()"
      ],
      "execution_count": 134,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/html": [
              "<div>\n",
              "<style scoped>\n",
              "    .dataframe tbody tr th:only-of-type {\n",
              "        vertical-align: middle;\n",
              "    }\n",
              "\n",
              "    .dataframe tbody tr th {\n",
              "        vertical-align: top;\n",
              "    }\n",
              "\n",
              "    .dataframe thead th {\n",
              "        text-align: right;\n",
              "    }\n",
              "</style>\n",
              "<table border=\"1\" class=\"dataframe\">\n",
              "  <thead>\n",
              "    <tr style=\"text-align: right;\">\n",
              "      <th></th>\n",
              "      <th>user id</th>\n",
              "      <th>movie title</th>\n",
              "      <th>rating</th>\n",
              "    </tr>\n",
              "  </thead>\n",
              "  <tbody>\n",
              "    <tr>\n",
              "      <th>0</th>\n",
              "      <td>1</td>\n",
              "      <td>101 Dalmatians (1996)</td>\n",
              "      <td>2.0</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>1</th>\n",
              "      <td>1</td>\n",
              "      <td>12 Angry Men (1957)</td>\n",
              "      <td>5.0</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>2</th>\n",
              "      <td>1</td>\n",
              "      <td>20,000 Leagues Under the Sea (1954)</td>\n",
              "      <td>3.0</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>3</th>\n",
              "      <td>1</td>\n",
              "      <td>2001: A Space Odyssey (1968)</td>\n",
              "      <td>4.0</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>4</th>\n",
              "      <td>1</td>\n",
              "      <td>Abyss, The (1989)</td>\n",
              "      <td>3.0</td>\n",
              "    </tr>\n",
              "  </tbody>\n",
              "</table>\n",
              "</div>"
            ],
            "text/plain": [
              "   user id                          movie title  rating\n",
              "0        1                101 Dalmatians (1996)     2.0\n",
              "1        1                  12 Angry Men (1957)     5.0\n",
              "2        1  20,000 Leagues Under the Sea (1954)     3.0\n",
              "3        1         2001: A Space Odyssey (1968)     4.0\n",
              "4        1                    Abyss, The (1989)     3.0"
            ]
          },
          "metadata": {
            "tags": []
          },
          "execution_count": 134
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "oTe-A4D156Ry",
        "outputId": "f64f656a-b218-4ab1-95a3-e01641fbe434",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 225
        }
      },
      "source": [
        "# get rating frequency\n",
        "movies_count_df = pd.DataFrame(refined_dataset.groupby('movie title').size(), columns=['count'])\n",
        "movies_count_df.head()"
      ],
      "execution_count": 135,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/html": [
              "<div>\n",
              "<style scoped>\n",
              "    .dataframe tbody tr th:only-of-type {\n",
              "        vertical-align: middle;\n",
              "    }\n",
              "\n",
              "    .dataframe tbody tr th {\n",
              "        vertical-align: top;\n",
              "    }\n",
              "\n",
              "    .dataframe thead th {\n",
              "        text-align: right;\n",
              "    }\n",
              "</style>\n",
              "<table border=\"1\" class=\"dataframe\">\n",
              "  <thead>\n",
              "    <tr style=\"text-align: right;\">\n",
              "      <th></th>\n",
              "      <th>count</th>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>movie title</th>\n",
              "      <th></th>\n",
              "    </tr>\n",
              "  </thead>\n",
              "  <tbody>\n",
              "    <tr>\n",
              "      <th>'Til There Was You (1997)</th>\n",
              "      <td>9</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>1-900 (1994)</th>\n",
              "      <td>5</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>101 Dalmatians (1996)</th>\n",
              "      <td>109</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>12 Angry Men (1957)</th>\n",
              "      <td>125</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>187 (1997)</th>\n",
              "      <td>41</td>\n",
              "    </tr>\n",
              "  </tbody>\n",
              "</table>\n",
              "</div>"
            ],
            "text/plain": [
              "                           count\n",
              "movie title                     \n",
              "'Til There Was You (1997)      9\n",
              "1-900 (1994)                   5\n",
              "101 Dalmatians (1996)        109\n",
              "12 Angry Men (1957)          125\n",
              "187 (1997)                    41"
            ]
          },
          "metadata": {
            "tags": []
          },
          "execution_count": 135
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "2PZxHmrq6MTz",
        "outputId": "e2b555d2-c2f9-44db-de48-8e57efe3e4c5",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 533
        }
      },
      "source": [
        "# plot rating frequency of all movies\n",
        "ax = movies_count_df \\\n",
        "    .sort_values('count', ascending=False) \\\n",
        "    .reset_index(drop=True) \\\n",
        "    .plot(\n",
        "        figsize=(12, 8),\n",
        "        title='Rating Frequency of All Movies',\n",
        "        fontsize=12\n",
        "    )\n",
        "ax.set_xlabel(\"movie Id\")\n",
        "ax.set_ylabel(\"number of ratings\")"
      ],
      "execution_count": 136,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "Text(0, 0.5, 'number of ratings')"
            ]
          },
          "metadata": {
            "tags": []
          },
          "execution_count": 136
        },
        {
          "output_type": "display_data",
          "data": {
            "image/png": "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\n",
            "text/plain": [
              "<Figure size 864x576 with 1 Axes>"
            ]
          },
          "metadata": {
            "tags": [],
            "needs_background": "light"
          }
        }
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "PyCcV_0j6yUw"
      },
      "source": [
        "**As the size of MovieLens dataset picked for this project is small. There is no need of removing rarely rated movies or users who has given rating for fewer movies.**\n",
        "\n",
        "**Also because the dataset considered is small, we do not see the long-tail property which will be the scenario with the distribution of ratings.**\n",
        "\n",
        "*If the dataset is larger, then* (this can be referred when we do similar kind of tasks with a larger dataset, just for future reference)\n",
        "\n",
        "The distribution of ratings among movies often satisfies a property in real-world settings, which is referred to as the long-tail property. According to this property, only a small fraction of the items are rated frequently. Such items are referred to as popular items. The vast majority of items are rated rarely. This results in a highly skewed distribution of the underlying ratings."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "PZD27ZLM8IN7"
      },
      "source": [
        "# Training KNN model to build item-based collaborative Recommender System."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "5omV7GyNTITK"
      },
      "source": [
        "**Reshaping the dataframe**\n",
        "\n",
        "We need to transform (reshape in this case) the data in such a way that each row of the dataframe represents a movie and each column represents a different user. So we want the data to be [movies, users] array if movie is the subject where similar movies must be found and [users, movies] array for reverse.\n",
        "\n",
        "To reshape the dataframe, we will pivot the dataframe to the wide format with movies as rows and users as columns. As we know that not all users watch all the movies, we can expect a lot of missing values. We will have to fill those missing observations with 0s since we are going to perform linear algebra operations (calculating distances between vectors). \n",
        "\n",
        "Finally, we transform the values of the dataframe into a scipy sparse matrix for most efficient calculations.\n",
        "\n",
        "This dataframe is then fed into a KNN model."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "IyvX84Lm6ToE"
      },
      "source": [
        "## Movie Recommendation using KNN with Input as **User id**, Number of similar users should the model pick and Number of movies you want to get recommended:"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "3qJCE3l3f2mY"
      },
      "source": [
        "1. Reshaping model in such a way that each user has n-dimensional rating space where n is total number of movies\n",
        "\n",
        " We will train the KNN model inorder to find the closely matching similar users to the user we give as input and we recommend the top movies which would interest the input user."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "pVjDfpRvWVhw",
        "outputId": "d4e854fb-2020-4c7e-88c4-57b2e5d638cb",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 391
        }
      },
      "source": [
        "# pivot and create movie-user matrix\n",
        "user_to_movie_df = refined_dataset.pivot(\n",
        "    index='user id',\n",
        "     columns='movie title',\n",
        "      values='rating').fillna(0)\n",
        "\n",
        "user_to_movie_df.head()"
      ],
      "execution_count": 138,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/html": [
              "<div>\n",
              "<style scoped>\n",
              "    .dataframe tbody tr th:only-of-type {\n",
              "        vertical-align: middle;\n",
              "    }\n",
              "\n",
              "    .dataframe tbody tr th {\n",
              "        vertical-align: top;\n",
              "    }\n",
              "\n",
              "    .dataframe thead th {\n",
              "        text-align: right;\n",
              "    }\n",
              "</style>\n",
              "<table border=\"1\" class=\"dataframe\">\n",
              "  <thead>\n",
              "    <tr style=\"text-align: right;\">\n",
              "      <th>movie title</th>\n",
              "      <th>'Til There Was You (1997)</th>\n",
              "      <th>1-900 (1994)</th>\n",
              "      <th>101 Dalmatians (1996)</th>\n",
              "      <th>12 Angry Men (1957)</th>\n",
              "      <th>187 (1997)</th>\n",
              "      <th>2 Days in the Valley (1996)</th>\n",
              "      <th>20,000 Leagues Under the Sea (1954)</th>\n",
              "      <th>2001: A Space Odyssey (1968)</th>\n",
              "      <th>3 Ninjas: High Noon At Mega Mountain (1998)</th>\n",
              "      <th>39 Steps, The (1935)</th>\n",
              "      <th>8 1/2 (1963)</th>\n",
              "      <th>8 Heads in a Duffel Bag (1997)</th>\n",
              "      <th>8 Seconds (1994)</th>\n",
              "      <th>A Chef in Love (1996)</th>\n",
              "      <th>Above the Rim (1994)</th>\n",
              "      <th>Absolute Power (1997)</th>\n",
              "      <th>Abyss, The (1989)</th>\n",
              "      <th>Ace Ventura: Pet Detective (1994)</th>\n",
              "      <th>Ace Ventura: When Nature Calls (1995)</th>\n",
              "      <th>Across the Sea of Time (1995)</th>\n",
              "      <th>Addams Family Values (1993)</th>\n",
              "      <th>Addicted to Love (1997)</th>\n",
              "      <th>Addiction, The (1995)</th>\n",
              "      <th>Adventures of Pinocchio, The (1996)</th>\n",
              "      <th>Adventures of Priscilla, Queen of the Desert, The (1994)</th>\n",
              "      <th>Adventures of Robin Hood, The (1938)</th>\n",
              "      <th>Affair to Remember, An (1957)</th>\n",
              "      <th>African Queen, The (1951)</th>\n",
              "      <th>Afterglow (1997)</th>\n",
              "      <th>Age of Innocence, The (1993)</th>\n",
              "      <th>Aiqing wansui (1994)</th>\n",
              "      <th>Air Bud (1997)</th>\n",
              "      <th>Air Force One (1997)</th>\n",
              "      <th>Air Up There, The (1994)</th>\n",
              "      <th>Airheads (1994)</th>\n",
              "      <th>Akira (1988)</th>\n",
              "      <th>Aladdin (1992)</th>\n",
              "      <th>Aladdin and the King of Thieves (1996)</th>\n",
              "      <th>Alaska (1996)</th>\n",
              "      <th>Albino Alligator (1996)</th>\n",
              "      <th>...</th>\n",
              "      <th>Whole Wide World, The (1996)</th>\n",
              "      <th>Widows' Peak (1994)</th>\n",
              "      <th>Wife, The (1995)</th>\n",
              "      <th>Wild America (1997)</th>\n",
              "      <th>Wild Bill (1995)</th>\n",
              "      <th>Wild Bunch, The (1969)</th>\n",
              "      <th>Wild Reeds (1994)</th>\n",
              "      <th>Wild Things (1998)</th>\n",
              "      <th>William Shakespeare's Romeo and Juliet (1996)</th>\n",
              "      <th>Willy Wonka and the Chocolate Factory (1971)</th>\n",
              "      <th>Window to Paris (1994)</th>\n",
              "      <th>Wings of Courage (1995)</th>\n",
              "      <th>Wings of Desire (1987)</th>\n",
              "      <th>Wings of the Dove, The (1997)</th>\n",
              "      <th>Winnie the Pooh and the Blustery Day (1968)</th>\n",
              "      <th>Winter Guest, The (1997)</th>\n",
              "      <th>Wishmaster (1997)</th>\n",
              "      <th>With Honors (1994)</th>\n",
              "      <th>Withnail and I (1987)</th>\n",
              "      <th>Witness (1985)</th>\n",
              "      <th>Wizard of Oz, The (1939)</th>\n",
              "      <th>Wolf (1994)</th>\n",
              "      <th>Woman in Question, The (1950)</th>\n",
              "      <th>Women, The (1939)</th>\n",
              "      <th>Wonderful, Horrible Life of Leni Riefenstahl, The (1993)</th>\n",
              "      <th>Wonderland (1997)</th>\n",
              "      <th>Wooden Man's Bride, The (Wu Kui) (1994)</th>\n",
              "      <th>World of Apu, The (Apur Sansar) (1959)</th>\n",
              "      <th>Wrong Trousers, The (1993)</th>\n",
              "      <th>Wyatt Earp (1994)</th>\n",
              "      <th>Yankee Zulu (1994)</th>\n",
              "      <th>Year of the Horse (1997)</th>\n",
              "      <th>You So Crazy (1994)</th>\n",
              "      <th>Young Frankenstein (1974)</th>\n",
              "      <th>Young Guns (1988)</th>\n",
              "      <th>Young Guns II (1990)</th>\n",
              "      <th>Young Poisoner's Handbook, The (1995)</th>\n",
              "      <th>Zeus and Roxanne (1997)</th>\n",
              "      <th>unknown</th>\n",
              "      <th>Á köldum klaka (Cold Fever) (1994)</th>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>user id</th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "    </tr>\n",
              "  </thead>\n",
              "  <tbody>\n",
              "    <tr>\n",
              "      <th>1</th>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>2.0</td>\n",
              "      <td>5.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>3.0</td>\n",
              "      <td>4.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>3.0</td>\n",
              "      <td>3.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>1.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>4.0</td>\n",
              "      <td>4.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>...</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>4.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>4.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>5.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>5.0</td>\n",
              "      <td>3.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>4.0</td>\n",
              "      <td>0.0</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>2</th>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>1.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>3.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>4.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>...</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>5.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>3</th>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>2.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>2.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>...</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>4</th>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>5.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>...</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>5.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>5</th>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>2.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>4.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>1.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>2.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>5.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>3.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>4.0</td>\n",
              "      <td>4.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>...</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>1.0</td>\n",
              "      <td>3.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>5.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>4.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>4.0</td>\n",
              "      <td>0.0</td>\n",
              "    </tr>\n",
              "  </tbody>\n",
              "</table>\n",
              "<p>5 rows × 1664 columns</p>\n",
              "</div>"
            ],
            "text/plain": [
              "movie title  'Til There Was You (1997)  ...  Á köldum klaka (Cold Fever) (1994)\n",
              "user id                                 ...                                    \n",
              "1                                  0.0  ...                                 0.0\n",
              "2                                  0.0  ...                                 0.0\n",
              "3                                  0.0  ...                                 0.0\n",
              "4                                  0.0  ...                                 0.0\n",
              "5                                  0.0  ...                                 0.0\n",
              "\n",
              "[5 rows x 1664 columns]"
            ]
          },
          "metadata": {
            "tags": []
          },
          "execution_count": 138
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "NzGiLk_P6ZPU",
        "outputId": "ce7e1849-a29d-456b-9eb7-a17190231787",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 50
        }
      },
      "source": [
        "# transform matrix to scipy sparse matrix\n",
        "user_to_movie_sparse_df = csr_matrix(user_to_movie_df.values)\n",
        "user_to_movie_sparse_df"
      ],
      "execution_count": 139,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "<943x1664 sparse matrix of type '<class 'numpy.float64'>'\n",
              "\twith 99693 stored elements in Compressed Sparse Row format>"
            ]
          },
          "metadata": {
            "tags": []
          },
          "execution_count": 139
        }
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "_lmFFozScX9B"
      },
      "source": [
        "**Fitting K-Nearest Neighbours model to the scipy sparse matrix:**"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "T-C_KVvkglZZ",
        "outputId": "fa672186-a2c4-478a-9e26-5a8d9eaa8334",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 67
        }
      },
      "source": [
        "knn_model = NearestNeighbors(metric='cosine', algorithm='brute')\n",
        "knn_model.fit(user_to_movie_sparse_df)"
      ],
      "execution_count": 140,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "NearestNeighbors(algorithm='brute', leaf_size=30, metric='cosine',\n",
              "                 metric_params=None, n_jobs=None, n_neighbors=5, p=2,\n",
              "                 radius=1.0)"
            ]
          },
          "metadata": {
            "tags": []
          },
          "execution_count": 140
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "GznTZhlIcPCI"
      },
      "source": [
        "## function to find top n similar users of the given input user \n",
        "def get_similar_users(user, n = 5):\n",
        "  ## input to this function is the user and number of top similar users you want.\n",
        "\n",
        "  knn_input = np.asarray([user_to_movie_df.values[user-1]])  #.reshape(1,-1)\n",
        "  # knn_input = user_to_movie_df.iloc[0,:].values.reshape(1,-1)\n",
        "  distances, indices = knn_model.kneighbors(knn_input, n_neighbors=n+1)\n",
        "  \n",
        "  print(\"Top\",n,\"users who are very much similar to the User-\",user, \"are: \")\n",
        "  print(\" \")\n",
        "  for i in range(1,len(distances[0])):\n",
        "    print(i,\". User:\", indices[0][i]+1, \"separated by distance of\",distances[0][i])\n",
        "  return indices.flatten()[1:] + 1, distances.flatten()[1:]\n"
      ],
      "execution_count": 141,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "UzD2cOe361JX"
      },
      "source": [
        "**Specify User id and Number of similar users we want to consider here**"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "ZAc5xnl2mZp3",
        "outputId": "9f9a1dd7-2877-4cdc-fd5f-e6282ac42a3e",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 319
        }
      },
      "source": [
        "from pprint import pprint\n",
        "user_id = 778\n",
        "print(\" Few of movies seen by the User:\")\n",
        "pprint(list(refined_dataset[refined_dataset['user id'] == user_id]['movie title'])[:10])\n",
        "similar_user_list, distance_list = get_similar_users(user_id,5)"
      ],
      "execution_count": 142,
      "outputs": [
        {
          "output_type": "stream",
          "text": [
            " Few of movies seen by the User:\n",
            "['Amityville Horror, The (1979)',\n",
            " 'Angels in the Outfield (1994)',\n",
            " 'Apocalypse Now (1979)',\n",
            " 'Apollo 13 (1995)',\n",
            " 'Austin Powers: International Man of Mystery (1997)',\n",
            " 'Babe (1995)',\n",
            " 'Back to the Future (1985)',\n",
            " 'Blues Brothers, The (1980)',\n",
            " 'Chasing Amy (1997)',\n",
            " 'Clerks (1994)']\n",
            "Top 5 users who are very much similar to the User- 778 are: \n",
            " \n",
            "1 . User: 124 separated by distance of 0.4586649429539592\n",
            "2 . User: 933 separated by distance of 0.5581959868865324\n",
            "3 . User: 56 separated by distance of 0.5858413112292744\n",
            "4 . User: 738 separated by distance of 0.5916272517988691\n",
            "5 . User: 653 separated by distance of 0.5991479757406326\n"
          ],
          "name": "stdout"
        }
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "LDtU_DkCqLl6"
      },
      "source": [
        "**With the help of the KNN model built, we could get desired number of top similar users.**\n",
        "\n",
        "**Now we will have to pick the top movies to recommend.**\n",
        "\n",
        "**One way would be by taking the average of the existing ratings given by the similar users and picking the top 10 or 15 movies to recommend to our current user.**\n",
        "\n",
        "**But I feel recommendation would be more effective if we define weights to ratings by each similar user based on the thier distance from the input user. Defining these weights would give us the accurate recommendations by eliminating the chance of decision manipulation by the users who are relatively very far from the input user.**"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "3JNvsjkzhXj4",
        "outputId": "d8f1e6b9-9d26-4415-8ad9-f5b4b5049aec",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 50
        }
      },
      "source": [
        "similar_user_list, distance_list"
      ],
      "execution_count": 143,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "(array([124, 933,  56, 738, 653]),\n",
              " array([0.45866494, 0.55819599, 0.58584131, 0.59162725, 0.59914798]))"
            ]
          },
          "metadata": {
            "tags": []
          },
          "execution_count": 143
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "7de9PUuitY5p",
        "outputId": "360455f1-412d-4b07-ed51-c704da2d788c",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 34
        }
      },
      "source": [
        "weightage_list = distance_list/np.sum(distance_list)\n",
        "weightage_list"
      ],
      "execution_count": 144,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "array([0.16419139, 0.19982119, 0.20971757, 0.2117888 , 0.21448105])"
            ]
          },
          "metadata": {
            "tags": []
          },
          "execution_count": 144
        }
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "lCX18TkDtnz8"
      },
      "source": [
        "Getting ratings of all movies by derived similar users"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "VEh6O0oAtv_F",
        "outputId": "140cf5f4-a9fb-47a7-8365-6fab2d732462",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 101
        }
      },
      "source": [
        "mov_rtngs_sim_users = user_to_movie_df.values[similar_user_list]\n",
        "mov_rtngs_sim_users"
      ],
      "execution_count": 145,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "array([[0., 0., 0., ..., 0., 0., 0.],\n",
              "       [0., 0., 2., ..., 0., 0., 0.],\n",
              "       [0., 0., 3., ..., 0., 0., 0.],\n",
              "       [0., 0., 0., ..., 0., 0., 0.],\n",
              "       [0., 0., 0., ..., 0., 0., 0.]])"
            ]
          },
          "metadata": {
            "tags": []
          },
          "execution_count": 145
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "nhty6LqMur17",
        "outputId": "d49cf83a-3e2c-4092-c477-77f81b285735",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 202
        }
      },
      "source": [
        "movies_list = user_to_movie_df.columns\n",
        "movies_list"
      ],
      "execution_count": 146,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "Index([''Til There Was You (1997)', '1-900 (1994)', '101 Dalmatians (1996)',\n",
              "       '12 Angry Men (1957)', '187 (1997)', '2 Days in the Valley (1996)',\n",
              "       '20,000 Leagues Under the Sea (1954)', '2001: A Space Odyssey (1968)',\n",
              "       '3 Ninjas: High Noon At Mega Mountain (1998)', '39 Steps, The (1935)',\n",
              "       ...\n",
              "       'Yankee Zulu (1994)', 'Year of the Horse (1997)', 'You So Crazy (1994)',\n",
              "       'Young Frankenstein (1974)', 'Young Guns (1988)',\n",
              "       'Young Guns II (1990)', 'Young Poisoner's Handbook, The (1995)',\n",
              "       'Zeus and Roxanne (1997)', 'unknown',\n",
              "       'Á köldum klaka (Cold Fever) (1994)'],\n",
              "      dtype='object', name='movie title', length=1664)"
            ]
          },
          "metadata": {
            "tags": []
          },
          "execution_count": 146
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "c_nwkKwhvQ7Y",
        "outputId": "bed4129d-df39-4742-8906-b24469f36cbf",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 67
        }
      },
      "source": [
        "print(\"Weightage list shape:\", len(weightage_list))\n",
        "print(\"mov_rtngs_sim_users shape:\", mov_rtngs_sim_users.shape)\n",
        "print(\"Number of movies:\", len(movies_list))"
      ],
      "execution_count": 147,
      "outputs": [
        {
          "output_type": "stream",
          "text": [
            "Weightage list shape: 5\n",
            "mov_rtngs_sim_users shape: (5, 1664)\n",
            "Number of movies: 1664\n"
          ],
          "name": "stdout"
        }
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "oMgSULlTx71x"
      },
      "source": [
        "**Broadcasting weightage matrix to similar user rating matrix. so that it gets compatible for matrix operations**"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "0WF66O37x7WH",
        "outputId": "8f6b8c87-d797-4485-8468-48b6802439d1",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 34
        }
      },
      "source": [
        "weightage_list = weightage_list[:,np.newaxis] + np.zeros(len(movies_list))\n",
        "weightage_list.shape"
      ],
      "execution_count": 148,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "(5, 1664)"
            ]
          },
          "metadata": {
            "tags": []
          },
          "execution_count": 148
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "RI6iizTIx7SO",
        "outputId": "e31a105c-d826-4928-ec93-15cf58e2cd42",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 50
        }
      },
      "source": [
        "new_rating_matrix = weightage_list*mov_rtngs_sim_users\n",
        "mean_rating_list = new_rating_matrix.sum(axis =0)\n",
        "mean_rating_list"
      ],
      "execution_count": 149,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "array([0.        , 0.        , 1.02879509, ..., 0.        , 0.        ,\n",
              "       0.        ])"
            ]
          },
          "metadata": {
            "tags": []
          },
          "execution_count": 149
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "jasA8xEWu3Sj"
      },
      "source": [
        "from pprint import pprint\n",
        "def recommend_movies(n):\n",
        "  n = min(len(mean_rating_list),n)\n",
        "  # print(np.argsort(mean_rating_list)[::-1][:n])\n",
        "  pprint(list(movies_list[np.argsort(mean_rating_list)[::-1][:n]]))\n",
        "\n"
      ],
      "execution_count": 150,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "4ix_nK1I33WS",
        "outputId": "64cfee5b-3f39-4616-81f3-d7a044706504",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 202
        }
      },
      "source": [
        "print(\"Movies recommended based on similar users are: \")\n",
        "recommend_movies(10)"
      ],
      "execution_count": 151,
      "outputs": [
        {
          "output_type": "stream",
          "text": [
            "Movies recommended based on similar users are: \n",
            "['Star Wars (1977)',\n",
            " 'Terminator, The (1984)',\n",
            " \"Schindler's List (1993)\",\n",
            " 'Fugitive, The (1993)',\n",
            " 'Forrest Gump (1994)',\n",
            " 'Princess Bride, The (1987)',\n",
            " 'Empire Strikes Back, The (1980)',\n",
            " 'Pulp Fiction (1994)',\n",
            " 'Die Hard (1988)',\n",
            " 'Monty Python and the Holy Grail (1974)']\n"
          ],
          "name": "stdout"
        }
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "MZh3ID7NgwD7"
      },
      "source": [
        "It had been observed that, this recommendation system built can be made more efficient as it has few drawbacks.\n",
        "\n",
        "**Drawbacks:**\n",
        "\n",
        "**1.** But this recommendation system has a drawback, it also **recommends movies which are already seen by the given input User.**\n",
        "\n",
        "**2.** And also there is a possibility of recommending the **movies which are not at all seen by any of the similar users.**"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "cMOC4pKzkKiQ"
      },
      "source": [
        "**Above drawbacks are addressed and a new recommender system with modification is built**\n",
        "\n",
        "Below function is defined to remove the movies which are already seen the current user and not at all seen by any of the similar users."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "cC5fgG3-iXei"
      },
      "source": [
        "\n",
        "def filtered_movie_recommendations(n):\n",
        "  \n",
        "  first_zero_index = np.where(mean_rating_list == 0)[0][-1]\n",
        "  sortd_index = np.argsort(mean_rating_list)[::-1]\n",
        "  sortd_index = sortd_index[:list(sortd_index).index(first_zero_index)]\n",
        "  n = min(len(sortd_index),n)\n",
        "  movies_watched = list(refined_dataset[refined_dataset['user id'] == user_id]['movie title'])\n",
        "  filtered_movie_list = list(movies_list[sortd_index])\n",
        "  count = 0\n",
        "  final_movie_list = []\n",
        "  for i in filtered_movie_list:\n",
        "    if i not in movies_watched:\n",
        "      count+=1\n",
        "      final_movie_list.append(i)\n",
        "    if count == n:\n",
        "      break\n",
        "  if count == 0:\n",
        "    print(\"There are no movies left which are not seen by the input users and seen by similar users. May be increasing the number of similar users who are to be considered may give a chance of suggesting an unseen good movie.\")\n",
        "  else:\n",
        "    pprint(final_movie_list)\n"
      ],
      "execution_count": 152,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "hhk_3V2QyeNz",
        "outputId": "d47981dd-3691-4255-a783-7b8fb2ce5d03",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 185
        }
      },
      "source": [
        "filtered_movie_recommendations(10)"
      ],
      "execution_count": 153,
      "outputs": [
        {
          "output_type": "stream",
          "text": [
            "['Star Wars (1977)',\n",
            " \"Schindler's List (1993)\",\n",
            " 'Princess Bride, The (1987)',\n",
            " 'Empire Strikes Back, The (1980)',\n",
            " 'Return of the Jedi (1983)',\n",
            " 'Fargo (1996)',\n",
            " 'Dances with Wolves (1990)',\n",
            " 'Toy Story (1995)',\n",
            " 'Braveheart (1995)',\n",
            " 'Star Trek: First Contact (1996)']\n"
          ],
          "name": "stdout"
        }
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "MI7T25n6ZOEf"
      },
      "source": [
        "Coding up all of the above individual cells into a function.\n",
        "\n",
        "Giving Input as **User id, Number of similar Users to be considered, Number of top movie we want to recommend**"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "GQ4UfrTM33hF"
      },
      "source": [
        "from pprint import pprint\n",
        "\n",
        "def recommender_system(user_id, n_similar_users, n_movies): #, user_to_movie_df, knn_model):\n",
        "  \n",
        "  print(\"Movie seen by the User:\")\n",
        "  pprint(list(refined_dataset[refined_dataset['user id'] == user_id]['movie title']))\n",
        "  print(\"\")\n",
        "\n",
        "  # def get_similar_users(user, user_to_movie_df, knn_model, n = 5):\n",
        "  def get_similar_users(user, n = 5):\n",
        "    \n",
        "    knn_input = np.asarray([user_to_movie_df.values[user-1]])\n",
        "    \n",
        "    distances, indices = knn_model.kneighbors(knn_input, n_neighbors=n+1)\n",
        "    \n",
        "    print(\"Top\",n,\"users who are very much similar to the User-\",user, \"are: \")\n",
        "    print(\" \")\n",
        "\n",
        "    for i in range(1,len(distances[0])):\n",
        "      print(i,\". User:\", indices[0][i]+1, \"separated by distance of\",distances[0][i])\n",
        "    print(\"\")\n",
        "    return indices.flatten()[1:] + 1, distances.flatten()[1:]\n",
        "\n",
        "\n",
        "  def filtered_movie_recommendations(n = 10):\n",
        "  \n",
        "    first_zero_index = np.where(mean_rating_list == 0)[0][-1]\n",
        "    sortd_index = np.argsort(mean_rating_list)[::-1]\n",
        "    sortd_index = sortd_index[:list(sortd_index).index(first_zero_index)]\n",
        "    n = min(len(sortd_index),n)\n",
        "    movies_watched = list(refined_dataset[refined_dataset['user id'] == user_id]['movie title'])\n",
        "    filtered_movie_list = list(movies_list[sortd_index])\n",
        "    count = 0\n",
        "    final_movie_list = []\n",
        "    for i in filtered_movie_list:\n",
        "      if i not in movies_watched:\n",
        "        count+=1\n",
        "        final_movie_list.append(i)\n",
        "      if count == n:\n",
        "        break\n",
        "    if count == 0:\n",
        "      print(\"There are no movies left which are not seen by the input users and seen by similar users. May be increasing the number of similar users who are to be considered may give a chance of suggesting an unseen good movie.\")\n",
        "    else:\n",
        "      pprint(final_movie_list)\n",
        "\n",
        "  similar_user_list, distance_list = get_similar_users(user_id,n_similar_users)\n",
        "  weightage_list = distance_list/np.sum(distance_list)\n",
        "  mov_rtngs_sim_users = user_to_movie_df.values[similar_user_list]\n",
        "  movies_list = user_to_movie_df.columns\n",
        "  weightage_list = weightage_list[:,np.newaxis] + np.zeros(len(movies_list))\n",
        "  new_rating_matrix = weightage_list*mov_rtngs_sim_users\n",
        "  mean_rating_list = new_rating_matrix.sum(axis =0)\n",
        "  print(\"\")\n",
        "  print(\"Movies recommended based on similar users are: \")\n",
        "  print(\"\")\n",
        "  filtered_movie_recommendations(n_movies)"
      ],
      "execution_count": 233,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "ZhQI_qBL33dj",
        "outputId": "fae03002-e4c8-46d9-b4ef-e5f0bcdb1781",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 1000
        }
      },
      "source": [
        "print(\"Enter user id\")\n",
        "user_id= int(input())\n",
        "print(\"number of similar users to be considered\")\n",
        "sim_users = int(input())\n",
        "print(\"Enter number of movies to be recommended:\")\n",
        "n_movies = int(input())\n",
        "recommender_system(user_id,sim_users,n_movies)\n",
        "# recommender_system(300, 15,15)"
      ],
      "execution_count": 234,
      "outputs": [
        {
          "output_type": "stream",
          "text": [
            "Enter user id\n",
            "307\n",
            "number of similar users to be considered\n",
            "15\n",
            "Enter number of movies to be recommended:\n",
            "15\n",
            "Movie seen by the User:\n",
            "['12 Angry Men (1957)',\n",
            " '2001: A Space Odyssey (1968)',\n",
            " 'Abyss, The (1989)',\n",
            " 'Alien (1979)',\n",
            " 'Apollo 13 (1995)',\n",
            " 'Back to the Future (1985)',\n",
            " 'Barbarella (1968)',\n",
            " 'Batman (1989)',\n",
            " 'Beauty and the Beast (1991)',\n",
            " 'Blade Runner (1982)',\n",
            " 'Blues Brothers, The (1980)',\n",
            " 'Boot, Das (1981)',\n",
            " 'Brady Bunch Movie, The (1995)',\n",
            " 'Braveheart (1995)',\n",
            " 'Brazil (1985)',\n",
            " 'Casablanca (1942)',\n",
            " 'Close Shave, A (1995)',\n",
            " 'Contact (1997)',\n",
            " 'Crying Game, The (1992)',\n",
            " 'Dead Poets Society (1989)',\n",
            " 'Dial M for Murder (1954)',\n",
            " 'Dr. Strangelove or: How I Learned to Stop Worrying and Love the Bomb (1963)',\n",
            " 'Dragonheart (1996)',\n",
            " 'E.T. the Extra-Terrestrial (1982)',\n",
            " 'Empire Strikes Back, The (1980)',\n",
            " 'English Patient, The (1996)',\n",
            " 'Englishman Who Went Up a Hill, But Came Down a Mountain, The (1995)',\n",
            " 'Escape from L.A. (1996)',\n",
            " 'Fargo (1996)',\n",
            " 'Fast, Cheap & Out of Control (1997)',\n",
            " 'Field of Dreams (1989)',\n",
            " 'Fish Called Wanda, A (1988)',\n",
            " 'Four Weddings and a Funeral (1994)',\n",
            " 'Fried Green Tomatoes (1991)',\n",
            " 'Full Monty, The (1997)',\n",
            " 'Gandhi (1982)',\n",
            " 'Ghost (1990)',\n",
            " 'Graduate, The (1967)',\n",
            " 'Grand Day Out, A (1992)',\n",
            " 'Grumpier Old Men (1995)',\n",
            " 'Harold and Maude (1971)',\n",
            " 'Heathers (1989)',\n",
            " 'Heavy Metal (1981)',\n",
            " 'Highlander (1986)',\n",
            " 'Home Alone (1990)',\n",
            " 'How to Make an American Quilt (1995)',\n",
            " 'Hudsucker Proxy, The (1994)',\n",
            " 'Hunt for Red October, The (1990)',\n",
            " 'Independence Day (ID4) (1996)',\n",
            " 'Indiana Jones and the Last Crusade (1989)',\n",
            " 'Jurassic Park (1993)',\n",
            " 'Koyaanisqatsi (1983)',\n",
            " 'Lawnmower Man, The (1992)',\n",
            " 'Lawrence of Arabia (1962)',\n",
            " 'Like Water For Chocolate (Como agua para chocolate) (1992)',\n",
            " 'Lion King, The (1994)',\n",
            " 'Mary Poppins (1964)',\n",
            " 'Mask, The (1994)',\n",
            " \"McHale's Navy (1997)\",\n",
            " 'Men in Black (1997)',\n",
            " \"Microcosmos: Le peuple de l'herbe (1996)\",\n",
            " 'Monty Python and the Holy Grail (1974)',\n",
            " \"Monty Python's Life of Brian (1979)\",\n",
            " 'Mrs. Doubtfire (1993)',\n",
            " 'Much Ado About Nothing (1993)',\n",
            " 'Muppet Treasure Island (1996)',\n",
            " 'My Left Foot (1989)',\n",
            " 'My Life as a Dog (Mitt liv som hund) (1985)',\n",
            " 'Mystery Science Theater 3000: The Movie (1996)',\n",
            " 'Nightmare Before Christmas, The (1993)',\n",
            " 'Pink Floyd - The Wall (1982)',\n",
            " 'Pretty Woman (1990)',\n",
            " 'Princess Bride, The (1987)',\n",
            " 'Psycho (1960)',\n",
            " 'Pulp Fiction (1994)',\n",
            " 'Raiders of the Lost Ark (1981)',\n",
            " 'Real Genius (1985)',\n",
            " 'Return of the Jedi (1983)',\n",
            " 'Return of the Pink Panther, The (1974)',\n",
            " 'Right Stuff, The (1983)',\n",
            " 'Road to Wellville, The (1994)',\n",
            " 'Robin Hood: Men in Tights (1993)',\n",
            " 'Rumble in the Bronx (1995)',\n",
            " 'Secret of Roan Inish, The (1994)',\n",
            " 'Sex, Lies, and Videotape (1989)',\n",
            " 'Shadowlands (1993)',\n",
            " 'Shawshank Redemption, The (1994)',\n",
            " 'Shining, The (1980)',\n",
            " 'Sneakers (1992)',\n",
            " 'Snow White and the Seven Dwarfs (1937)',\n",
            " 'Sound of Music, The (1965)',\n",
            " 'Stand by Me (1986)',\n",
            " 'Star Trek III: The Search for Spock (1984)',\n",
            " 'Star Trek IV: The Voyage Home (1986)',\n",
            " 'Star Trek V: The Final Frontier (1989)',\n",
            " 'Star Trek VI: The Undiscovered Country (1991)',\n",
            " 'Star Trek: First Contact (1996)',\n",
            " 'Star Trek: Generations (1994)',\n",
            " 'Star Trek: The Motion Picture (1979)',\n",
            " 'Star Trek: The Wrath of Khan (1982)',\n",
            " 'Star Wars (1977)',\n",
            " 'Stargate (1994)',\n",
            " 'Tank Girl (1995)',\n",
            " 'Terminator, The (1984)',\n",
            " 'This Is Spinal Tap (1984)',\n",
            " 'Titanic (1997)',\n",
            " 'To Kill a Mockingbird (1962)',\n",
            " 'Top Gun (1986)',\n",
            " 'Toy Story (1995)',\n",
            " 'Wallace & Gromit: The Best of Aardman Animation (1996)',\n",
            " 'Wizard of Oz, The (1939)',\n",
            " 'Wrong Trousers, The (1993)']\n",
            "\n",
            "Top 15 users who are very much similar to the User- 307 are: \n",
            " \n",
            "1 . User: 70 separated by distance of 0.4560883724650484\n",
            "2 . User: 738 separated by distance of 0.4846662001127756\n",
            "3 . User: 922 separated by distance of 0.503221313979523\n",
            "4 . User: 407 separated by distance of 0.5038250337403114\n",
            "5 . User: 514 separated by distance of 0.5060750098353226\n",
            "6 . User: 44 separated by distance of 0.5160506271876224\n",
            "7 . User: 660 separated by distance of 0.5165826487301209\n",
            "8 . User: 5 separated by distance of 0.5211146313938015\n",
            "9 . User: 457 separated by distance of 0.5309167131718452\n",
            "10 . User: 23 separated by distance of 0.5316197783536492\n",
            "11 . User: 843 separated by distance of 0.5324703658288387\n",
            "12 . User: 64 separated by distance of 0.53318921205275\n",
            "13 . User: 198 separated by distance of 0.535682894616484\n",
            "14 . User: 815 separated by distance of 0.5416036160331636\n",
            "15 . User: 95 separated by distance of 0.5468066886836396\n",
            "\n",
            "\n",
            "Movies recommended based on similar users are: \n",
            "\n",
            "[\"Schindler's List (1993)\",\n",
            " 'Liar Liar (1997)',\n",
            " 'When Harry Met Sally... (1989)',\n",
            " 'Leaving Las Vegas (1995)',\n",
            " 'Silence of the Lambs, The (1991)',\n",
            " 'Dead Man Walking (1995)',\n",
            " 'Trainspotting (1996)',\n",
            " 'Forrest Gump (1994)',\n",
            " 'Scream (1996)',\n",
            " 'Twelve Monkeys (1995)',\n",
            " 'Jerry Maguire (1996)',\n",
            " 'Raising Arizona (1987)',\n",
            " 'Godfather, The (1972)',\n",
            " 'Rock, The (1996)',\n",
            " 'Fugitive, The (1993)']\n"
          ],
          "name": "stdout"
        }
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "9i5m2wO4iQUW"
      },
      "source": [
        "## Movie Recommendation using KNN with Input as **Movie Name** and Number of movies you want to get recommended:"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "XaQLSI1ni_qS"
      },
      "source": [
        "2. Reshaping model in such a way that each movie has n-dimensional rating space where n is total number of users who could rate.\n",
        "\n",
        " We will train the KNN model inorder to find the closely matching similar movies to the movie we give as input and we recommend the top movies which would more closely align to the movie we have given."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "pKgkHLCN33ZT",
        "outputId": "9b3ac3a7-2436-47ef-f6a6-fb39fc62c515",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 391
        }
      },
      "source": [
        "# pivot and create movie-user matrix\n",
        "movie_to_user_df = refined_dataset.pivot(\n",
        "     index='movie title',\n",
        "   columns='user id',\n",
        "      values='rating').fillna(0)\n",
        "\n",
        "movie_to_user_df.head()"
      ],
      "execution_count": 157,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/html": [
              "<div>\n",
              "<style scoped>\n",
              "    .dataframe tbody tr th:only-of-type {\n",
              "        vertical-align: middle;\n",
              "    }\n",
              "\n",
              "    .dataframe tbody tr th {\n",
              "        vertical-align: top;\n",
              "    }\n",
              "\n",
              "    .dataframe thead th {\n",
              "        text-align: right;\n",
              "    }\n",
              "</style>\n",
              "<table border=\"1\" class=\"dataframe\">\n",
              "  <thead>\n",
              "    <tr style=\"text-align: right;\">\n",
              "      <th>user id</th>\n",
              "      <th>1</th>\n",
              "      <th>2</th>\n",
              "      <th>3</th>\n",
              "      <th>4</th>\n",
              "      <th>5</th>\n",
              "      <th>6</th>\n",
              "      <th>7</th>\n",
              "      <th>8</th>\n",
              "      <th>9</th>\n",
              "      <th>10</th>\n",
              "      <th>11</th>\n",
              "      <th>12</th>\n",
              "      <th>13</th>\n",
              "      <th>14</th>\n",
              "      <th>15</th>\n",
              "      <th>16</th>\n",
              "      <th>17</th>\n",
              "      <th>18</th>\n",
              "      <th>19</th>\n",
              "      <th>20</th>\n",
              "      <th>21</th>\n",
              "      <th>22</th>\n",
              "      <th>23</th>\n",
              "      <th>24</th>\n",
              "      <th>25</th>\n",
              "      <th>26</th>\n",
              "      <th>27</th>\n",
              "      <th>28</th>\n",
              "      <th>29</th>\n",
              "      <th>30</th>\n",
              "      <th>31</th>\n",
              "      <th>32</th>\n",
              "      <th>33</th>\n",
              "      <th>34</th>\n",
              "      <th>35</th>\n",
              "      <th>36</th>\n",
              "      <th>37</th>\n",
              "      <th>38</th>\n",
              "      <th>39</th>\n",
              "      <th>40</th>\n",
              "      <th>...</th>\n",
              "      <th>904</th>\n",
              "      <th>905</th>\n",
              "      <th>906</th>\n",
              "      <th>907</th>\n",
              "      <th>908</th>\n",
              "      <th>909</th>\n",
              "      <th>910</th>\n",
              "      <th>911</th>\n",
              "      <th>912</th>\n",
              "      <th>913</th>\n",
              "      <th>914</th>\n",
              "      <th>915</th>\n",
              "      <th>916</th>\n",
              "      <th>917</th>\n",
              "      <th>918</th>\n",
              "      <th>919</th>\n",
              "      <th>920</th>\n",
              "      <th>921</th>\n",
              "      <th>922</th>\n",
              "      <th>923</th>\n",
              "      <th>924</th>\n",
              "      <th>925</th>\n",
              "      <th>926</th>\n",
              "      <th>927</th>\n",
              "      <th>928</th>\n",
              "      <th>929</th>\n",
              "      <th>930</th>\n",
              "      <th>931</th>\n",
              "      <th>932</th>\n",
              "      <th>933</th>\n",
              "      <th>934</th>\n",
              "      <th>935</th>\n",
              "      <th>936</th>\n",
              "      <th>937</th>\n",
              "      <th>938</th>\n",
              "      <th>939</th>\n",
              "      <th>940</th>\n",
              "      <th>941</th>\n",
              "      <th>942</th>\n",
              "      <th>943</th>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>movie title</th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "      <th></th>\n",
              "    </tr>\n",
              "  </thead>\n",
              "  <tbody>\n",
              "    <tr>\n",
              "      <th>'Til There Was You (1997)</th>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>...</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "      <td>0.0</td>\n",
              "  
Download .txt
gitextract_6b3qicba/

├── Images/
│   └── .gitkeep
├── Item_based_Collaborative_Recommender_System_using_KNN.ipynb
├── Knowledge_based_Recommender_System.ipynb
├── README.md
├── Recommender_System_using_SVD.ipynb
└── Recommender_System_using_Softmax_DNN.ipynb
Condensed preview — 6 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (1,125K chars).
[
  {
    "path": "Images/.gitkeep",
    "chars": 1,
    "preview": "\n"
  },
  {
    "path": "Item_based_Collaborative_Recommender_System_using_KNN.ipynb",
    "chars": 239472,
    "preview": "{\n  \"nbformat\": 4,\n  \"nbformat_minor\": 0,\n  \"metadata\": {\n    \"colab\": {\n      \"name\": \"Item-based-Collaborative-Recomme"
  },
  {
    "path": "Knowledge_based_Recommender_System.ipynb",
    "chars": 602372,
    "preview": "{\n  \"nbformat\": 4,\n  \"nbformat_minor\": 0,\n  \"metadata\": {\n    \"colab\": {\n      \"name\": \"Knowledge-based-Recommender-Syst"
  },
  {
    "path": "README.md",
    "chars": 40639,
    "preview": "## [Unrelated post - Connect with me on LinkedIn] \n[09-01-2023] It's been almost three years since I completed this proj"
  },
  {
    "path": "Recommender_System_using_SVD.ipynb",
    "chars": 75205,
    "preview": "{\n  \"nbformat\": 4,\n  \"nbformat_minor\": 0,\n  \"metadata\": {\n    \"colab\": {\n      \"name\": \"Recommender-System-using-SVD.ipy"
  },
  {
    "path": "Recommender_System_using_Softmax_DNN.ipynb",
    "chars": 114018,
    "preview": "{\n  \"nbformat\": 4,\n  \"nbformat_minor\": 0,\n  \"metadata\": {\n    \"colab\": {\n      \"name\": \"Recommender-System-using-Softmax"
  }
]

About this extraction

This page contains the full source code of the rposhala/Recommender-System-on-MovieLens-dataset GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 6 files (1.0 MB), approximately 481.9k tokens. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!