PickFlix — Repenser la recommandation cinématographique en milieu rural grâce à la data

📌 Contexte & Problématique

Dans le cadre de ma formation en Data Analyse, j’ai réalisé un projet intitulé PickFlix, dans lequel je me suis glissé dans la peau d’un Data Analyst freelance. Ma mission : aider un cinéma local de la Creuse, en perte de vitesse, à faire un virage digital.

Le client voulait offrir un outil en ligne de recommandation de films personnalisé à ses spectateurs, en parallèle de son site Internet. L’enjeu ? Créer un moteur de recommandations intelligent, sans disposer au départ d’aucune préférence client (situation de cold start).


🗺️ Étape 1 – Étude de marché (Semaine 1 & 2)

Avant de plonger dans les bases de données, il était essentiel de comprendre le public local :

📊 Analyse démographique de la région Creuse (via les données INSEE)

🎟️ Recherche sur la consommation cinématographique en milieu rural (CNC)

🧠 Identification des préférences cinématographiques locales et nationales

📚 Synthèse des données et présentation des conclusions

👉 Cette première phase a permis d’identifier des genres de films préférés, de dégager les habitudes de consommation, et de guider la suite de l’analyse.


🧹 Étape 2 – Appropriation et traitement des données (Semaine 3)

Le client nous a fourni un jeu de données massif basé sur IMDb et complété par TMDB, ce qui représentait plusieurs millions de lignes.

Les étapes techniques :

🔍 Exploration initiale des datasets IMDb

🧼 Nettoyage et filtrage des données : suppression des doublons, valeurs manquantes, typage

🔗 Jointures entre les tables (films, acteurs, réalisateurs)

📦 Export de jeux de données allégés pour traitement futur

Cette phase a été l’occasion de consolider ma maîtrise de Pandas et de travailler avec des fichiers volumineux au format TSV.



📊 Étape 3 – Analyse exploratoire & visualisations (Semaine 4)

Objectif : dégager des tendances pour alimenter le système de recommandation.

J’ai notamment réalisé des analyses sur :

🧑‍🎬 Les acteurs les plus présents et leurs périodes d'activité

📈 L’évolution de la durée moyenne des films

👵 L’âge moyen des acteurs par genre

🌟 Les films les mieux notés et les caractéristiques partagées

Le tout a été synthétisé dans des visualisations interactives pour un futur dashboard. Cette phase m’a permis de poser des hypothèses sur les préférences du public rural.


🧠 Étape 4 – Machine Learning et recommandations (Semaines 5 & 6)

Cœur du projet : créer un système de recommandation basé sur le contenu à partir de films appréciés.

📂 Préparation des données d'entraînement

🧪 Test d’un premier modèle avec Scikit-Learn (KNN)

🔄 Intégration de la récupération des posters de films via TMDB

🤝 Ajout d’un second modèle : filtrage collaboratif simplifié

🛠️ Optimisation et validation finale du système

👉 Le modèle renvoie désormais une liste de films similaires à un titre saisi par l’utilisateur.

    #----------------------------------------------------------------------------------------------------------------------------------------------- #
    #                                                               Machine learning                                                                 #
    #----------------------------------------------------------------------------------------------------------------------------------------------- #


    # Import du dataset utilisé pour le ML
    @st.cache_data
    def chargement(): 
        df1 = pd.read_csv('Datasets-and-cleaning/dataset_final_splitted.csv')
        df_ml = df1.drop(columns = ['Unnamed: 0.1', 'Unnamed: 0']).copy()
        return df_ml
    df_ml = chargement()

    # Application du Lemmatizer
    @st.cache_data
    def clean_text(text: str) -> str:
        nlp = load_spacy_model()
        # Chargement des stopwords
        stop_words = set(stopwords.words('english'))
        # 1. Conversion en minuscules
        text = text.lower()
        # 2. Suppression des balises HTML
        text = re.sub(r'<.*?>', '', text)
        # 3. Suppression des caractères spéciaux (garde lettres, chiffres et espaces)
        text = re.sub(r'[^a-zA-Z0-9\s]', '', text)
        # 4. Suppression des stopwords
        text = ' '.join([word for word in text.split() if word not in stop_words])
        # 5. Lemmatization avec spaCy
        doc = nlp(text)
        text = ' '.join([token.lemma_ for token in doc])
        # 6. Nettoyage final des espaces multiples
        text = ' '.join(text.split())
        return text

    @st.cache_data
    def clean_dataframe_column(df_ml, column_name: str, language: str = 'english'):
        # Appliquer le nettoyage sur la colonne spécifiée
        df_ml[f'clean_{column_name}'] = df_ml[column_name].apply(clean_text)
        return df_ml
    
    # Intégration dans le DF
    with st.spinner("Nettoyage des titres..."):
        df_ml = clean_dataframe_column(df_ml, 'overview')

    # Sélection des features
    X = df_ml[['release_year', 'runtimeMinutes', 'vote_average', 'vote_count', 'genre_1', 'nationality_1', 'title', 'actor_1', 'clean_overview']]

    # Standardisation des données
    # ----> Définition des colonnes selon si elles sont numériques ou catégorielles
    col_num = ['release_year', 'runtimeMinutes', 'vote_average', 'vote_count']
    col_cat = ['genre_1', 'nationality_1', 'actor_1']
    col_text = ['clean_overview']

    # ----> Définition des tranformations à apporter sur les colonnes selon leurs valeurs
    transfo_num = Pipeline(steps=[('scaler', StandardScaler()),
                                    ])

    transfo_cat = Pipeline(steps=[('imputation', SimpleImputer(strategy='constant', fill_value='manquant')),
                                    ('onehot', OneHotEncoder(handle_unknown='ignore'))])

    transfo_text = Pipeline(steps=[('flatten', FunctionTransformer(lambda x: x.iloc[:,0], validate=False)),
                                    ('Count vectorizer', TfidfVectorizer())])

    # ----> Définition du process de transformation
    preprocessor = ColumnTransformer([('num', transfo_num, col_num),
                                    ('cat', transfo_cat, col_cat),
                                    ('text', transfo_text, col_text)])

    # Construction du pipeline global avec préprocessing et régression
    model_pipeline = Pipeline(steps=[
        ('preprocessor', preprocessor),  # Transformation des données
        ('neighbor', NearestNeighbors(n_neighbors=6, metric='euclidean', algorithm='auto'))])  # Modèle de régression pour imputation

    # Entraînement du modèle
    model_pipeline.fit(X)

    # Choix d'un film de référence
    movie_ref = X[X['title'] == selected_film['title']]  # double crochet pour garder un DataFrame

    # transformer les données pour qu'elles soient standardisées
    X_transformed = model_pipeline.named_steps['preprocessor'].transform(X)
    movie_transformed = model_pipeline.named_steps['preprocessor'].transform(movie_ref)

    # trouver les 5 films voisins
    distances, indices = model_pipeline.named_steps['neighbor'].kneighbors(movie_transformed)


💻 Étape 5 – Interface utilisateur & dashboard final (Semaine 7)

Pour que le client puisse tester la solution, j’ai développé une application interactive sous Streamlit :

📈 Un tableau de bord présentant les KPIs clés sur les films et les acteurs

🔍 Un moteur de recherche permettant de taper un film et d’obtenir des recommandations

🖼️ Affichage des posters des films recommandés

🔁 Un bouton “Accueil” pour revenir à l’état initial

🎯 Cette interface simple et responsive peut être intégrée ou liée au site du cinéma.

🔗 Lien vers l’application finale : https://pickflix.streamlit.app



🧠 Ce que j’ai appris

Gérer des datasets massifs (90M+ lignes) de manière efficace

Maîtriser les jointures complexes entre tables relationnelles

Implémenter un système de recommandation en situation de cold start

Créer un dashboard interactif et orienté utilisateur

Adapter mon approche aux besoins d’un client réel


🔮 Pistes d'amélioration

Intégrer les préférences utilisateur une fois collectées (filtrage collaboratif plus robuste)

Ajouter des critères personnalisés (budget, pays, langue)

Optimiser les performances de l’interface

Déployer l’application sur un hébergeur pour usage réel


🧰 Stack technique utilisée

Python, Pandas, Matplotlib, Seaborn

Scikit-Learn (KNN), NLP pour le contenu

Streamlit pour l’interface

IMDb & TMDB datasets (TSV & CSV)


💬 Conclusion

Ce projet m’a permis de lier data analyse, machine learning, et UX pour répondre à un besoin concret. À travers PickFlix, j’ai pu allier technique et sens produit pour proposer une solution digitale innovante à un acteur local du cinéma.