Corso
A causa della nuova cultura del binge-watching di serie TV e film, gli utenti consumano contenuti a ritmo sostenuto grazie a servizi come Netflix, Prime Video, Hulu e Disney+. Alcune di queste nuove piattaforme, come Hulu e YouTube TV, offrono anche lo streaming live di eventi come sport, concerti/tour dal vivo e canali di notizie. Lo streaming live non è ancora stato adottato da alcune piattaforme, come Netflix.
Le piattaforme di streaming offrono agli utenti maggiore flessibilità per guardare le loro serie e i loro film preferiti, in qualsiasi momento e su qualsiasi dispositivo. Questi servizi possono attrarre più consumatori giovani e moderni grazie all’ampia varietà di contenuti. Consentono inoltre di recuperare qualsiasi programma perso in base alla disponibilità. In questo tutorial analizzerai i dati dei film delle piattaforme di streaming Netflix, Prime Video, Hulu e Disney+ e proverai a comprendere il loro pubblico.

Comprendere il dataset
Questo dataset include solo film disponibili su piattaforme di streaming come Netflix, Prime Video, Hulu e Disney+. Puoi scaricarlo da Kaggle qui.
Descriviamo in dettaglio gli attributi dei dati:
- ID: un ID univoco per ogni record.
- Title: il nome del film
- Year: anno di uscita del film.
- Age: fascia d’età di riferimento
- IMDb: valutazione IMDB dei film.
- Rotten Tomatoes: percentuale Rotten Tomatoes
- Netflix: se il film è presente su Netflix
- Hulu: se il film è presente su Hulu
- Prime Video: se il film è presente su Prime Video
- Disney+: se il film è presente su Disney+
- Type: film o serie TV
- Directors: nome del regista
- Genres: tipo di genere
- Country: paese di origine
- Language: lingua di origine
- Runtime: durata del film
Importiamo i moduli necessari e carichiamo il dataset:
# Import required libraries
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.feature_extraction.text import TfidfVectorizer
from nltk.tokenize import RegexpTokenizer
import numpy as np
from sklearn import preprocessing
from scipy.sparse import hstack
import pandas_profiling
# Load dataset
df = pd.read_csv("tvshow.csv")
df=df.iloc[:,1:] # removing in unnamed index column
df.head()
| Unnamed: 0 | ID | Title | Year | Age | IMDb | Rotten Tomatoes | Netflix | Hulu | Prime Video | Disney+ | Type | Directors | Genres | Country | Language | Runtime | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 0 | 1 | Inception | 2010 | 13+ | 8.8 | 87% | 1 | 0 | 0 | 0 | 0 | Christopher Nolan | Action,Adventure,Sci-Fi,Thriller | United States,United Kingdom | English,Japanese,French | 148.0 |
| 1 | 1 | 2 | The Matrix | 1999 | 18+ | 8.7 | 87% | 1 | 0 | 0 | 0 | 0 | Lana Wachowski,Lilly Wachowski | Action,Sci-Fi | United States | English | 136.0 |
| 2 | 2 | 3 | Avengers: Infinity War | 2018 | 13+ | 8.5 | 84% | 1 | 0 | 0 | 0 | 0 | Anthony Russo,Joe Russo | Action,Adventure,Sci-Fi | United States | English | 149.0 |
| 3 | 3 | 4 | Back to the Future | 1985 | 7+ | 8.5 | 96% | 1 | 0 | 0 | 0 | 0 | Robert Zemeckis | Adventure,Comedy,Sci-Fi | United States | English | 116.0 |
| 4 | 4 | 5 | The Good, the Bad and the Ugly | 1966 | 18+ | 8.8 | 97% | 1 | 0 | 1 | 0 | 0 | Sergio Leone | Western | Italy,Spain,West Germany | Italian | 161.0 |
# Show initial information about the dataset
df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 16744 entries, 0 to 16743
Data columns (total 16 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 ID 16744 non-null object
1 Title 16744 non-null object
2 Year 16744 non-null int64
3 Age 7354 non-null object
4 IMDb 16173 non-null float64
5 Rotten Tomatoes 5158 non-null object
6 Netflix 16744 non-null int64
7 Hulu 16744 non-null int64
8 Prime Video 16744 non-null int64
9 Disney+ 16744 non-null int64
10 Type 16744 non-null int64
11 Directors 16018 non-null object
12 Genres 16469 non-null object
13 Country 16309 non-null object
14 Language 16145 non-null object
15 Runtime 16152 non-null float64
dtypes: float64(2), int64(6), object(8)
memory usage: 2.0+ MB
df.Type.unique()
array([0])
Gestire i valori mancanti
In questa sezione lavorerai con i valori mancanti usando la funzione isnull(). Vediamo un esempio:
#Finding Missing values in all columns
miss = pd.DataFrame(df.isnull().sum())
miss = miss.rename(columns={0:"miss_count"})
miss["miss_%"] = (miss.miss_count/len(df.ID))*100
miss
| misscount | miss% | |
|---|---|---|
| ID | 0 | 0.000000 |
| Title | 0 | 0.000000 |
| Year | 0 | 0.000000 |
| Age | 9390 | 56.079790 |
| IMDb | 571 | 3.410177 |
| Rotten Tomatoes | 11586 | 69.194935 |
| Netflix | 0 | 0.000000 |
| Hulu | 0 | 0.000000 |
| Prime Video | 0 | 0.000000 |
| Disney+ | 0 | 0.000000 |
| Type | 0 | 0.000000 |
| Directors | 726 | 4.335882 |
| Genres | 275 | 1.642379 |
| Country | 435 | 2.597946 |
| Language | 599 | 3.577401 |
| Runtime | 592 | 3.535595 |
Puoi vedere che le variabili Age e Rotten Tomatoes hanno oltre il 50% di valori mancanti, il che è preoccupante.
Ora gestiremo i valori mancanti nei seguenti passaggi:
- Elimina le colonne con più del 50% di valori mancanti
- Elimina i NA dalle colonne IMDb, Directors, Genres, Country, Language e Runtime
- Reimposta l’indice
- Converti la colonna year in object
# Dropping values with missing % more than 50%
df.drop(['Rotten Tomatoes', 'Age'], axis = 1, inplace=True)
# Dropping Na's from the following columns
df.dropna(subset=['IMDb','Directors', 'Genres', 'Country', 'Language', 'Runtime'],inplace=True)
df.reset_index(inplace=True,drop=True)
# Converting into object type
df.Year = df.Year.astype("object")
df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 15233 entries, 0 to 15232
Data columns (total 14 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 ID 15233 non-null object
1 Title 15233 non-null object
2 Year 15233 non-null object
3 IMDb 15233 non-null float64
4 Netflix 15233 non-null int64
5 Hulu 15233 non-null int64
6 Prime Video 15233 non-null int64
7 Disney+ 15233 non-null int64
8 Type 15233 non-null int64
9 Directors 15233 non-null object
10 Genres 15233 non-null object
11 Country 15233 non-null object
12 Language 15233 non-null object
13 Runtime 15233 non-null float64
dtypes: float64(2), int64(5), object(7)
memory usage: 1.6+ MB
Grafici di distribuzione
Puoi verificare la distribuzione della colonna Year usando la funzione distplot() di seaborn. Tracciamo il grafico della distribuzione dell’anno di uscita dei film.
#checking Distribution of years
plt.figure(figsize=(20,5))
sns.distplot(df['Year'])
plt.show()

Il grafico mostra la distribuzione dell’anno di origine dei film. Si può interpretare che la maggior parte dei film è stata realizzata tra il 2000 e il 2020. Tracciamo ora il grafico di distribuzione del punteggio IMDB.
# Distribution of IMDb Rating
plt.figure(figsize=(20,5))
sns.distplot(df['IMDb'])
plt.show()

La distribuzione sopra è leggermente asimmetrica. Si può interpretare che la media IMDB della maggior parte dei film è 6,5.
Tracciamo il grafico di distribuzione della durata dei film.
# Distribution of runtime
sns.distplot(df['Runtime'])
plt.show()

Dal grafico sopra, si può interpretare che la durata media dei film è compresa tra 80 e 120 minuti.
Distribuzione dei film su ciascuna piattaforma di streaming
In questa sezione vedrai la distribuzione dei film per piattaforma. Prima, devi creare una funzione m_cnt() che conti i film per una determinata piattaforma. Dopodiché, puoi tracciare dei grafici a torta per comprendere le quote delle piattaforme.
# A function to calculate the movies in different Streaming platforms
def m_cnt(plat, count=False):
if count==False:
print('Platform {} Count: {}'. format(plat, df[plat].sum()))
else:
return df[plat].sum()
# Let's see count of movies/shows of each streaming platform
m_cnt('Netflix')
m_cnt('Hulu')
m_cnt('Prime Video')
m_cnt('Disney+')
Platform Netflix Count: 3152
Platform Hulu Count: 848
Platform Prime Video Count: 11289
Platform Disney+ Count: 542
# Movies on each platform
lab = 'Prime Video','Netflix', 'Hulu', 'Disney'
s = [m_cnt('Prime Video', count=True),
m_cnt('Netflix', count=True),
m_cnt('Hulu', count=True),
m_cnt('Disney+', count=True)]
explode = (0.1, 0.1, 0.1, 0.1)
#plotting
fig1, ax1 = plt.subplots()
ax1.pie(s,
labels = lab,
autopct = '%1.1f%%',
explode = explode,
shadow = True,
startangle = 100)
ax1.axis = ('equal')
plt.show()

Dal grafico sopra, si può dire che Prime Video ospita il numero massimo di titoli con una quota del 71%, e Netflix ospita il 20% dei titoli. Disney+ e Hulu ospitano il minor numero di titoli, rispettivamente il 5,4% e il 3,4%.
Distribuzione dei film per genere
In questa sezione vedrai la distribuzione dei film per genere. Prima devi preparare i dati. Devi gestire i generi multipli presenti in una singola cella del dataframe. Per farlo, puoi usare le funzioni split(), apply() e stack(). La funzione split() separa i valori multipli con una virgola e crea una lista. apply(pd.Series,1) crea più colonne per ciascun genere e la funzione stack() le impila in una singola colonna.
Dopo queste tre operazioni, una nuova colonna Genres si unirà al dataframe esistente e sarai pronto per tracciare. Puoi mostrare i primi 10 generi con il relativo conteggio usando la funzione value_counts() e usare la funzione plot() della libreria pandas.
##split the genres by ',' & then stack it one after the other for easy analysis.
g = df['Genres'].str.split(',').apply(pd.Series, 1).stack()
g.index = g.index.droplevel(-1)
# Assign name to column
g.name = 'Genres'
# delete column
del df['Genres']
# join new column with the existing dataframe
df_genres = df.join(g)
# Count of movies according to genre
plt.figure(figsize=(15,5))
sns.countplot(x='Genres', data=df_genres)
plt.xticks(rotation=90)
plt.show()

Dal grafico sopra, si può dire che la maggior parte dei film rientra nei generi Drama e Comedy.
Distribuzione dei film per paese
In questa sezione vedrai la distribuzione dei film per paese. Prima devi preparare i dati. Devi gestire paesi multipli presenti in una singola cella del dataframe. Per farlo, puoi usare le funzioni split(), apply() e stack(). La funzione split() separa i valori multipli con una virgola e crea una lista. apply(pd.Series,1) crea più colonne per ciascun paese e la funzione stack() le impila in una singola colonna.
Dopo queste tre operazioni, una nuova colonna Country si unirà al dataframe esistente e sarai pronto per tracciare. Puoi mostrare i primi 10 paesi con il relativo conteggio usando la funzione value_counts() e la funzione plot() della libreria pandas.
# Split the Country by ',' & then stack it one after the other for easy analysis.
c = df['Country'].str.split(',').apply(pd.Series, 1).stack()
c.index = c.index.droplevel(-1)
# Assign name to column
c.name = 'Country'
# delete column
del df['Country']
# join new column with the existing dataframe
df_country = df.join(c)
# plotting top 10 country and movie count
df_country['Country'].value_counts()[:10].plot(kind='bar',figsize=(15,5))
plt.show()

Il grafico sopra mostra che la maggior parte dei film è stata realizzata negli Stati Uniti.
Distribuzione dei film per lingua
In questa sezione vedrai la distribuzione dei film per lingua. Prima devi preparare i dati. Devi gestire lingue multiple presenti in una singola cella del dataframe. Per farlo, puoi usare le funzioni split(), apply() e stack(). La funzione split() divide i valori multipli con una virgola e crea una lista. apply(pd.Series,1) crea più colonne per ciascuna lingua e la funzione stack() le impila in una singola colonna.
Dopo queste tre operazioni, una nuova colonna Language si unirà al dataframe esistente e sarai pronto per tracciare. Puoi mostrare le prime 10 lingue con il relativo conteggio usando la funzione value_counts() e usare la funzione plot() della libreria pandas.
# perform stacking operation on language column
l = df['Language'].str.split(',').apply(pd.Series,1).stack()
l.index = l.index.droplevel(-1)
# Assign name to column
l.name = 'Language'
# delete column
del df['Language']
# join new column with the existing dataframe
df_language = df.join(l)
# plotting top 10 Language and movie count
df_language['Language'].value_counts()[:10].plot(kind='bar',figsize=(15,3))
plt.show()

Dal grafico sopra, puoi concludere che la maggior parte dei film è in lingua inglese.
Distribuzione delle valutazioni IMDB su ciascuna piattaforma
In questa sezione tracerai la distribuzione delle valutazioni IMDB per piattaforma. Per ottenere questi risultati, devi applicare la funzione melt() e tracciare un FacetGrid. La funzione melt() converte un dataframe in formato wide in un dataframe in formato long. Vediamo un esempio:
# melting platform columns to create visualization
df2 = pd.melt(df, id_vars=["ID","Title","Year","IMDb","Type","Runtime"], var_name="platform")
df2 = df2[df2.value==1]
df2.drop(columns=["value"],axis=1,inplace=True)
# Distribution of IMDB rating in different platform
g = sns.FacetGrid(df2, col = "platform")
g.map(plt.hist, "IMDb")
plt.show()

Il grafico sopra mostra la distribuzione media delle valutazioni IMDB su ciascuna piattaforma.

Durata per piattaforma suddivisa per fascia d’età
Nella sezione "Gestire i valori mancanti" ho eliminato la colonna Age. Per ottenere i risultati sulla durata per piattaforma in base alla fascia d’età, devo caricare di nuovo i dati e applicare la funzione melt().
# Load dataset
df = pd.read_csv("tvshow.csv")
df=df.iloc[:,1:]
df.ID = df.ID.astype("object")
# melting platform columns to create visualization
df2 = pd.melt(df, id_vars=["ID","Title","Year","Age","IMDb","Rotten Tomatoes","Type","Runtime"], var_name="platform")
df2 = df2[df2.value==1]
df2.drop(columns=["value"],axis=1,inplace=True)
Dopo aver ricaricato il dataset ed eseguito il melt, è il momento di generare un grafico della durata in base alla piattaforma per le diverse fasce d’età.
# Total of runtime in different platform
ax = sns.barplot(x="platform", y="Runtime",hue="Age", estimator=sum, data=df2)

Il grafico sopra mostra che il tempo di visione totale su Prime Video per gli utenti 18+ è molto più alto rispetto a qualsiasi altra piattaforma. Si può interpretare che su Prime Video gran parte dei contenuti è orientata alla fascia 18+.
Costruire un sistema di raccomandazione
Negli ultimi anni, con l’ascesa di YouTube, Walmart, Netflix e molti altri servizi web, i sistemi di raccomandazione hanno avuto un impatto enorme nell’industria. Dal suggerire prodotti/servizi ad aumentare il valore delle aziende grazie alla monetizzazione basata su annunci online e all’abbinamento delle preferenze e della pertinenza dell’utente per spingerlo all’acquisto, i sistemi di raccomandazione sono diventati imprescindibili nelle nostre ricerche sul web.
In generale, si tratta di framework basati sulla matematica focalizzati sul suggerire prodotti/servizi agli utenti finali pertinenti ai loro bisogni e desideri. Per esempio, film da guardare, articoli da leggere, prodotti da acquistare, musica da ascoltare, o qualsiasi altra cosa a seconda del dominio. Esistono principalmente tre metodi per costruire un sistema di raccomandazione:
- Metodi content-based: definiscono un modello per gli utenti o per gli item con cui hanno interagito sulla base del set di feature degli item e raccomandano altri item simili agli utenti.
- Metodi di collaborative filtering: definiscono un modello per il punteggio di similarità tra utenti e item o tra utente e utente, usato per la raccomandazione degli item.
- Metodi ibridi: utilizzano sia metodi content-based sia collaborativi per ottenere un risultato migliore.
Prima preprocessiamo il dataset per il sistema di raccomandazione. Per prima cosa, controlla i valori mancanti:
# Reading Data Again
df = pd.read_csv("tvshow.csv")
df=df.iloc[:,1:]
#Finding Missing values in all columns
miss = pd.DataFrame(df.isnull().sum())
miss = miss.rename(columns={0:"miss_count"})
miss["miss_%"] = (miss.miss_count/len(df.ID))*100
miss
#Dropping values with missing % more than 50%
df.drop(['Rotten Tomatoes', 'Age'], axis = 1, inplace=True)
# Dropping Na's from the following columns
df.dropna(subset=['IMDb','Directors', 'Genres', 'Country', 'Language', 'Runtime'],inplace=True)
df.reset_index(inplace=True,drop=True)
# converting into object type
df.ID = df.ID.astype("object")
df.Year = df.Year.astype("object")
Costruirai due sistemi di raccomandazione basati sulla similarità coseno.
1. Usando solo le variabili numeriche
2. Usando sia variabili numeriche che categoriche
Uso delle sole colonne numeriche
Passo 1: seleziona le variabili numeriche
ndf = df.select_dtypes(include=['float64',"int64"])
Passo 2: scala le variabili numeriche con un Min-Max Scaler per ridurre complessità del modello e tempi di training
#importing minmax scaler
from sklearn import preprocessing
# Create MinMaxScaler Object
scaler = preprocessing.MinMaxScaler(feature_range=(0, 1))
# Create dataframe after transformation
ndfmx = pd.DataFrame((scaler.fit_transform(ndf)))
# assign column names
ndfmx.columns=ndf.columns
# Show initial 5 records
ndfmx.head()
Passo 3: calcola il punteggio di similarità usando la similarità coseno
Ora calcolerai il punteggio di similarità usando la similarità coseno.
# Import cosine similarity
from sklearn.metrics.pairwise import cosine_similarity
# Compute the cosine similarity
sig = cosine_similarity(ndfmx, ndfmx)
# Reverse mapping of indices and movie titles
indices = pd.Series(df.index, index=df['Title']).drop_duplicates()
indices.head()
Passo 4: scrivi una funzione per ottenere raccomandazioni basate sul punteggio di similarità
- La funzione accetta due argomenti: il titolo del film e la matrice dei punteggi di similarità. Cerca l’indice del titolo corrispondente nell’indice original_titles nella nostra serie di indici.
- Ottiene i punteggi di similarità a coppie di tutti i film.
- Ordina i punteggi di similarità in ordine decrescente e li converte in una lista.
- Ottiene i punteggi e gli indici dei 10 film migliori e restituisce i titoli dei 10 film principali dal nostro dataframe.
def give_rec(title, sig=sig):
# Get the index corresponding to original_title
idx = indices[title]
# Get the pairwise similarity scores
sig_scores = list(enumerate(sig[idx]))
# Sort the movies
sig_scores = sorted(sig_scores, key=lambda x: x[1], reverse=True)
# Scores of the 10 most similar movies
sig_scores = sig_scores[1:11]
# Movie indices
movie_indices = [i[0] for i in sig_scores]
# Top 10 most similar movies
return df['Title'].iloc[movie_indices]
# Execute get_rec() function for getting recommendation
give_rec("The Matrix",sig = sig)
Qui, i film consigliati non sono eccezionali. Il motivo di questo risultato modesto è che stai usando solo le valutazioni dei film, le durate e le variabili di piattaforma. Puoi migliorare usando altre informazioni come genere, registi e paese.
Uso di colonne numeriche e testuali
Dato che il sistema precedente funzionava ma le raccomandazioni non erano ottimali, proverai un nuovo approccio migliore per migliorare i risultati.
df.head()
Passo 1:
Userai le colonne testuali in un’unica colonna, poi utilizzerai un tokenizer e un TF-IDF Vectorizer per creare una matrice sparsa con il punteggio TF-IDF di tutte le parole. Poi selezionerai e scalerai le variabili numeriche e le aggiungerai alla matrice sparsa. Devi eseguire i seguenti passaggi per il preprocessing:
- Selezionare tutti i tipi di dato object e salvarli in una lista.
- Rimuovere le colonne ID e Title.
- Unire tutte le colonne di testo/object con virgole in un’unica colonna.
- Creare un tokenizer per rimuovere elementi indesiderati dai dati, come simboli e numeri.
- Convertire in TfidfVector a partire dal testo. Dopo di ciò eseguiremo il preprocessing delle colonne numeriche
- Selezionare le variabili numeriche in un DataFrame
- Scalare le variabili numeriche con un minmax scaler in range (0,1)
- Aggiungere le variabili numeriche nella matrice sparsa dei vettori TF-IDF usando la funzione hstack (hstack serve per aggiungere array orizzontali a una matrice sparsa).
#the function performs all the important preprocessing steps
def preprocess(df):
#combining all text columns
# Selecting all object data type and storing them in list
s = list(df.select_dtypes(include=['object']).columns)
# Removing ID and Title column
s.remove("Title")
s.remove("ID")
# Joining all text/object columns using commas into a single column
df['all_text']= df[s].apply(lambda x: ','.join(x.dropna().astype(str)),axis=1)
# Creating a tokenizer to remove unwanted elements from our data like symbols and numbers
token = RegexpTokenizer(r'[a-zA-Z]+')
# Converting TfidfVector from the text
cv = TfidfVectorizer(lowercase=True,stop_words='english',ngram_range = (1,1),tokenizer = token.tokenize)
text_counts= cv.fit_transform(df['all_text'])
# Aselecting numerical variables
ndf = df.select_dtypes(include=['float64',"int64"])
# Scaling Numerical variables
scaler = preprocessing.MinMaxScaler(feature_range=(0, 1))
# Applying scaler on our data and converting i into a data frame
ndfmx = pd.DataFrame((scaler.fit_transform(ndf)))
ndfmx.columns=ndf.columns
# Adding our adding numerical variables in the TF-IDF vector
IMDb = ndfmx.IMDb.values[:, None]
X_train_dtm = hstack((text_counts, IMDb))
Netflix = ndfmx.Netflix.values[:, None]
X_train_dtm = hstack((X_train_dtm, Netflix))
Hulu = ndfmx.Hulu.values[:, None]
X_train_dtm = hstack((X_train_dtm, Hulu))
Prime = ndfmx["Prime Video"].values[:, None]
X_train_dtm = hstack((X_train_dtm, Prime))
Disney = ndfmx["Disney+"].values[:, None]
X_train_dtm = hstack((X_train_dtm, Disney))
Runtime = ndfmx.Runtime.values[:, None]
X_train_dtm = hstack((X_train_dtm, Runtime))
return X_train_dtm
Passo 2: applicare la funzione ai nostri dati e creare una matrice sparsa
# Preprocessing data
mat =preprocess(df)
mat.shape
Passo 3: applicare nuovamente la similarità coseno per calcolare il punteggio di similarità
# using cosine similarity
from sklearn.metrics.pairwise import cosine_similarity
# Compute the sigmoid kernel
sig2 = cosine_similarity(mat, mat)
# Reverse mapping of indices and movie titles
indices = pd.Series(df.index, index=df['Title']).drop_duplicates()
Passo 4: ottenere una raccomandazione dal nostro sistema migliorato
give_rec("The Matrix",sig=sig2)
Questa volta il sistema di raccomandazione funziona molto meglio rispetto al precedente, il che dimostra che aggiungendo dati più pertinenti come il testo descrittivo, un sistema di raccomandazione content-based può migliorare in modo significativo.
Conclusione
Congratulazioni, sei arrivato alla fine di questo tutorial!
In questo tutorial hai eseguito un’analisi esplorativa del dataset dei film sulle piattaforme di streaming. Hai esplorato i valori mancanti, i grafici di distribuzione individuali e la distribuzione dei film su ciascuna piattaforma. Hai inoltre scoperto insight su genere, paese, lingua, valutazioni IMDB e durata dei film. Infine, hai visto come costruire un sistema di raccomandazione in Python.
Dai un’occhiata al tutorial di DataCamp Recommender Systems in Python.


