Projet de Science des Données pour la Prédiction des Notes des Films Rotten Tomatoes Deuxième Approche

'Deuxième approche pour prédire les notes des films Rotten Tomatoes dans un projet de science des données.'

Ce projet de science des données a été utilisé comme tâche à réaliser chez Meta (Facebook) dans le cadre du processus de recrutement. Dans cette tâche à réaliser, nous découvrirons comment Rotten Tomatoes effectue l’étiquetage en tant que “Pourri”, “Frais” ou “Certifié Frais”.

Lien vers ce projet de science des données : https://platform.stratascratch.com/data-projects/rotten-tomatoes-movies-rating-prediction

Pour ce faire, nous développerons deux approches différentes.

Tout au long de notre exploration, nous discuterons du prétraitement des données, des différents classificateurs et des améliorations potentielles visant à améliorer les performances de nos modèles.

À la fin de cet article, vous aurez acquis une compréhension de la façon dont l’apprentissage automatique peut être utilisé pour prédire le succès d’un film et comment cette connaissance peut être appliquée dans l’industrie du divertissement.

Mais avant d’approfondir, découvrons les données sur lesquelles nous allons travailler.

Deuxième approche : Prédire l’état d’un film en fonction du sentiment de la critique

Dans la deuxième approche, nous prévoyons de prédire le succès du film en évaluant le sentiment de ses critiques. Nous appliquerons spécifiquement une analyse de sentiment pour évaluer le sentiment global de la critique et classer le film comme “Frais” ou “Pourri” en fonction de ce sentiment.

Cependant, avant de commencer l’analyse de sentiment, nous devons d’abord préparer notre ensemble de données. Contrairement à la stratégie précédente, celle-ci consiste à traiter des données textuelles (critiques) plutôt que des variables numériques et catégorielles. Pour ce défi, nous continuerons à utiliser le modèle Random Forest. Examinons de plus près nos données avant de passer à l’étape suivante.

Tout d’abord, lisons les données.

Voici le code.

df_critics = pd.read_csv('rotten_tomatoes_critic_reviews_50k.csv')
df_critics.head()

Voici le résultat.

Très bien, commençons par le prétraitement des données.

Prétraitement des données

Dans cet ensemble de données, nous n’avons pas les noms des films et leurs statuts correspondants. Pour cet ensemble de données, nous avons les variables review_content et review_type.

C’est pourquoi nous fusionnerons cet ensemble de données avec notre précédent, sur rotten_tomatoes_link, et sélectionnerons les fonctionnalités nécessaires avec des crochets d’indexation comme suit.

Voici le code :

df_merged = df_critics.merge(df_movie, how='inner', on=['rotten_tomatoes_link'])
df_merged = df_merged[['rotten_tomatoes_link', 'movie_title', 'review_content', 'review_type', 'tomatometer_status']]
df_merged.head()

Voici le résultat.

Dans cette approche, nous utiliserons uniquement la colonne review_content comme fonction d’entrée et review_type comme étiquette de vérité terrain.

Pour nous assurer que les données sont exploitables, nous devons filtrer les valeurs manquantes dans la colonne review_content, car les critiques vides ne peuvent pas être utilisées dans l’analyse de sentiment.

df_merged = df_merged.dropna(subset=['review_content'])

Après avoir filtré les valeurs manquantes, nous visualiserons la distribution de review_type pour mieux comprendre la distribution des données.

# Plot distribution of the review
ax = df_merged.review_type.value_counts().plot(kind='bar', figsize=(12,9))
ax.bar_label(ax.containers[0])

Cette visualisation nous aidera à déterminer s’il existe des déséquilibres de classe dans les données et nous guidera dans le choix d’une métrique d’évaluation appropriée pour notre modèle.

Voici le code complet :

df_merged = df_merged.dropna(subset=['review_content'])
# Plot distribution of the review
ax = df_merged.review_type.value_counts().plot(kind='bar', figsize=(12,9))
ax.bar_label(ax.containers[0])

Voici la sortie.

Il semble que nous avons un problème de déséquilibre entre nos caractéristiques.

De plus, nous avons trop de points de données, ce qui pourrait diminuer notre vitesse.

Nous allons donc d’abord sélectionner 5000 entrées du jeu de données d’origine.

df_sub = df_merged[0:5000]

Ensuite, nous ferons le codage ordinal.

review_type = pd.DataFrame(df_sub.review_type.replace(['Rotten','Fresh'],[0,1]))

Enfin, nous créerons un dataframe qui contient les étiquettes codées avec le contenu de la critique en utilisant la méthode concat() en Python et nous afficherons les 5 premières lignes en utilisant la méthode head().

df_feature_critics = pd.concat([df_sub[['review_content']]
                        ,review_type], axis=1).dropna()
df_feature_critics.head()

Voici le code complet.

# Sélectionner seulement 5000 entrées du jeu de données d'origine
df_sub = df_merged[0:5000]

# Encoder l'étiquette
review_type = pd.DataFrame(df_sub.review_type.replace(['Rotten','Fresh'],[0,1]))

# Construire le dataframe final
df_feature_critics = pd.concat([df_sub[['review_content']]
                        ,review_type], axis=1).dropna()
df_feature_critics.head()

Voici la sortie.

Super, maintenant en tant que dernière étape de cette section, divisons notre jeu de données en jeu d’entraînement et jeu de test.

X_train, X_test, y_train, y_test = train_test_split( df_feature_critics['review_content'], df_feature_critics['review_type'], test_size=0.2, random_state=42)

Forêt aléatoire par défaut

Pour utiliser les critiques de texte dans notre DataFrame pour les méthodes d’apprentissage automatique, nous devons les transformer en un format pouvant être traité. En traitement du langage naturel, cela s’appelle la tokenisation, où nous traduisons le texte ou les mots en vecteurs n-dimensionnels, puis utilisons ces représentations vectorielles comme données d’entraînement pour notre algorithme d’apprentissage automatique.

Pour ce faire, nous allons utiliser la classe CountVectorizer de scikit-learn pour transformer les critiques de texte en une matrice de comptage de tokens. Nous commençons par créer un dictionnaire de termes uniques à partir du texte d’entrée.

Par exemple, sur la base des deux critiques “Ce film est bon” et “Le film est mauvais”, l’algorithme créerait un dictionnaire de phrases uniques telles que ;

Ensuite, en fonction du texte d’entrée, nous calculons le nombre d’occurrences de chaque mot dans le dictionnaire.

[“ce”, “film”, “est”, “un”, “bon”, “le”, “mauvais”].

Par exemple, l’entrée “Ce film est un bon film” donnerait un vecteur de [1, 2, 1, 1, 1, 0, 0]

Enfin, nous introduisons le vecteur généré dans notre modèle de forêt aléatoire.

Nous pouvons prédire le sentiment des critiques et classer le film comme “Fresh” ou “Rotten” en formant notre classifieur de forêt aléatoire sur les données de texte vectorisées.

Le code suivant instancie une classe CountVectorizer qui transforme les données textuelles en vecteurs numériques, et spécifie qu’un mot doit apparaître dans au moins un document pour être inclus dans le vocabulaire.

# Instancier la classe vectorizer
vectorizer = CountVectorizer(min_df=1)

Ensuite, nous allons transformer les données d’entraînement en vecteurs en utilisant l’objet CountVectorizer instancié.

# Transformer nos données textuelles en vecteurs
X_train_vec = vectorizer.fit_transform(X_train).toarray()

Ensuite, nous instancions un objet RandomForestClassifier avec un état aléatoire spécifié et ajustons le modèle de forêt aléatoire en utilisant les données d’entraînement.

# Initialiser la forêt aléatoire et l'entraîner
rf = RandomForestClassifier(random_state=2)
rf.fit(X_train_vec, y_train)

Il est maintenant temps de prédire en utilisant le modèle entraîné et les données de test transformées.

Ensuite, nous imprimerons le rapport de classification qui contient des métriques d’évaluation telles que la précision, le rappel et le score F1.

# Prédire et afficher le rapport de classification
y_predicted = rf.predict(vectorizer.transform(X_test).toarray())

print(classification_report(y_test, y_predicted))

Enfin, créons une nouvelle figure avec une taille spécifiée pour le tracé de la matrice de confusion et affichons la matrice de confusion.

fig, ax = plt.subplots(figsize=(12, 9))
plot_confusion_matrix(rf, vectorizer.transform(X_test).toarray(), y_test, cmap ='cividis', ax=ax

Voici le code complet.

# Instancier la classe vectorizer
vectorizer = CountVectorizer(min_df=1)

# Transformer nos données textuelles en vecteur
X_train_vec = vectorizer.fit_transform(X_train).toarray()

# Initialiser le random forest et l'entraîner
rf = RandomForestClassifier(random_state=2)
rf.fit(X_train_vec, y_train)

# Prédire et afficher le rapport de classification
y_predicted = rf.predict(vectorizer.transform(X_test).toarray())

print(classification_report(y_test, y_predicted))

fig, ax = plt.subplots(figsize=(12, 9))
plot_confusion_matrix(rf, vectorizer.transform(X_test).toarray(), y_test, cmap ='cividis', ax=ax

Voici le résultat.

Random Forest Pondérée

Comme nous pouvons le voir sur notre dernière matrice de confusion, les performances de notre modèle ne sont pas suffisamment bonnes.

Cependant, cela peut être attendu en raison du nombre limité de points de données (5000 au lieu de 100000).

Voyons si nous pouvons améliorer les performances en résolvant le problème de déséquilibre avec des poids de classe.

Voici le code.

class_weight = compute_class_weight(class_weight= 'balanced', classes= np.unique(df_feature_critics.review_type), 
                      y = df_feature_critics.review_type.values)

class_weight_dict = dict(zip(range(len(class_weight.tolist())), class_weight.tolist()))
class_weight_dict

Voici le résultat.

Nous entraînons maintenant notre classifieur Random Forest sur l’entrée textuelle vectorisée, mais cette fois en incluant les informations sur le poids de classe pour augmenter les métriques d’évaluation.

Nous créons d’abord la classe CountVectorizer et, comme précédemment, transformons notre entrée textuelle en vecteurs.

Et transformons nos données textuelles en vecteur.

vectorizer = CountVectorizer(min_df=1)
X_train_vec = vectorizer.fit_transform(X_train).toarray()

Ensuite, nous définirons un random forest avec le poids de classe calculé et l’entraînerons.

# Initialiser le random forest et l'entraîner
rf_weighted = RandomForestClassifier(random_state=2, class_weight=class_weight_dict)
rf_weighted.fit(X_train_vec, y_train)

Il est maintenant temps de faire une prédiction en utilisant les données de test et d’afficher le rapport de classification.

# Prédire et afficher le rapport de classification
y_predicted = rf_weighted.predict(vectorizer.transform(X_test).toarray())

print(classification_report(y_test, y_predicted))

À la dernière étape, nous définissons la taille de la figure et affichons la matrice de confusion.

fig, ax = plt.subplots(figsize=(12, 9))
plot_confusion_matrix(rf_weighted, vectorizer.transform(X_test).toarray(), y_test, cmap ='cividis', ax=ax)

Voici le code complet.

# Instancier la classe vectorizer
vectorizer = CountVectorizer(min_df=1)

# Transformer nos données textuelles en vecteur
X_train_vec = vectorizer.fit_transform(X_train).toarray()

# Initialiser le random forest et l'entraîner
rf_weighted = RandomForestClassifier(random_state=2, class_weight=class_weight_dict)
rf_weighted.fit(X_train_vec, y_train)

# Prédire et afficher le rapport de classification
y_predicted = rf_weighted.predict(vectorizer.transform(X_test).toarray())

print(classification_report(y_test, y_predicted))

fig, ax = plt.subplots(figsize=(12, 9))
plot_confusion_matrix(rf_weighted, vectorizer.transform(X_test).toarray(), y_test, cmap ='cividis', ax=ax)

Voici le résultat.

Maintenant, la précision de notre modèle est légèrement meilleure que celle sans les poids de classe.

De plus, parce que le poids de la classe 0 (‘Pourri’) est plus élevé que le poids de la classe 1 (‘Frais’), le modèle fonctionne maintenant mieux pour prédire les critiques de films ‘Pourris’ mais moins bien pour prédire les critiques de films ‘Frais’.

Cela est dû au fait que le modèle accorde plus d’attention aux données classées comme ‘Pourries’.

Prédiction de l’état du film

Utilisons maintenant notre modèle Random Forest pour prédire l’état d’un film maintenant que nous l’avons entraîné à prédire le sentiment d’une critique de film. Nous allons suivre les étapes suivantes pour déterminer l’état d’un film :

  • Collecter toutes les critiques d’un certain film.
  • Utiliser notre modèle Random Forest pour estimer l’état de chaque critique (par exemple, ‘Frais’ ou ‘Pourri’).
  • Pour classer l’état final d’un film en fonction de l’état total des critiques, utiliser l’approche basée sur des règles donnée sur le site de Rotten Tomatoes.

Ici, dans le code suivant, nous créons d’abord une fonction nommée predict_movie_statust, qui prend une prédiction comme argument.

Ensuite, en fonction de la valeur positive_percentage, nous identifions l’état du film, en attribuant soit ‘Frais’ soit ‘Pourri’ à la variable prédiction.

Enfin, il affichera le pourcentage de critiques positives avec l’état du film.

Voici le code.

def predict_movie_status(prediction):
    """Attribue une étiquette (Frais/Pourri) en fonction de la prédiction"""
    positive_percentage = (prediction == 1).sum()/len(prediction)*100
    
    prediction = 'Frais' if positive_percentage >= 60 else 'Pourri'
    
    print(f'Critique positive : {positive_percentage:.2f}%')
    print(f'État du film : {prediction}')

Dans cet exemple, nous allons prédire l’état de trois films : Body of Lies, Angel Heart et The Duchess. Commençons par Body of Lies.

Prédiction de ‘Body of Lies’

Maintenant, comme indiqué ci-dessus, commençons par collecter toutes les critiques du film Body of Lies.

Voici le code.

# Rassembler toutes les critiques du film Body of Lies
df_bol = df_merged.loc[df_merged['movie_title'] == 'Body of Lies']

df_bol.head()

Voici le résultat.

Super, à ce stade, appliquons un algorithme de forêt aléatoire pondéré pour prédire l’état. Ensuite, utilisons cela dans la fonction personnalisée que nous avons définie précédemment, qui prend une prédiction en argument.

Voici le code.

y_predicted_bol = rf_weighted.predict(vectorizer.transform(df_bol['review_content']).toarray())
predict_movie_status(y_predicted_bol)

Voici le résultat.

Et voici notre résultat, vérifions si notre résultat est valide ou non en le comparant à l’état ground_truth.

Voici le code.

df_merged['tomatometer_status'].loc[df_merged['movie_title'] == 'Body of Lies'].unique()

Voici le résultat.

Il semble que notre prédiction soit assez valide car l’état de ce film est Pourri, comme nous l’avions prédit.

Prédiction de ‘Angel Heart’

Ici, nous allons répéter toutes les étapes.

  • Rassembler toutes les critiques
  • Faire une prédiction
  • Comparer

Commençons d’abord par rassembler toutes les critiques du film Anna Karenina.

Voici le code.

df_ah = df_merged.loc[df_merged['movie_title'] == 'Angel Heart']
df_ah.head()

Voici le résultat.

Maintenant, il est temps de faire une prédiction en utilisant la forêt aléatoire et notre fonction personnalisée.

Voici le code.

y_predicted_ah = rf_weighted.predict(vectorizer.transform(df_ah['review_content']).toarray())
predict_movie_status(y_predicted_ah)

Voici le résultat.

Faisons maintenant une comparaison.

Voici le code.

df_merged['tomatometer_status'].loc[df_merged['movie_title'] == 'Angel Heart'].unique()

Voici le résultat.

Notre modèle prédit correctement à nouveau.

Essayons maintenant une fois de plus.

Prédiction de ‘The Duchess’

Tout d’abord, collectons toutes les critiques.

Voici le code.

df_duchess = df_merged.loc[df_merged['movie_title'] == 'The Duchess']
df_duchess.head()

Voici le résultat.

Il est maintenant temps de faire une prédiction.

Voici le code.

y_predicted_duchess = rf_weighted.predict(vectorizer.transform(df_duchess['review_content']).toarray())
predict_movie_status(y_predicted_duchess)

Voici le résultat.

Comparons notre prédiction avec la vérité.

Voici le code.

df_merged['tomatometer_status'].loc[df_merged['movie_title'] == 'The Duchess'].unique()

Voici le résultat.

Et l’étiquette réelle du film est ‘Fresh’, ce qui indique que la prévision de notre modèle est incorrecte.

Cependant, il est possible de remarquer que la prédiction de notre modèle est très proche du seuil de 60%, ce qui indique qu’une légère modification du modèle pourrait changer sa prédiction de ‘Rotten’ à ‘Fresh’.

Évidemment, le modèle de forêt aléatoire que nous avons entraîné n’est pas le meilleur modèle, car il y a encore un potentiel d’amélioration. Dans la partie suivante, nous donnerons de nombreuses suggestions pour améliorer les performances de notre modèle.

Suggestions pour l’amélioration des performances

  1. Augmentez la quantité de données dont vous disposez.
  2. Définissez différents hyperparamètres du modèle de forêt aléatoire.
  3. Appliquez différents modèles d’apprentissage automatique pour trouver le meilleur.
  4. Ajustez la méthode utilisée pour représenter les données textuelles.

Conclusion

Dans cet article, nous avons exploré deux approches différentes pour prédire le statut d’un film en fonction de caractéristiques numériques et catégorielles.

Nous avons d’abord effectué un prétraitement des données, puis appliqué un classifieur d’arbres de décision et un classifieur de forêt aléatoire pour entraîner notre modèle.

Nous avons également expérimenté la sélection de fonctionnalités et un classifieur de forêt aléatoire pondéré.

Dans la deuxième approche, nous avons utilisé la forêt aléatoire par défaut et la forêt aléatoire pondérée pour prédire le statut de trois films différents.

Nous avons donné des suggestions pour améliorer les performances de nos modèles. Nous espérons que cet article a été informatif et utile.

Si vous recherchez des projets de niveau débutant, consultez notre article “Idées de projets en science des données pour les débutants”. Nate Rosidi est un data scientist travaillant dans la stratégie de produit. Il est également professeur adjoint d’analyse et fondateur de StrataScratch, une plateforme aidant les data scientists à se préparer à leurs entretiens avec de vraies questions d’entretien de grandes entreprises. Connectez-vous avec lui sur Twitter: StrataScratch ou LinkedIn.

We will continue to update IPGirl; if you have any questions or suggestions, please contact us!

Share:

Was this article helpful?

93 out of 132 found this helpful

Discover more

AI

Cette recherche en apprentissage automatique de DeepMind introduit des modèles vectoriels quantifiés (VQ) pour une planification avancée dans des environnements dynamiques

Avec les avancées constantes de la technologie, l’intelligence artificielle permet aux ordinateurs de penser et...

AI

Pourquoi les machines peuvent-elles penser

Au 17e siècle, René Descartes a introduit une idée relativement nouvelle - le dictum cogito ergo sum (Je pense donc j...

AI

Bots, Ferme de Fraude Responsable de 73% du Trafic Web

Arkose Labs a signalé que les attaques malveillantes par des bots et des fermes de fraude humaine représentaient 73% ...

AI

Cette recherche en intelligence artificielle présente une nouvelle approche de la reconnaissance d'objet de pose en tant que prédiction du prochain jeton.

Comment pouvons-nous aborder efficacement la reconnaissance d’objets ? Une équipe de chercheurs de Meta AI et d...