import streamlit as st import pandas as pd import numpy as np import plotly.express as px import plotly.graph_objects as go from datetime import datetime import re # Configuration de la page st.set_page_config( page_title="Analyse des tendances YouTube 2025", page_icon="📊", layout="wide" ) # Fonction pour charger les données @st.cache_data def load_data(): # Chargement des données df = pd.read_csv('tendances_2025_final.csv') categories = pd.read_csv('category.csv', sep=';') # Conversion des types de données numeric_cols = ['view_count', 'likes', 'dislikes', 'comment_count'] for col in numeric_cols: df[col] = pd.to_numeric(df[col], errors='coerce') # Extraction de la date de trending correctement formatée # Le format semble être YY.DD.MM df['trending_date_formatted'] = pd.to_datetime(df['trending_date'].apply( lambda x: '20' + x.split('.')[0] + '-' + x.split('.')[2] + '-' + x.split('.')[1] ), errors='coerce') # Conversion de la date de publication df['publishedAt'] = pd.to_datetime(df['publishedAt'], errors='coerce') # Conversion de la durée en minutes def convert_duration(duration_str): if pd.isna(duration_str): return np.nan parts = duration_str.split(':') if len(parts) == 2: # MM:SS return int(parts[0]) + int(parts[1])/60 elif len(parts) == 3: # HH:MM:SS return int(parts[0])*60 + int(parts[1]) + int(parts[2])/60 return np.nan df['duration_minutes'] = df['duration'].apply(convert_duration) # Ajout des noms de catégories df = df.merge(categories, left_on='categoryId', right_on='ID', how='left') # Calcul des métriques supplémentaires df['likes_per_view'] = df['likes'] / df['view_count'] df['comments_per_view'] = df['comment_count'] / df['view_count'] return df # Fonction pour créer un histogramme def create_histogram(df, column, title, color='#1f77b4', nbins=20): fig = px.histogram(df, x=column, nbins=nbins, title=title) fig.update_layout(bargap=0.1) return fig # Fonction pour créer un graphique en barres def create_bar_chart(df, x_col, y_col, title, color='#1f77b4'): fig = px.bar(df, x=x_col, y=y_col, title=title, color_discrete_sequence=[color]) return fig # Fonction pour créer un nuage de points def create_scatter_plot(df, x_col, y_col, size_col, hover_data, title): fig = px.scatter(df, x=x_col, y=y_col, size=size_col, hover_data=hover_data, title=title) return fig # Fonction pour créer une carte de chaleur def create_heatmap(df, categories, metrics): # Création d'un DataFrame pivot avec les moyennes par catégorie heatmap_data = pd.DataFrame() for metric in metrics: for cat in categories: cat_data = df[df['Category name'] == cat] if not cat_data.empty: heatmap_data.loc[cat, metric] = cat_data[metric].mean() # Normalisation des données pour la carte de chaleur normalized_data = (heatmap_data - heatmap_data.min()) / (heatmap_data.max() - heatmap_data.min()) # Création de la carte de chaleur fig = go.Figure(data=go.Heatmap( z=normalized_data.values, x=normalized_data.columns, y=normalized_data.index, colorscale='Viridis', hovertemplate='Catégorie: %{y}
Métrique: %{x}
Valeur: %{z}' )) fig.update_layout( title='Carte de chaleur des métriques par catégorie', xaxis_title='Métriques', yaxis_title='Catégories' ) return fig # Chargement des données df = load_data() # Sidebar pour les filtres st.sidebar.title("Filtres") # Filtre par catégorie categories = sorted(df['Category name'].dropna().unique()) selected_categories = st.sidebar.multiselect( "Sélectionner les catégories", categories, default=categories[:3] # Par défaut, sélectionne les 3 premières catégories ) # Filtre par date de tendance min_date = df['trending_date_formatted'].min().date() max_date = df['trending_date_formatted'].max().date() date_range = st.sidebar.date_input( "Période de tendance", [min_date, max_date], min_value=min_date, max_value=max_date ) # Filtre par chaîne YouTube channels = sorted(df['channelTitle'].dropna().unique()) selected_channels = st.sidebar.multiselect( "Sélectionner les chaînes", channels, default=[] ) # Application des filtres filtered_df = df.copy() if selected_categories: filtered_df = filtered_df[filtered_df['Category name'].isin(selected_categories)] if len(date_range) == 2: start_date, end_date = date_range filtered_df = filtered_df[ (filtered_df['trending_date_formatted'].dt.date >= start_date) & (filtered_df['trending_date_formatted'].dt.date <= end_date) ] if selected_channels: filtered_df = filtered_df[filtered_df['channelTitle'].isin(selected_channels)] # Titre principal st.title("📊 Analyse des tendances YouTube 2025") # Métriques principales st.header("📈 Indicateurs clés") col1, col2, col3, col4 = st.columns(4) with col1: st.metric("Nombre de vidéos", f"{len(filtered_df):,}") with col2: avg_views = filtered_df['view_count'].mean() st.metric("Vues moyennes", f"{avg_views:,.0f}") with col3: avg_likes_per_view = filtered_df['likes_per_view'].mean() * 100 st.metric("Likes/Vues moyen", f"{avg_likes_per_view:.2f}%") with col4: avg_duration = filtered_df['duration_minutes'].mean() st.metric("Durée moyenne", f"{avg_duration:.1f} min") # Visualisations st.header("🔍 Visualisations") # Distribution des vues col1, col2 = st.columns(2) with col1: views_hist = create_histogram(filtered_df, 'view_count', 'Distribution des vues', color='#FF0000', nbins=30) st.plotly_chart(views_hist, use_container_width=True) with col2: duration_hist = create_histogram(filtered_df, 'duration_minutes', 'Distribution des durées (minutes)', color='#00BFD6', nbins=25) st.plotly_chart(duration_hist, use_container_width=True) # Engagement par catégorie col1, col2 = st.columns(2) with col1: category_engagement = filtered_df.groupby('Category name').agg({ 'likes_per_view': 'mean', 'comments_per_view': 'mean' }).reset_index() category_engagement['likes_per_view'] = category_engagement['likes_per_view'] * 100 category_engagement['comments_per_view'] = category_engagement['comments_per_view'] * 100 likes_by_category = create_bar_chart( category_engagement, 'Category name', 'likes_per_view', 'Taux de likes par catégorie (%)', color='#FF9900' ) st.plotly_chart(likes_by_category, use_container_width=True) with col2: comments_by_category = create_bar_chart( category_engagement, 'Category name', 'comments_per_view', 'Taux de commentaires par catégorie (%)', color='#00CC96' ) st.plotly_chart(comments_by_category, use_container_width=True) # Nuage de points des vidéos scatter_plot = create_scatter_plot( filtered_df, 'view_count', 'likes_per_view', 'duration_minutes', ['title', 'channelTitle', 'Category name'], 'Relation entre vues et taux de likes' ) st.plotly_chart(scatter_plot, use_container_width=True) # Carte de chaleur des métriques par catégorie if selected_categories: metrics = ['view_count', 'likes_per_view', 'comments_per_view', 'duration_minutes'] heatmap = create_heatmap(filtered_df, selected_categories, metrics) st.plotly_chart(heatmap, use_container_width=True) # Top vidéos par vues st.header("🏆 Top 10 des vidéos les plus vues") top_videos = filtered_df.nlargest(10, 'view_count')[['title', 'channelTitle', 'Category name', 'view_count', 'likes', 'comment_count', 'duration_minutes']] top_videos = top_videos.rename(columns={ 'title': 'Titre', 'channelTitle': 'Chaîne', 'Category name': 'Catégorie', 'view_count': 'Vues', 'likes': 'Likes', 'comment_count': 'Commentaires', 'duration_minutes': 'Durée (min)' }) st.dataframe(top_videos, use_container_width=True) # Téléchargement des données filtrées st.header("📥 Télécharger les données filtrées") csv = filtered_df.to_csv(index=False).encode('utf-8') st.download_button( label="Télécharger en CSV", data=csv, file_name="youtube_trends_filtered.csv", mime="text/csv", ) # Informations sur l'application st.sidebar.markdown("---") st.sidebar.info(""" **À propos de cette application** Cette application analyse les tendances YouTube de 2025. Vous pouvez filtrer les données par catégorie, date et chaîne pour explorer les métriques importantes. Données mises à jour le 9 avril 2025. """)