<jupyter_start><jupyter_text>Installieren aller Pakete<jupyter_code># Hier die Kaggle Credentials einfügen (ohne Anführungszeichen)

%env KAGGLE_USERNAME=openhpi
%env KAGGLE_KEY=das_ist_der_key
import nltk
from nltk.corpus import stopwords
nltk.download('stopwords')
from nltk.tokenize import word_tokenize
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.metrics.pairwise import linear_kernel
from sklearn.neighbors import NearestNeighbors
from scipy.sparse import csr_matrix

import numpy as np
import pandas as pd<jupyter_output><empty_output><jupyter_text>2.5 Recommender Systems 1:  Vorschlagssystem mit Content-based Filtering Datensatz:  The Movies DatasetMetadaten für über 45.000 Filme. 26 Millionen Bewertungen von über 270.000 NutzerInnen.Quelle: kaggle.com  Download Dataset   Manuellvia https://www.kaggle.com/rounakbanik/the-movies-dataset  Via APIHinzufügen der kaggle.jsonSpeichern als ~/.kaggle/kaggle.json auf Linux, OSX, oder andere UNIX-based Betriebssysteme und unter C:\Users.kaggle\kaggle.json auf WindowsSiehe https://www.kaggle.com/docs/api oder https://github.com/Kaggle/kaggle-api        Beispiel:~/kaggle/kaggle.json{"username":"openHPI","key":"das_ist_der_key"}  Was wir erreichen wollenWie in der Theorie-Einheit beschrieben, wollen wir Filme vorschlagen, die bisher gesehenen Filmen inhaltlich ähnlich sind. Hat Person 1 also bereits Film A gesehen, so wollen wir Filme vorschlagen, die Film A inhaltlich ähnlich sind. Was inhaltliche Ähnlichkeit genau bedeutet, kann man auf verschiedene Arten interpretieren und umsetzen - wir fokussieren uns hierbei auf die inhaltliche Ähnlichkeit der Kurzbeschreibungen der Filme.   Einlesen der Daten<jupyter_code>!pip3 install kaggle
!kaggle datasets download -d rounakbanik/the-movies-dataset
import zipfile
with zipfile.ZipFile("the-movies-dataset.zip", 'r') as zip_ref:
    zip_ref.extractall("")
import pandas as pd
df_film_metadata = pd.read_csv("movies_metadata.csv", low_memory=False)<jupyter_output><empty_output><jupyter_text>Beschreibung eines Beispiel-Films:<jupyter_code>print("Film-Titel: " + df_film_metadata["title"][9] + "\n")
print("Film-Beschreibung: " + df_film_metadata["overview"][9])<jupyter_output><empty_output><jupyter_text>Wir betrachten erneut einmal die verschiedenen Titel der Filme. Hier sieht man erneut die Gesamtanzahl aller Filme mit **45466**. Auffällig ist auch, das ein Film hier in dieser Ansicht keinen englischen Titel trägt.<jupyter_code>df_film_metadata["original_title"]<jupyter_output><empty_output><jupyter_text>Wir wollen auch kurz untersuchen, ob das für uns im Laufe der Analyse zum Problem wird. Grundsätzlich sollte man als Input eines Machine Learning Modells stets auf identische Einheiten achten und so auch auf gleiche Sprachen bei Textfeldern. Das ist hier jedoch kein Problem, da wir die Spalte mit den Original-Titeln betrachtet haben. Die Spalte "title" hingegen enthält den Titel in übersetzer Form und auch die "overview" Spalte enthält Englisch.<jupyter_code>print("Original-Film-Titel: " + df_film_metadata["original_title"][45461] + "\n")
print("Film-Titel: " + df_film_metadata["title"][45461] + "\n")
print("Film-Beschreibung: " + df_film_metadata["overview"][45461])<jupyter_output><empty_output><jupyter_text>Filtern fehlender Werte Da wir Filme anhand deren Kurzbeschreibung verleichen wollen, so wollen wir natürlich nur jene Filme beachten, die auch eine Beschreibung enthalten. Gibt es überhaupt Filme ohne Kurzbeschreibung?<jupyter_code>df_film_metadata[df_film_metadata['overview'].isna()]
df_film_metadata = df_film_metadata[df_film_metadata['overview'].notna()]
df_film_metadata = df_film_metadata.reset_index()<jupyter_output><empty_output><jupyter_text>Ähnlichkeitsberechnungen  Etwas Theorie: **Count Vectorizer**Bei einem Count Vectorizer konvertiert man Texte in eine Matrix mit den Anzahlen der Vorkommnisse der verschiedenen Tokens. Ein Token ist eine Sequenz von Zeichen (z.B. "Christian" oder "Johannes", jedoch kann auch "Johannes und Christian" ein einzelner Token sein).<jupyter_code>text = ["Künstliche Intelligenz und Maschinelles Lernen in der Praxis", 
        "Künstliche Intelligenz und maschinelles Lernen für Einsteiger", 
       "Connected Healthcare: Gesundheitsdaten im Alltag erfassen und analysieren"]


cv = CountVectorizer()
count_matrix = cv.fit_transform(text)
np.set_printoptions(precision=3)
print("Feature-Names: " + str(cv.get_feature_names()) + "\n")
print("Matrix: \n" + str(count_matrix.todense()))<jupyter_output><empty_output><jupyter_text>Etwas Theorie: **Tf-idf Vectorizer**Bei einem Tf-idf Vectorizer misst man die inverse Dokumenthäufigkeit von Tokens. Das Vorkommen von seltener Begriffe ist hier relevanter als das Vorkommen von häufigen Wörtern (z.B. "und" oder "das").Der Tf-idf Wert eines Tokens wird wie folgt berechnet:$$ TF(w,d) = \frac{Anzahl\; von\; Wort\; w\; in\; Dokument\; d}{Gesamtanzahl\; von\; Woertern\; in\; Dokument\; d} $$$$ IDF(w, D) = ln \left ( \;\frac{Gesamtanzahl\;  von\; Dokumenten\; (N)\; in\; Corpus\; D }{Anzahl\; von\; Dokumenten\; die\; Wort\; w\; enthalten}\;\right ) $$Der Gesamtwert berechnet sich wie folgt:$$TFIDF(w,d,D) = TF(w,d) * IDF(w,D)$$<jupyter_code>text = ["Künstliche Intelligenz und Maschinelles Lernen in der Praxis", 
        "Künstliche Intelligenz und maschinelles Lernen für Einsteiger", 
       "Connected Healthcare: Gesundheitsdaten im Alltag erfassen und analysieren"]


tfidf = TfidfVectorizer()
tfidf_matrix = tfidf.fit_transform(text)
np.set_printoptions(precision=3)
print("Feature-Names: " + str(tfidf.get_feature_names()) + "\n")
print("Matrix: \n" + str(tfidf_matrix.todense()))<jupyter_output><empty_output><jupyter_text>Berechnung der Ähnlichkeit auf Film-Beschreibungen<jupyter_code>tfidf = TfidfVectorizer(stop_words='english')
tfidf_matrix = tfidf.fit_transform(df_film_metadata['overview'])<jupyter_output><empty_output><jupyter_text>Wie viele Wörter wurden jetzt bei dieser Tfidf Vektorisierung jetzt beachtet? Dafür geben wir uns einmal die Form der resultierenden Matrix aus. Hier sehen wir, dass die Matrix 44512x75827 groß ist. 44512 ist die Anzahl der Filme, so haben wir also 75827 Features (ein Feature ist hier ein Wort).<jupyter_code>tfidf_matrix.shape<jupyter_output><empty_output><jupyter_text>Wenn wir die Ähnlichkeiten zwischen Filmen berechnen, dann müssen wir ermöglichen, mit dem Titel auf die Positionen in der Matrix zugreifen zu können. Hierfür kreieren wir eine Art Dictionary, um von dem jeweiligen Titel auf die Position des Films zu kommen.<jupyter_code>title_to_index = pd.Series(df_film_metadata.index, index=df_film_metadata['title'])
title_to_index<jupyter_output><empty_output><jupyter_text>K-Nearest-Neighbors Um die Ähnlichkeiten zwischen den Filmen zu ermitteln nutzen wir den K-Nearest-Neighbor Ansatz. Als Ähnlichkeitsmaß nehmen wir die Cosine Similarity zwischen den tfidf-Vectoren. Die Cosine Similarity ist eine von vielen verschiedenen Möglichkeiten "Ähnlichkeit in hochdimensionalem Raum" zu berechnen.<jupyter_code>movie_matrix=csr_matrix(tfidf_matrix)
model_knn= NearestNeighbors(metric='cosine', algorithm='auto', n_neighbors=10, n_jobs=-1)
def recommend_films_by_title_knn(title, data, model, n_neighbors):
    model.fit(data)
    movie_idx = title_to_index[title]
    sim_scores, movie_indices = model.kneighbors(data[movie_idx], n_neighbors=n_neighbors+1)
    sim_scores = sim_scores.squeeze().tolist()
    recommendation_list = []
    for idx, movie_idx in enumerate(movie_indices.squeeze().tolist()):
        recommendation_list.append({'Title':df_film_metadata['title'][movie_idx],'Similarity':sim_scores[idx]})
    return pd.DataFrame(recommendation_list).sort_values(by=['Similarity'], ascending=False).reset_index(drop=True)[:-1]<jupyter_output><empty_output><jupyter_text>Wir wollen uns nun einmal einen Vorschlag zu dem Film "Golden Eye", also einem James-Bond Film ausgeben.<jupyter_code>recommend_films_by_title_knn("GoldenEye", movie_matrix, model_knn, n_neighbors=10)<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.09473814229249011, 'fraction_numerical': 0.008522727272727272, 'mean_word_length': 6.876459143968872, 'pattern_counts': {'":': 2, '<': 53, '<?xml version=': 0, '>': 53, 'https://': 3, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 3, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '13', 'dir': 'jupyter-structured-clean-dedup', 'id': '481528', 'license': 'MIT', 'n_tokens_mistral': 2910, 'n_tokens_neox': 2847, 'n_words': 709, 'path': 'Woche 2/2_5_Recommender_Systems_1.ipynb', 'repo_name': 'sting-aree/openhpi-kipraxis', 'size': '8096'}