youtube-trends / app.py
jeanviet's picture
Update app.py
1518b5c verified
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}<br>Métrique: %{x}<br>Valeur: %{z}<extra></extra>'
))
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.
""")