Accéder au contenu principal

Tutoriel : système de recommandation pour les plateformes de streaming

Dans ce tutoriel Python, explorez des données de films issues de plateformes de streaming populaires et créez un système de recommandation.
Actualisé 19 sept. 2026  · 10 min lire

Explorer avec l’IA

ChatGPTClaudePerplexity

Avec la généralisation du binge-watching de séries et de films, les utilisateurs consomment du contenu à un rythme soutenu grâce aux services disponibles comme Netflix, Prime Video, Hulu et Disney+. Certaines plateformes récentes, telles que Hulu et YouTube TV, proposent aussi des retransmissions en direct d’événements comme le sport, des concerts/tournées ou des chaînes d’info. Le direct n’est toutefois pas encore adopté par toutes les plateformes, comme Netflix.

Les plateformes de streaming offrent davantage de flexibilité : regarder ses séries et films préférés, à tout moment, sur n’importe quel appareil. Grâce à la variété de contenus proposés, elles séduisent particulièrement un public jeune et connecté. Elles permettent aussi de rattraper un programme manqué, selon ses disponibilités. Dans ce tutoriel, vous allez analyser les données de films disponibles sur Netflix, Prime Video, Hulu et Disney+ et tenter de mieux comprendre leurs audiences.

career-building python skills with data camp banner

Comprendre le jeu de données

Ce jeu de données ne contient que des films disponibles sur des plateformes de streaming comme Netflix, Prime Video, Hulu et Disney+. Vous pouvez le télécharger sur Kaggle ici.

Voici une description détaillée des attributs :

  • ID : identifiant unique de chaque enregistrement
  • Title : titre du film
  • Year : année de sortie
  • Age : tranche d’âge ciblée
  • IMDb : note IMDb des films
  • Rotten Tomatoes : pourcentage Rotten Tomatoes
  • Netflix : indique si le film est disponible sur Netflix
  • Hulu : indique si le film est disponible sur Hulu
  • Prime Video : indique si le film est disponible sur Prime Video
  • Disney+ : indique si le film est disponible sur Disney+
  • Type : film ou série
  • Directors : nom du ou des réalisateurs
  • Genres : genre(s)
  • Country : pays d’origine
  • Language : langue d’origine
  • Runtime : durée du film

Importons les modules nécessaires et chargeons le jeu de données :

 # 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])

Gérer les valeurs manquantes

Dans cette section, vous allez traiter les valeurs manquantes avec la fonction isnull(). Voici un exemple :

 #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

On constate que les variables Age et Rotten Tomatoes présentent plus de 50 % de valeurs manquantes, ce qui est problématique.

Nous allons maintenant traiter les valeurs manquantes en suivant ces étapes :

  • Supprimer les colonnes avec plus de 50 % de valeurs manquantes
  • Supprimer les NA dans les colonnes IMDb, Directors, Genres, Country, Language et Runtime
  • Réinitialiser l’index
  • Convertir la colonne Year en type objet
# 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

Graphiques de distribution

Vous pouvez examiner la distribution de la colonne Year avec la fonction distplot() de seaborn. Traçons la distribution des années de sortie.

#checking Distribution of years
plt.figure(figsize=(20,5))
sns.distplot(df['Year'])
plt.show()
movie year distribution plot

Ce graphique montre la distribution des années d’origine des films. On peut en déduire que la majorité a été produite entre 2000 et 2020. Traçons maintenant la distribution des notes IMDb.

# Distribution of IMDb Rating
plt.figure(figsize=(20,5))
sns.distplot(df['IMDb'])
plt.show()
imdb rating distribution plot

La distribution ci-dessus est légèrement asymétrique. On observe que la note IMDb moyenne de la plupart des films tourne autour de 6,5.

Traçons enfin la distribution des durées (Runtime).

# Distribution of runtime
sns.distplot(df['Runtime'])
plt.show()
movie Runtime distribution plot

D’après ce graphique, la durée moyenne des films se situe entre 80 et 120 minutes.

Répartition des films par plateforme de streaming

Dans cette section, vous allez visualiser la répartition des films par plateforme. Commencez par créer une fonction m_cnt() qui compte les films pour une plateforme donnée. Ensuite, affichez un camembert pour comparer les parts de chaque plateforme.

# 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()
streaming platforms

Ce graphique montre que Prime Video héberge le plus grand nombre de titres, avec 71 % de part, et Netflix environ 20 %. Disney+ et Hulu ferment la marche, avec respectivement 5,4 % et 3,4 % des titres.

Répartition des films par genre

Ici, vous allez visualiser la répartition par genre. Il faut d’abord préparer les données : gérer les multiples genres listés dans une même cellule du DataFrame. Pour cela, utilisez les fonctions split(), apply() et stack(). split() sépare les valeurs par virgule et crée une liste, apply(pd.Series,1) crée plusieurs colonnes (une par genre) et stack() les empile dans une seule colonne.

Après ces étapes, une nouvelle colonne Genres est jointe au DataFrame, et vous pouvez tracer les graphiques. Affichez les 10 genres principaux avec leur nombre de films via value_counts(), puis utilisez la méthode plot() de 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()
movie genres

On observe que les genres les plus fréquents sont le drame et la comédie.

Répartition des films par pays

Dans cette section, vous allez visualiser la répartition par pays. Là encore, il faut gérer les multiples pays mentionnés dans une seule cellule. Utilisez split(), apply() et stack(). La fonction split() sépare les valeurs par des virgules, apply(pd.Series,1) crée une colonne par pays et stack() empile le tout dans une seule colonne.

Après ces opérations, une nouvelle colonne Country est jointe au DataFrame et vous pouvez tracer le graphique. Affichez le top 10 des pays par nombre de films avec value_counts() et la méthode plot() de 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()
countries movies were made

La majorité des films ont été produits aux États‑Unis.

Répartition des films par langue

Dans cette section, vous allez visualiser la répartition par langue. Comme précédemment, il faut gérer les langues multiples présentes dans une même cellule du DataFrame. Utilisez split(), apply() et stack(). La fonction split() sépare les valeurs par des virgules, apply(pd.Series,1) crée une colonne par langue et stack() les regroupe dans une seule colonne.

Après ces étapes, une nouvelle colonne Language est jointe au DataFrame. Vous pouvez afficher le top 10 des langues avec leur nombre de films via value_counts() et la méthode plot() de 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()
movie languages plot

On en conclut que la majorité des films sont en anglais.

Distribution des notes IMDb selon chaque plateforme

Dans cette section, vous allez tracer la distribution des notes IMDb par plateforme. Pour obtenir ces résultats, appliquez la fonction melt() puis utilisez un FacetGrid. melt() convertit un DataFrame large en format long. Exemple :

 # 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()
IMDB rating Distribution According to each Platform

On visualise ici la distribution moyenne des notes IMDb sur chaque plateforme.

explore datacamp's python course library banner

Durée totale par plateforme et par tranche d’âge

Dans la section « Gérer les valeurs manquantes », nous avons supprimé la colonne Age. Pour analyser la durée totale par plateforme et par tranche d’âge, rechargeons les données et appliquons 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)

Après avoir rechargé le jeu de données et effectué le melt, générons un graphique croisant la durée et la plateforme selon les tranches d’âge.

# Total of runtime in different platform
ax = sns.barplot(x="platform", y="Runtime",hue="Age", estimator=sum, data=df2)
Runtime Per Platform Along with Age Group

On voit que la durée totale sur Prime Video pour les utilisateurs 18+ dépasse largement celle des autres plateformes. On peut en déduire que l’essentiel du contenu de Prime Video cible la tranche 18+.

Construire un système de recommandation

Ces dernières années, avec l’essor de YouTube, Walmart, Netflix et d’autres services web, les systèmes de recommandation ont eu un impact considérable. Ils vont du conseil de produits/services à la monétisation publicitaire, en passant par la mise en correspondance des préférences des utilisateurs pour favoriser l’achat. Les systèmes de recommandation sont devenus incontournables dans nos usages en ligne.

Il s’agit généralement d’approches fondées sur les mathématiques, visant à proposer aux utilisateurs finaux des produits/services pertinents selon leurs besoins et envies : films à regarder, articles à lire, produits à acheter, musique à écouter, etc. On distingue trois grandes familles pour construire un système de recommandation :

  1. Méthodes basées sur le contenu : modéliser les utilisateurs ou les éléments avec lesquels ils ont interagi à partir des caractéristiques des éléments, puis recommander des éléments similaires.
  2. Filtrage collaboratif : modéliser les similarités d’interactions entre utilisateurs et éléments, ou entre utilisateurs eux‑mêmes, pour recommander des éléments.
  3. Approches hybrides : combiner contenu et collaboratif pour de meilleurs résultats.

Commençons par prétraiter le jeu de données pour le système de recommandation. D’abord, vérifions les valeurs manquantes :

# 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")

Vous allez construire deux systèmes de recommandation basés sur la similarité cosinus.

1. En utilisant uniquement les variables numériques
2. En combinant variables numériques et catégorielles

Utiliser uniquement les colonnes numériques

Étape 1 : sélectionner les variables numériques

ndf = df.select_dtypes(include=['float64',"int64"])

Étape 2 : appliquer un min‑max scaler aux variables numériques pour réduire la complexité et le temps d’entraînement

#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()

Étape 3 : calculer le score de similarité avec la similarité cosinus

Calculons maintenant la similarité cosinus.

# 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()

Étape 4 : écrire une fonction qui retourne des recommandations selon le score de similarité

  • La fonction prend deux arguments : le titre du film et la matrice de similarité. Elle recherche l’index du titre dans la série indices.
  • Récupérer les similarités par paire pour tous les films.
  • Trier ces scores par ordre décroissant et les convertir en liste.
  • Récupérer les 10 meilleurs scores/indices et retourner les titres correspondants.
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)

Ici, les recommandations ne sont pas très satisfaisantes. La raison : nous n’utilisons que les notes, les durées et des variables de plateforme. On peut améliorer en intégrant d’autres informations, comme les genres, les réalisateurs et les pays.

Combiner colonnes numériques et textuelles

Le premier système fonctionne, mais la qualité des résultats reste perfectible. Essayons une approche plus riche pour améliorer les recommandations.

df.head()

Étape 1 :

Regroupez les colonnes textuelles en une seule, puis utilisez un tokenizer et un TF‑IDF Vectorizer pour créer une matrice creuse des scores TF‑IDF. Ensuite, sélectionnez et mettez à l’échelle les variables numériques, puis ajoutez-les à la matrice creuse. Étapes de prétraitement :

  • Sélectionner toutes les colonnes de type objet et les stocker dans une liste
  • Retirer les colonnes ID et Title
  • Concaténer toutes les colonnes texte/objet en une seule colonne séparée par des virgules
  • Créer un tokenizer pour retirer les éléments indésirables (symboles, chiffres)
  • Convertir le texte en vecteurs TF‑IDF, puis prétraiter les colonnes numériques
  • Sélectionner les variables numériques dans un DataFrame
  • Appliquer un min‑max scaler (0,1) aux variables numériques
  • Ajouter les variables numériques à la matrice TF‑IDF au moyen de hstack (concaténation horizontale de matrices creuses)
#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

Étape 2 : appliquer la fonction et créer la matrice creuse

# Preprocessing data
mat =preprocess(df)
mat.shape

Étape 3 : recalculer la similarité cosinus

# 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()

Étape 4 : obtenir des recommandations avec notre système amélioré

give_rec("The Matrix",sig=sig2)

Cette fois, le système fournit des recommandations nettement meilleures, ce qui montre qu’en ajoutant des données plus pertinentes (comme du texte descriptif), un système de recommandation basé sur le contenu peut être considérablement amélioré.

Conclusion

Félicitations, vous êtes arrivé au bout de ce tutoriel !

Vous avez mené une analyse exploratoire d’un jeu de données de films issus de plateformes de streaming. Vous avez exploré les valeurs manquantes, les distributions individuelles et la répartition des films par plateforme. Vous avez aussi dégagé des insights par genre, pays, langue, notes IMDb et durée des films. Enfin, vous avez vu comment construire un système de recommandation en Python.

Consultez le tutoriel de DataCamp : Recommender Systems in Python.

datacamp's python course library banner
Sujets
Python
Science des données
Analyse des données

En savoir plus sur Python

Cours

Créer des moteurs de recommandation en Python

4 h
12.9K
Apprenez à développer des moteurs de recommandation en Python à l'aide de techniques de machine learning.
Afficher les détailsRight Arrow
Commencer Le Cours
Voir plusRight Arrow