{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "3e1205b8",
   "metadata": {},
   "outputs": [],
   "source": [
    "import pandas as pd\n",
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "import seaborn as sns\n",
    "from sklearn.feature_extraction.text import TfidfVectorizer\n",
    "from scipy.sparse import csr_matrix\n",
    "from sklearn.decomposition import TruncatedSVD\n",
    "import joblib"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "14d5fa17",
   "metadata": {},
   "outputs": [],
   "source": [
    "CLEAN_TMDB_FILE_PATH = \"../datasets/clean/tmdb-movies/TMDB_movie_dataset_v11.csv\"\n",
    "CLEAN_MOVIELENS_RATINGS_PATH = \"../datasets/clean/ml-32m/ratings.csv\"\n",
    "\n",
    "ML_API_TF_IDF_MATRIX_PATH = \"../../ml-api/model/tf_idf_matrix.pkl\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "9519c1e4",
   "metadata": {},
   "outputs": [],
   "source": [
    "tmdb = pd.read_csv(CLEAN_TMDB_FILE_PATH)\n",
    "ratings = pd.read_csv(CLEAN_MOVIELENS_RATINGS_PATH)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "b25fd422",
   "metadata": {},
   "outputs": [],
   "source": [
    "ratings_glob_mean = ratings[\"rating\"].mean()\n",
    "tmdb_id_to_index = pd.Series(tmdb.index, index=tmdb[\"id\"]).to_dict()\n",
    "ratings[\"rating\"] = ratings[\"rating\"] - ratings_glob_mean"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d8366c37",
   "metadata": {},
   "outputs": [],
   "source": [
    "plt.hist(ratings[\"rating\"], bins=50)\n",
    "plt.title(\"Distribution ratings\")\n",
    "plt.xlabel(\"Score\")\n",
    "plt.ylabel(\"Frequency\")\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "47e8442c",
   "metadata": {},
   "outputs": [],
   "source": [
    "print(\"min:\", ratings[\"rating\"].min())\n",
    "print(\"max:\", ratings[\"rating\"].max())\n",
    "print(\"mean:\", ratings[\"rating\"].mean())\n",
    "print(\"std:\", ratings[\"rating\"].std())\n",
    "print(np.percentile(ratings[\"rating\"], [0, 25, 50, 75, 100]))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "dc0af892",
   "metadata": {},
   "outputs": [],
   "source": [
    "def find_in_dataset_by_substring(movie_names):\n",
    "    found = []\n",
    "    for movie_name in movie_names:\n",
    "        results = tmdb[tmdb[\"title\"].str.contains(movie_name, case=False, na=False)]\n",
    "        haa = results.sort_values(by=\"popularity\", ascending=False)[[\"id\", \"title\"]]\n",
    "        found.append(haa.values.tolist())\n",
    "    return found\n",
    "\n",
    "def find_in_dataset_by_id(movie_id):\n",
    "    return tmdb[tmdb[\"id\"] == movie_id][\"title\"].values[0]\n",
    "\n",
    "def print_ratings_dict(ratings_dict: dict[int, int]):\n",
    "    for id, rating in ratings_dict.items():\n",
    "        print(f\"id: {id}, name: {find_in_dataset_by_id(id)}, rating: {rating}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4014001f",
   "metadata": {},
   "outputs": [],
   "source": [
    "find_in_dataset_by_substring([\"justice\", \"batman\", \"superman\", \"flash\", \"lantern\", \"steel\", \"watchmen\", \"joker\"])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "53bb21b9",
   "metadata": {},
   "outputs": [],
   "source": [
    "find_in_dataset_by_id(791373)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "616210d8",
   "metadata": {},
   "outputs": [],
   "source": [
    "marvel_fan_rd = {\n",
    "  569094: 4.5,\n",
    "  634649: 4,\n",
    "  271110: 3,\n",
    "  1771: 4,\n",
    "  10138: 4.5,\n",
    "  1724: 3.5,\n",
    "  26881: 4,\n",
    "  299536: 5,\n",
    "  9320: 4.5\n",
    "}\n",
    "\n",
    "print_ratings_dict(marvel_fan_rd)\n",
    "print()\n",
    "print()\n",
    "print()\n",
    "\n",
    "marvel_fan_dc_hater_rd = {\n",
    "  569094: 4.5,\n",
    "  634649: 4,\n",
    "  271110: 3,\n",
    "  1771: 4,\n",
    "  10138: 4.5,\n",
    "  1724: 3.5,\n",
    "  26881: 4,\n",
    "  299536: 5,\n",
    "  9320: 4.5,\n",
    "  141052: 1,\n",
    "  209112: 0,\n",
    "  414906: 2.5,\n",
    "  272: 1.4,\n",
    "  1924: 1,\n",
    "  298618: 0.7,\n",
    "  44912: 0,\n",
    "  49521: 1.8,\n",
    "  13183: 0.3,\n",
    "  475557: 3\n",
    "}\n",
    "\n",
    "print_ratings_dict(marvel_fan_dc_hater_rd)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d7057e23",
   "metadata": {},
   "source": [
    "Collaborative filtering\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1bb3bbdf",
   "metadata": {},
   "outputs": [],
   "source": [
    "ratings[ratings[\"tmdbId\"].isna()]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f342aee6",
   "metadata": {},
   "outputs": [],
   "source": [
    "ratings[ratings[\"userId\"].isna()]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e3ff770e",
   "metadata": {},
   "outputs": [],
   "source": [
    "movie_stats = ratings.groupby(\"tmdbId\").agg(\n",
    "    avg=(\"rating\", \"mean\"),\n",
    "    count=(\"rating\", \"count\")\n",
    ")\n",
    "\n",
    "good_movies = movie_stats[\n",
    "    (movie_stats[\"count\"] >= 0)\n",
    "].index\n",
    "\n",
    "ratings_filtered = ratings[ratings[\"tmdbId\"].isin(good_movies)]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "0f76bfc1",
   "metadata": {},
   "outputs": [],
   "source": [
    "len(np.sort(ratings[\"tmdbId\"].unique()))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "274ee0b4",
   "metadata": {},
   "outputs": [],
   "source": [
    "ratings_test = ratings_filtered\n",
    "\n",
    "\n",
    "user_ids = np.sort(ratings_test[\"userId\"].unique())\n",
    "movie_ids = np.sort(ratings_test[\"tmdbId\"].unique())\n",
    "\n",
    "user_map = {u: i for i, u in enumerate(user_ids)}\n",
    "movie_map = {m: i for i, m in enumerate(movie_ids)}\n",
    "\n",
    "n_users = len(user_ids)\n",
    "n_items = len(movie_ids)\n",
    "\n",
    "rows = ratings_test[\"userId\"].map(user_map)\n",
    "cols = ratings_test[\"tmdbId\"].map(movie_map)\n",
    "data = ratings_test[\"rating\"]\n",
    "\n",
    "R = csr_matrix((data, (rows, cols)), shape=(n_users, n_items))\n",
    "\n",
    "svd = TruncatedSVD(n_components=35)\n",
    "U = svd.fit_transform(R)\n",
    "V = svd.components_"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "6fc2eb3d",
   "metadata": {},
   "outputs": [],
   "source": [
    "U"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4ffe4492",
   "metadata": {},
   "outputs": [],
   "source": [
    "V"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "87abff91",
   "metadata": {},
   "outputs": [],
   "source": [
    "def build_user_profile_collab(ratings_dict):\n",
    "    _indices = []\n",
    "    _ratings = []\n",
    "\n",
    "    for tmdb_id, rating in ratings_dict.items():\n",
    "        if tmdb_id in movie_map:\n",
    "            _indices.append(movie_map[tmdb_id])\n",
    "            _ratings.append(rating - ratings_glob_mean)\n",
    "        \n",
    "    V_sub = V[:, _indices]\n",
    "    r = np.array(_ratings)\n",
    "    user_vector = r @ V_sub.T\n",
    "    return user_vector"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4c8a264e",
   "metadata": {},
   "outputs": [],
   "source": [
    "def recommend_content(user_vector, top_k=20):\n",
    "    scores = user_vector @ V\n",
    "\n",
    "    top_idx = scores.argsort()[::-1][:top_k]\n",
    "    top_movies = [(movie_ids[i], scores[i]) for i in top_idx]\n",
    "\n",
    "    results = []\n",
    "\n",
    "    tmdb_indexed = tmdb.set_index(\"id\")\n",
    "\n",
    "    for movie_id, score in top_movies:\n",
    "        if movie_id in tmdb_indexed.index:\n",
    "            title = tmdb_indexed.loc[movie_id][\"title\"]\n",
    "            results.append((title, score))\n",
    "    \n",
    "    return results\n",
    "\n",
    "def find_recommended_content(user_vector, movie_id):\n",
    "    pass\n",
    "\n",
    "def analyze_recommended_content(user_vector):\n",
    "    pass\n",
    "    sims = cosine_similarity(user_vector, tfidf_matrix).flatten()\n",
    "    weighted_sims = sims * tmdb[\"popularity_log\"].values\n",
    "    \n",
    "    results = tmdb[[\"id\", \"title\", \"vote_average\", \"popularity\"]].copy()\n",
    "    results[\"match_score\"] = weighted_sims\n",
    "\n",
    "    # --- 1. Základní statistiky a percentily ---\n",
    "    print(\"=== STATISTIKY MATCH SCORE ===\")\n",
    "    stats = results[\"match_score\"].describe(percentiles=[0.5, 0.75, 0.90, 0.95, 0.99])\n",
    "    print(stats)\n",
    "    print(\"\\n\")\n",
    "\n",
    "    # --- 2. Analýza distribuce (Kladné vs Záporné) ---\n",
    "    print(\"=== DISTRIBUCE SKÓRE ===\")\n",
    "    kladne = (results[\"match_score\"] > 0).sum()\n",
    "    zaporne = (results[\"match_score\"] < 0).sum()\n",
    "    nuly = (results[\"match_score\"] == 0).sum()\n",
    "    \n",
    "    print(f\"Filmy s kladným skóre (kandidáti na doporučení): {kladne}\")\n",
    "    print(f\"Filmy se záporným skóre (aktivně penalizované):  {zaporne}\")\n",
    "    print(f\"Filmy s nulovým skóre (žádná shoda v textu):    {nuly}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ec2541ff",
   "metadata": {},
   "outputs": [],
   "source": [
    "marvel_fan = build_user_profile_collab(marvel_fan_rd)\n",
    "recommend_content(marvel_fan)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "33a73386",
   "metadata": {},
   "outputs": [],
   "source": [
    "marvel_fan_dc_hater = build_user_profile_collab(marvel_fan_dc_hater_rd)\n",
    "recommend_content(marvel_fan_dc_hater)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "60d89950",
   "metadata": {},
   "outputs": [],
   "source": [
    "ratings_glob_mean"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e0c2974b",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": ".venv (3.13.9)",
   "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.13.9"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
