Spaces:
Sleeping
Sleeping
File size: 12,402 Bytes
b71325b |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 |
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('youtube_channels_2025.csv')
categories = pd.read_csv('category.csv', sep=';')
# Conversion des types de données
numeric_cols = ['Views', 'Likes', 'Comments', 'Channel_subscribers', 'Channel_views',
'Channel_total_videos', 'duration_seconds', 'like_rate', 'comment_rate',
'views_per_subscriber', 'vues_par_jour']
for col in numeric_cols:
if col in df.columns:
df[col] = pd.to_numeric(df[col], errors='coerce')
# Conversion de la date de publication
df['Published_date'] = pd.to_datetime(df['Published_date'], errors='coerce')
# Extraction du jour de la semaine et de l'heure
df['day_of_week'] = df['Published_date'].dt.day_name()
df['hour_of_publication'] = df['Published_date'].dt.hour
# Conversion de la durée en minutes
df['duration_minutes'] = df['duration_seconds'] / 60
# Ajout des noms de catégories
df = df.merge(categories, left_on='category_id', right_on='ID', how='left')
# Nettoyage des données manquantes
df = df.dropna(subset=['Views', 'Likes', 'Category name'])
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,
color_discrete_sequence=[color])
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])
fig.update_xaxis(tickangle=45)
return fig
# Fonction pour créer un nuage de points
def create_scatter_plot(df, x_col, y_col, size_col, hover_data, title, color_col=None):
fig = px.scatter(df, x=x_col, y=y_col, size=size_col,
hover_data=hover_data, title=title,
color=color_col if color_col else None)
return fig
# Fonction pour créer une série temporelle
def create_time_series(df, date_col, value_col, title):
daily_stats = df.groupby(df[date_col].dt.date)[value_col].mean().reset_index()
fig = px.line(daily_stats, x=date_col, y=value_col, title=title)
return fig
# Chargement des données
try:
df = load_data()
except FileNotFoundError as e:
st.error(f"Erreur lors du chargement des fichiers : {e}")
st.error("Assurez-vous que les fichiers 'youtube_channels_2025.csv' et 'category.csv' sont présents.")
st.stop()
# Sidebar pour les filtres
st.sidebar.title("🎛️ Filtres")
# Filtre par catégorie
if 'Category name' in df.columns:
categories = sorted(df['Category name'].dropna().unique())
selected_categories = st.sidebar.multiselect(
"📂 Sélectionner les catégories",
categories,
default=categories[:5] if len(categories) >= 5 else categories
)
else:
selected_categories = []
# Filtre par date de publication
if 'Published_date' in df.columns:
min_date = df['Published_date'].min().date()
max_date = df['Published_date'].max().date()
date_range = st.sidebar.date_input(
"📅 Période de publication",
[min_date, max_date],
min_value=min_date,
max_value=max_date
)
else:
date_range = []
# Filtre par chaîne YouTube
if 'Channel_name' in df.columns:
channels = sorted(df['Channel_name'].dropna().unique())
selected_channels = st.sidebar.multiselect(
"📺 Sélectionner les chaînes",
channels,
default=[]
)
else:
selected_channels = []
# Filtre par jour de la semaine
if 'day_of_week' in df.columns:
days = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']
selected_days = st.sidebar.multiselect(
"📆 Jours de la semaine",
days,
default=days
)
else:
selected_days = []
# Application des filtres
filtered_df = df.copy()
if selected_categories and 'Category name' in df.columns:
filtered_df = filtered_df[filtered_df['Category name'].isin(selected_categories)]
if len(date_range) == 2 and 'Published_date' in df.columns:
start_date, end_date = date_range
filtered_df = filtered_df[
(filtered_df['Published_date'].dt.date >= start_date) &
(filtered_df['Published_date'].dt.date <= end_date)
]
if selected_channels and 'Channel_name' in df.columns:
filtered_df = filtered_df[filtered_df['Channel_name'].isin(selected_channels)]
if selected_days and 'day_of_week' in df.columns:
filtered_df = filtered_df[filtered_df['day_of_week'].isin(selected_days)]
# Titre principal
st.title("📊 Analyse des tendances YouTube 2025")
st.markdown("*Explorez les données des chaînes YouTube qui ont été en tendance*")
# Métriques principales
st.header("📈 Indicateurs clés")
col1, col2, col3, col4, col5 = st.columns(5)
with col1:
st.metric("Nombre de vidéos", f"{len(filtered_df):,}")
with col2:
if 'Views' in filtered_df.columns:
avg_views = filtered_df['Views'].mean()
st.metric("Vues moyennes", f"{avg_views:,.0f}")
with col3:
if 'like_rate' in filtered_df.columns:
avg_like_rate = filtered_df['like_rate'].mean() * 100
st.metric("Taux de likes moyen", f"{avg_like_rate:.2f}%")
with col4:
if 'duration_minutes' in filtered_df.columns:
avg_duration = filtered_df['duration_minutes'].mean()
st.metric("Durée moyenne", f"{avg_duration:.1f} min")
with col5:
if 'views_per_subscriber' in filtered_df.columns:
avg_vps = filtered_df['views_per_subscriber'].mean()
st.metric("Vues/Abonnés", f"{avg_vps:.3f}")
# Visualisations principales
st.header("🔍 Visualisations")
# Première ligne de graphiques
col1, col2 = st.columns(2)
with col1:
if 'Views' in filtered_df.columns:
views_hist = create_histogram(filtered_df, 'Views', 'Distribution des vues', color='#FF0000', nbins=30)
st.plotly_chart(views_hist, use_container_width=True)
with col2:
if 'duration_minutes' in filtered_df.columns:
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)
# Deuxième ligne de graphiques
col1, col2 = st.columns(2)
with col1:
if 'Category name' in filtered_df.columns and 'like_rate' in filtered_df.columns:
category_engagement = filtered_df.groupby('Category name').agg({
'like_rate': 'mean',
'comment_rate': 'mean' if 'comment_rate' in filtered_df.columns else 'count'
}).reset_index()
category_engagement['like_rate'] = category_engagement['like_rate'] * 100
likes_by_category = create_bar_chart(
category_engagement,
'Category name',
'like_rate',
'Taux de likes par catégorie (%)',
color='#FF9900'
)
st.plotly_chart(likes_by_category, use_container_width=True)
with col2:
if 'day_of_week' in filtered_df.columns and 'Views' in filtered_df.columns:
daily_stats = filtered_df.groupby('day_of_week')['Views'].mean().reset_index()
# Réorganiser les jours dans l'ordre
day_order = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']
daily_stats['day_of_week'] = pd.Categorical(daily_stats['day_of_week'], categories=day_order, ordered=True)
daily_stats = daily_stats.sort_values('day_of_week')
daily_views = create_bar_chart(
daily_stats,
'day_of_week',
'Views',
'Vues moyennes par jour de la semaine',
color='#00CC96'
)
st.plotly_chart(daily_views, use_container_width=True)
# Graphique de dispersion
if all(col in filtered_df.columns for col in ['Views', 'like_rate', 'Channel_subscribers']):
scatter_plot = create_scatter_plot(
filtered_df,
'Views',
'like_rate',
'Channel_subscribers',
['Title', 'Channel_name', 'Category name'],
'Relation entre vues et taux de likes (taille = nb d\'abonnés)',
'Category name'
)
st.plotly_chart(scatter_plot, use_container_width=True)
# Analyse temporelle
if 'Published_date' in filtered_df.columns and 'Views' in filtered_df.columns:
st.header("📅 Analyse temporelle")
col1, col2 = st.columns(2)
with col1:
time_series = create_time_series(filtered_df, 'Published_date', 'Views', 'Évolution des vues moyennes dans le temps')
st.plotly_chart(time_series, use_container_width=True)
with col2:
if 'hour_of_publication' in filtered_df.columns:
hourly_stats = filtered_df.groupby('hour_of_publication')['Views'].mean().reset_index()
hourly_chart = create_bar_chart(
hourly_stats,
'hour_of_publication',
'Views',
'Vues moyennes par heure de publication',
color='#9467bd'
)
st.plotly_chart(hourly_chart, use_container_width=True)
# Top vidéos
st.header("🏆 Top 10 des vidéos les plus vues")
if 'Views' in filtered_df.columns:
top_videos = filtered_df.nlargest(10, 'Views')[
['Title', 'Channel_name', 'Category name', 'Views', 'Likes', 'Comments', 'duration_minutes']
].copy()
# Renommer les colonnes pour l'affichage
top_videos = top_videos.rename(columns={
'Title': 'Titre',
'Channel_name': 'Chaîne',
'Category name': 'Catégorie',
'Views': 'Vues',
'Likes': 'Likes',
'Comments': 'Commentaires',
'duration_minutes': 'Durée (min)'
})
st.dataframe(top_videos, use_container_width=True)
# Statistiques par chaîne
st.header("📺 Top chaînes")
if all(col in filtered_df.columns for col in ['Channel_name', 'Views', 'Channel_subscribers']):
channel_stats = filtered_df.groupby('Channel_name').agg({
'Views': ['count', 'mean', 'sum'],
'Channel_subscribers': 'first',
'like_rate': 'mean',
'views_per_subscriber': 'mean'
}).round(2)
# Aplatir les colonnes multi-index
channel_stats.columns = ['Nb_vidéos', 'Vues_moyennes', 'Vues_totales', 'Abonnés', 'Taux_likes_moyen', 'Vues_par_abonné']
channel_stats = channel_stats.reset_index()
channel_stats = channel_stats.sort_values('Vues_totales', ascending=False).head(10)
st.dataframe(channel_stats, use_container_width=True)
# Export des donné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_2025.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 basées sur les chaînes qui ont été en tendance.
**Fonctionnalités :**
- Filtrage par catégorie, date, chaîne et jour
- Indicateurs clés de performance
- Visualisations interactives
- Analyse temporelle
- Export des données
Créé avec Streamlit et Plotly.
""")
# Statistiques globales en bas de page
with st.expander("📊 Statistiques globales du dataset"):
st.write(f"**Nombre total de vidéos :** {len(df):,}")
st.write(f"**Nombre de chaînes uniques :** {df['Channel_name'].nunique() if 'Channel_name' in df.columns else 'N/A'}")
st.write(f"**Nombre de catégories :** {df['Category name'].nunique() if 'Category name' in df.columns else 'N/A'}")
st.write(f"**Période couverte :** {df['Published_date'].min().strftime('%d/%m/%Y') if 'Published_date' in df.columns else 'N/A'} - {df['Published_date'].max().strftime('%d/%m/%Y') if 'Published_date' in df.columns else 'N/A'}")
|