---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
Cell In[11], line 14
     11     return movie_quality_simulation.output['movie_quality']
     13 # Apply the function to the dataset
---> 14 data['movie_quality_score'] = data.apply(compute_movie_quality, axis=1)

File C:\ProgramData\anaconda3\Lib\site-packages\pandas\core\frame.py:10374, in DataFrame.apply(self, func, axis, raw, result_type, args, by_row, engine, engine_kwargs, **kwargs)
  10360 from pandas.core.apply import frame_apply
  10362 op = frame_apply(
  10363     self,
  10364     func=func,
   (...)
  10372     kwargs=kwargs,
  10373 )
> 10374 return op.apply().__finalize__(self, method="apply")

File C:\ProgramData\anaconda3\Lib\site-packages\pandas\core\apply.py:916, in FrameApply.apply(self)
    913 elif self.raw:
    914     return self.apply_raw(engine=self.engine, engine_kwargs=self.engine_kwargs)
--> 916 return self.apply_standard()

File C:\ProgramData\anaconda3\Lib\site-packages\pandas\core\apply.py:1063, in FrameApply.apply_standard(self)
   1061 def apply_standard(self):
   1062     if self.engine == "python":
-> 1063         results, res_index = self.apply_series_generator()
   1064     else:
   1065         results, res_index = self.apply_series_numba()

File C:\ProgramData\anaconda3\Lib\site-packages\pandas\core\apply.py:1081, in FrameApply.apply_series_generator(self)
   1078 with option_context("mode.chained_assignment", None):
   1079     for i, v in enumerate(series_gen):
   1080         # ignore SettingWithCopy here in case the user mutates
-> 1081         results[i] = self.func(v, *self.args, **self.kwargs)
   1082         if isinstance(results[i], ABCSeries):
   1083             # If we have a view on v, we need to make a copy because
   1084             #  series_generator will swap out the underlying data
   1085             results[i] = results[i].copy(deep=False)

Cell In[11], line 11, in compute_movie_quality(row)
      8 # Compute the fuzzy result
      9 movie_quality_simulation.compute()
---> 11 return movie_quality_simulation.output['movie_quality']

KeyError: 'movie_quality'

Fix like senior programmer!
{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "d7e2d4d1",
   "metadata": {},
   "source": [
    "# Fuzzy Logic Analysis of Movie Data\n",
    "\n",
    "## Introduction\n",
    "\n",
    "In this notebook, we will perform a fuzzy logic analysis on a dataset of movies. The goal is to classify movies based on their IMDb rating, release year, and the number of votes they have received. We will employ fuzzy logic principles to handle the inherent uncertainty and vagueness in classifying movies into categories such as *Old Classic*, *Modern Hit*, or *Underrated Gem*.\n",
    "\n",
    "## Dataset Overview\n",
    "\n",
    "The dataset contains the following columns:\n",
    "\n",
    "- `title`: The title of the movie.\n",
    "- `type`: The type of the content (e.g., movie, series).\n",
    "- `genres`: The genres associated with the movie.\n",
    "- `releaseYear`: The year the movie was released.\n",
    "- `imdbAverageRating`: The average IMDb rating of the movie (0.0 - 10.0).\n",
    "- `imdbNumVotes`: The number of votes the movie has received on IMDb (up to 2,961,822).\n",
    "- `availableCountries`: The countries where the movie is available.\n",
    "\n",
    "We will read the data from `./data/data-cleaned.csv`."
   ]
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "## Setup",
   "id": "bcb89f18f9075445"
  },
  {
   "metadata": {},
   "cell_type": "code",
   "source": "!pip install numpy pandas scikit-fuzzy matplotlib requests",
   "id": "f8a75ccbcc5153d",
   "outputs": [],
   "execution_count": null
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": [
    "Import Dataset\n",
    "Link: https://www.kaggle.com/datasets/octopusteam/full-netflix-dataset"
   ],
   "id": "55be887827f180d1"
  },
  {
   "metadata": {},
   "cell_type": "code",
   "source": [
    "import requests, zipfile\n",
    "from io import BytesIO\n",
    "\n",
    "zipfile.ZipFile(BytesIO(requests.get('https://www.kaggle.com/api/v1/datasets/download/octopusteam/full-netflix-dataset', allow_redirects=True).content)).extractall('./data')"
   ],
   "id": "d1c1eed839db7935",
   "outputs": [],
   "execution_count": null
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "Clean Data set",
   "id": "439f5a0d37be3160"
  },
  {
   "metadata": {},
   "cell_type": "code",
   "source": [
    "import pandas as pd\n",
    "\n",
    "df = pd.read_csv('./data/data.csv')\n",
    "df_cleaned = df.dropna()\n",
    "\n",
    "df_cleaned = df_cleaned.drop(columns=['imdbId'])\n",
    "df_cleaned.to_csv('./data/data-cleaned.csv', index=False)"
   ],
   "id": "fd4eeee97d692053",
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "markdown",
   "id": "0c6acd7f",
   "metadata": {},
   "source": [
    "## Importing Necessary Libraries"
   ]
  },
  {
   "cell_type": "code",
   "id": "cdfba8b9",
   "metadata": {},
   "source": [
    "import numpy as np\n",
    "import pandas as pd\n",
    "import skfuzzy as fuzz\n",
    "from skfuzzy import control as ctrl\n",
    "import matplotlib.pyplot as plt\n",
    "%matplotlib inline"
   ],
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "markdown",
   "id": "89a3c9b6",
   "metadata": {},
   "source": [
    "## Loading the Dataset"
   ]
  },
  {
   "cell_type": "code",
   "id": "d95d1edc",
   "metadata": {},
   "source": [
    "# Load the dataset\n",
    "data = pd.read_csv('./data/data-cleaned.csv')\n",
    "\n",
    "# Display the first few rows\n",
    "data.head()"
   ],
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "markdown",
   "id": "e7fc9235",
   "metadata": {},
   "source": [
    "## Defining Fuzzy Variables\n",
    "\n",
    "We will define fuzzy variables for the following inputs and output:\n",
    "\n",
    "### Input Variables\n",
    "- **IMDb Rating** (`imdb_rating`): Ranges from 0.0 to 10.0.\n",
    "- **Release Year** (`release_year`): Ranges from 1900 to 2025.\n",
    "- **Number of Votes** (`num_votes`): Ranges from 0 to 3,000,000.\n",
    "\n",
    "### Output Variable\n",
    "- **Movie Quality** (`movie_quality`): A qualitative measure (e.g., *Low*, *Medium*, *High*)."
   ]
  },
  {
   "cell_type": "code",
   "id": "2256d896",
   "metadata": {},
   "source": [
    "# Define the universal variables\n",
    "imdb_rating = ctrl.Antecedent(np.arange(0, 10.1, 0.1), 'imdb_rating')\n",
    "release_year = ctrl.Antecedent(np.arange(1900, 2026, 1), 'release_year')\n",
    "num_votes = ctrl.Antecedent(np.arange(0, 3000001, 10000), 'num_votes')\n",
    "movie_quality = ctrl.Consequent(np.arange(0, 11, 1), 'movie_quality')"
   ],
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "markdown",
   "id": "2cfcaf5d",
   "metadata": {},
   "source": [
    "## Membership Functions\n",
    "\n",
    "We will define the membership functions for each variable. These functions map the crisp input values to degrees of membership between 0 and 1."
   ]
  },
  {
   "cell_type": "code",
   "id": "6029b95d",
   "metadata": {},
   "source": [
    "# IMDb Rating Membership Functions\n",
    "imdb_rating['low'] = fuzz.trimf(imdb_rating.universe, [0, 0, 5])\n",
    "imdb_rating['medium'] = fuzz.trimf(imdb_rating.universe, [4, 5.5, 7])\n",
    "imdb_rating['high'] = fuzz.trimf(imdb_rating.universe, [6, 10, 10])\n",
    "\n",
    "# Release Year Membership Functions\n",
    "release_year['classic'] = fuzz.trapmf(release_year.universe, [1900, 1900, 1970, 1990])\n",
    "release_year['modern'] = fuzz.trapmf(release_year.universe, [1985, 2000, 2010, 2025])\n",
    "\n",
    "# Number of Votes Membership Functions\n",
    "num_votes['few'] = fuzz.trimf(num_votes.universe, [0, 0, 100000])\n",
    "num_votes['average'] = fuzz.trimf(num_votes.universe, [50000, 200000, 500000])\n",
    "num_votes['many'] = fuzz.trimf(num_votes.universe, [400000, 3000000, 3000000])\n",
    "\n",
    "# Movie Quality Membership Functions\n",
    "movie_quality['low'] = fuzz.trimf(movie_quality.universe, [0, 0, 5])\n",
    "movie_quality['medium'] = fuzz.trimf(movie_quality.universe, [4, 5.5, 7])\n",
    "movie_quality['high'] = fuzz.trimf(movie_quality.universe, [6, 10, 10])"
   ],
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "markdown",
   "id": "f3f721b1",
   "metadata": {},
   "source": [
    "### Visualizing Membership Functions"
   ]
  },
  {
   "cell_type": "code",
   "id": "a70edf9f",
   "metadata": {},
   "source": [
    "# Visualize IMDb Rating Membership Functions\n",
    "imdb_rating.view()\n",
    "plt.show()"
   ],
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "code",
   "id": "a56c8eb1",
   "metadata": {},
   "source": [
    "# Visualize Release Year Membership Functions\n",
    "release_year.view()\n",
    "plt.show()"
   ],
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "code",
   "id": "a3cd6b65",
   "metadata": {},
   "source": [
    "# Visualize Number of Votes Membership Functions\n",
    "num_votes.view()\n",
    "plt.show()"
   ],
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "code",
   "id": "0e9bccfe",
   "metadata": {},
   "source": [
    "# Visualize Movie Quality Membership Functions\n",
    "movie_quality.view()\n",
    "plt.show()"
   ],
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "markdown",
   "id": "3958d38c",
   "metadata": {},
   "source": [
    "## Defining Fuzzy Rules\n",
    "\n",
    "We will define the fuzzy rules to model the decision-making logic. The rules are based on expert knowledge about what constitutes a *High*, *Medium*, or *Low* quality movie."
   ]
  },
  {
   "cell_type": "code",
   "id": "e3102beb",
   "metadata": {},
   "source": [
    "rule1 = ctrl.Rule(imdb_rating['high'] & num_votes['many'], movie_quality['high'])\n",
    "rule2 = ctrl.Rule(imdb_rating['medium'] & num_votes['average'], movie_quality['medium'])\n",
    "rule3 = ctrl.Rule(imdb_rating['low'] & num_votes['few'], movie_quality['low'])\n",
    "rule4 = ctrl.Rule(imdb_rating['high'] & release_year['classic'], movie_quality['high'])\n",
    "rule5 = ctrl.Rule(imdb_rating['medium'] & release_year['modern'], movie_quality['medium'])\n",
    "rule6 = ctrl.Rule(imdb_rating['low'] | num_votes['few'], movie_quality['low'])"
   ],
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "markdown",
   "id": "3fcf7fa9",
   "metadata": {},
   "source": [
    "## Building the Control System"
   ]
  },
  {
   "cell_type": "code",
   "id": "1170c33a",
   "metadata": {},
   "source": [
    "movie_quality_ctrl = ctrl.ControlSystem([rule1, rule2, rule3, rule4, rule5, rule6])\n",
    "movie_quality_simulation = ctrl.ControlSystemSimulation(movie_quality_ctrl)"
   ],
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "markdown",
   "id": "ad86e640",
   "metadata": {},
   "source": [
    "## Applying the Fuzzy Model to the Dataset\n",
    "\n",
    "We will apply the fuzzy model to each movie in the dataset and compute its quality score."
   ]
  },
  {
   "cell_type": "code",
   "id": "279540ab",
   "metadata": {},
   "source": [
    "# Define a function to compute movie quality\n",
    "def compute_movie_quality(row):\n",
    "    # Set input values\n",
    "    movie_quality_simulation.input['imdb_rating'] = row['imdbAverageRating']\n",
    "    movie_quality_simulation.input['release_year'] = row['releaseYear']\n",
    "    movie_quality_simulation.input['num_votes'] = row['imdbNumVotes']\n",
    "    \n",
    "    # Compute the fuzzy result\n",
    "    movie_quality_simulation.compute()\n",
    "    \n",
    "    return movie_quality_simulation.output['movie_quality']\n",
    "\n",
    "# Apply the function to the dataset\n",
    "data['movie_quality_score'] = data.apply(compute_movie_quality, axis=1)"
   ],
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "markdown",
   "id": "5b6ec7b6",
   "metadata": {},
   "source": [
    "## Analyzing the Results"
   ]
  },
  {
   "cell_type": "code",
   "id": "11a3e5f7",
   "metadata": {},
   "source": [
    "# Display the movies with the highest quality scores\n",
    "data.sort_values(by='movie_quality_score', ascending=False).head(10)"
   ],
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "markdown",
   "id": "5ef34d1f",
   "metadata": {},
   "source": [
    "## Visualizing the Movie Quality Distribution"
   ]
  },
  {
   "cell_type": "code",
   "id": "783e6f1a",
   "metadata": {},
   "source": [
    "# Plot the distribution of movie quality scores\n",
    "plt.figure(figsize=(10,6))\n",
    "plt.hist(data['movie_quality_score'], bins=20, color='skyblue', edgecolor='black')\n",
    "plt.title('Distribution of Movie Quality Scores')\n",
    "plt.xlabel('Movie Quality Score')\n",
    "plt.ylabel('Number of Movies')\n",
    "plt.show()"
   ],
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "markdown",
   "id": "e47bc537",
   "metadata": {},
   "source": [
    "## Conclusion\n",
    "\n",
    "Using fuzzy logic, we have created a model to evaluate movies based on their IMDb rating, release year, and number of votes. This approach allows us to handle the uncertainties and subjective judgments inherent in movie quality assessment. The results can aid in identifying movies that are considered high quality according to the defined fuzzy rules."
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}