Spaces:
Runtime error
Runtime error
ajout 5 fichier
Browse filesdonnées + projet
- .gitattributes +1 -0
- README.md +136 -7
- app.py +342 -0
- category.csv +16 -0
- requirements.txt +4 -0
- youtube_channels_2025.csv +3 -0
.gitattributes
CHANGED
|
@@ -33,3 +33,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
| 36 |
+
youtube_channels_2025.csv filter=lfs diff=lfs merge=lfs -text
|
README.md
CHANGED
|
@@ -1,12 +1,141 @@
|
|
| 1 |
---
|
| 2 |
-
title:
|
| 3 |
-
emoji:
|
| 4 |
-
colorFrom:
|
| 5 |
colorTo: blue
|
| 6 |
-
sdk:
|
|
|
|
|
|
|
| 7 |
pinned: false
|
| 8 |
-
license:
|
| 9 |
-
short_description: Analyse des
|
| 10 |
---
|
| 11 |
|
| 12 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
---
|
| 2 |
+
title: YouTube Trends 2025
|
| 3 |
+
emoji: 📊
|
| 4 |
+
colorFrom: red
|
| 5 |
colorTo: blue
|
| 6 |
+
sdk: streamlit
|
| 7 |
+
sdk_version: 1.29.0
|
| 8 |
+
app_file: app.py
|
| 9 |
pinned: false
|
| 10 |
+
license: apache-2.0
|
| 11 |
+
short_description: Analyse des tendances YouTube 2025
|
| 12 |
---
|
| 13 |
|
| 14 |
+
# 📊 YouTube Trends Analyzer 2025
|
| 15 |
+
|
| 16 |
+
Cette application Streamlit permet d'analyser les tendances YouTube de 2025 à travers diverses métriques et visualisations interactives basées sur les chaînes qui ont été en tendance.
|
| 17 |
+
|
| 18 |
+
## 🚀 Fonctionnalités
|
| 19 |
+
|
| 20 |
+
### 🎛️ Filtrage avancé
|
| 21 |
+
- **Par catégorie** : Film, Musique, Gaming, Sport, etc.
|
| 22 |
+
- **Par période** : Sélection de plages de dates
|
| 23 |
+
- **Par chaîne YouTube** : Analyse de chaînes spécifiques
|
| 24 |
+
- **Par jour de la semaine** : Comprendre les patterns temporels
|
| 25 |
+
|
| 26 |
+
### 📈 Indicateurs clés
|
| 27 |
+
- Nombre total de vidéos analysées
|
| 28 |
+
- Vues moyennes par vidéo
|
| 29 |
+
- Taux de likes moyen (likes/vues)
|
| 30 |
+
- Durée moyenne des vidéos
|
| 31 |
+
- Ratio vues/abonnés
|
| 32 |
+
|
| 33 |
+
### 🔍 Visualisations interactives
|
| 34 |
+
- **Histogrammes** : Distribution des vues et durées
|
| 35 |
+
- **Graphiques en barres** : Performance par catégorie et jour
|
| 36 |
+
- **Nuage de points** : Corrélation vues/engagement avec taille par abonnés
|
| 37 |
+
- **Séries temporelles** : Évolution des métriques dans le temps
|
| 38 |
+
- **Analyse horaire** : Meilleurs moments de publication
|
| 39 |
+
|
| 40 |
+
### 📊 Tableaux de données
|
| 41 |
+
- **Top 10 vidéos** les plus vues avec métriques détaillées
|
| 42 |
+
- **Top chaînes** avec statistiques agrégées
|
| 43 |
+
- **Export CSV** des données filtrées
|
| 44 |
+
|
| 45 |
+
## 📁 Structure des données
|
| 46 |
+
|
| 47 |
+
### youtube_channels_2025.csv
|
| 48 |
+
Contient les informations sur toutes les vidéos 2025 des chaînes qui ont été en tendance :
|
| 49 |
+
- `video_id` : Identifiant unique de la vidéo
|
| 50 |
+
- `Title` : Titre de la vidéo
|
| 51 |
+
- `Published_date` : Date de publication
|
| 52 |
+
- `Views` : Nombre de vues
|
| 53 |
+
- `Likes` : Nombre de likes
|
| 54 |
+
- `Comments` : Nombre de commentaires
|
| 55 |
+
- `Channel_name` : Nom de la chaîne
|
| 56 |
+
- `Channel_subscribers` : Nombre d'abonnés de la chaîne
|
| 57 |
+
- `category_id` : ID de la catégorie
|
| 58 |
+
- `duration_seconds` : Durée en secondes
|
| 59 |
+
- `like_rate` : Taux de likes (likes/vues)
|
| 60 |
+
- `comment_rate` : Taux de commentaires (commentaires/vues)
|
| 61 |
+
- `views_per_subscriber` : Ratio vues/abonnés
|
| 62 |
+
|
| 63 |
+
### category.csv
|
| 64 |
+
Fichier de correspondance des catégories :
|
| 65 |
+
- `ID` : Identifiant numérique de la catégorie
|
| 66 |
+
- `Category name` : Nom de la catégorie (Film & Animation, Gaming, Music, etc.)
|
| 67 |
+
|
| 68 |
+
## 🛠️ Installation et déploiement
|
| 69 |
+
|
| 70 |
+
### Déploiement sur Hugging Face Spaces
|
| 71 |
+
|
| 72 |
+
1. **Créer un nouveau Space**
|
| 73 |
+
- Connectez-vous à [Hugging Face](https://huggingface.co/)
|
| 74 |
+
- Cliquez sur "Create new Space"
|
| 75 |
+
- Sélectionnez "Streamlit" comme SDK
|
| 76 |
+
- Nommez votre space (ex: `youtube-trends-2025`)
|
| 77 |
+
|
| 78 |
+
2. **Uploader les fichiers**
|
| 79 |
+
- `app.py` : Application principale
|
| 80 |
+
- `requirements.txt` : Dépendances Python
|
| 81 |
+
- `youtube_channels_2025.csv` : Vos données YouTube
|
| 82 |
+
- `category.csv` : Correspondance des catégories
|
| 83 |
+
- `README.md` : Documentation
|
| 84 |
+
|
| 85 |
+
3. **Configuration automatique**
|
| 86 |
+
- L'application se déploie automatiquement
|
| 87 |
+
- Accessible via l'URL de votre Space
|
| 88 |
+
|
| 89 |
+
### Installation locale
|
| 90 |
+
|
| 91 |
+
```bash
|
| 92 |
+
pip install -r requirements.txt
|
| 93 |
+
streamlit run app.py
|
| 94 |
+
```
|
| 95 |
+
|
| 96 |
+
## 📊 Métriques et analyses disponibles
|
| 97 |
+
|
| 98 |
+
### Performance globale
|
| 99 |
+
- Distribution des vues et engagement
|
| 100 |
+
- Comparaison entre catégories
|
| 101 |
+
- Patterns temporels (jours, heures)
|
| 102 |
+
|
| 103 |
+
### Analyse par chaîne
|
| 104 |
+
- Performances individuelles
|
| 105 |
+
- Comparaison des stratégies de contenu
|
| 106 |
+
- Efficacité du ratio abonnés/vues
|
| 107 |
+
|
| 108 |
+
### Tendances temporelles
|
| 109 |
+
- Évolution des métriques dans le temps
|
| 110 |
+
- Meilleurs moments de publication
|
| 111 |
+
- Saisonnalité du contenu
|
| 112 |
+
|
| 113 |
+
## 🎯 Cas d'usage
|
| 114 |
+
|
| 115 |
+
- **Créateurs de contenu** : Optimiser leurs stratégies de publication
|
| 116 |
+
- **Marketeurs** : Comprendre les tendances du marché YouTube
|
| 117 |
+
- **Analystes** : Étudier les patterns de consommation vidéo
|
| 118 |
+
- **Chercheurs** : Analyser l'écosystème YouTube
|
| 119 |
+
|
| 120 |
+
## 🔧 Personnalisation
|
| 121 |
+
|
| 122 |
+
L'application est facilement personnalisable :
|
| 123 |
+
- Ajouter de nouvelles métriques dans les calculs
|
| 124 |
+
- Créer de nouveaux types de visualisations
|
| 125 |
+
- Modifier les filtres selon vos besoins
|
| 126 |
+
- Adapter les couleurs et le style
|
| 127 |
+
|
| 128 |
+
## 📝 Notes techniques
|
| 129 |
+
|
| 130 |
+
- **Cache des données** : Utilisation de `@st.cache_data` pour optimiser les performances
|
| 131 |
+
- **Gestion d'erreurs** : Traitement robuste des données manquantes
|
| 132 |
+
- **Interface responsive** : Adaptation automatique à différentes tailles d'écran
|
| 133 |
+
- **Export de données** : Téléchargement CSV des données filtrées
|
| 134 |
+
|
| 135 |
+
## 🤝 Contribution
|
| 136 |
+
|
| 137 |
+
N'hésitez pas à fork ce projet et à proposer des améliorations !
|
| 138 |
+
|
| 139 |
+
## 📄 Licence
|
| 140 |
+
|
| 141 |
+
Ce projet est disponible sous licence Apache 2.0.
|
app.py
ADDED
|
@@ -0,0 +1,342 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import streamlit as st
|
| 2 |
+
import pandas as pd
|
| 3 |
+
import numpy as np
|
| 4 |
+
import plotly.express as px
|
| 5 |
+
import plotly.graph_objects as go
|
| 6 |
+
from datetime import datetime
|
| 7 |
+
import re
|
| 8 |
+
|
| 9 |
+
# Configuration de la page
|
| 10 |
+
st.set_page_config(
|
| 11 |
+
page_title="Analyse des tendances YouTube 2025",
|
| 12 |
+
page_icon="📊",
|
| 13 |
+
layout="wide"
|
| 14 |
+
)
|
| 15 |
+
|
| 16 |
+
# Fonction pour charger les données
|
| 17 |
+
@st.cache_data
|
| 18 |
+
def load_data():
|
| 19 |
+
# Chargement des données
|
| 20 |
+
df = pd.read_csv('youtube_channels_2025.csv')
|
| 21 |
+
categories = pd.read_csv('category.csv', sep=';')
|
| 22 |
+
|
| 23 |
+
# Conversion des types de données
|
| 24 |
+
numeric_cols = ['Views', 'Likes', 'Comments', 'Channel_subscribers', 'Channel_views',
|
| 25 |
+
'Channel_total_videos', 'duration_seconds', 'like_rate', 'comment_rate',
|
| 26 |
+
'views_per_subscriber', 'vues_par_jour']
|
| 27 |
+
|
| 28 |
+
for col in numeric_cols:
|
| 29 |
+
if col in df.columns:
|
| 30 |
+
df[col] = pd.to_numeric(df[col], errors='coerce')
|
| 31 |
+
|
| 32 |
+
# Conversion de la date de publication
|
| 33 |
+
df['Published_date'] = pd.to_datetime(df['Published_date'], errors='coerce')
|
| 34 |
+
|
| 35 |
+
# Extraction du jour de la semaine et de l'heure
|
| 36 |
+
df['day_of_week'] = df['Published_date'].dt.day_name()
|
| 37 |
+
df['hour_of_publication'] = df['Published_date'].dt.hour
|
| 38 |
+
|
| 39 |
+
# Conversion de la durée en minutes
|
| 40 |
+
df['duration_minutes'] = df['duration_seconds'] / 60
|
| 41 |
+
|
| 42 |
+
# Ajout des noms de catégories
|
| 43 |
+
df = df.merge(categories, left_on='category_id', right_on='ID', how='left')
|
| 44 |
+
|
| 45 |
+
# Nettoyage des données manquantes
|
| 46 |
+
df = df.dropna(subset=['Views', 'Likes', 'Category name'])
|
| 47 |
+
|
| 48 |
+
return df
|
| 49 |
+
|
| 50 |
+
# Fonction pour créer un histogramme
|
| 51 |
+
def create_histogram(df, column, title, color='#1f77b4', nbins=20):
|
| 52 |
+
fig = px.histogram(df, x=column, nbins=nbins, title=title,
|
| 53 |
+
color_discrete_sequence=[color])
|
| 54 |
+
fig.update_layout(bargap=0.1)
|
| 55 |
+
return fig
|
| 56 |
+
|
| 57 |
+
# Fonction pour créer un graphique en barres
|
| 58 |
+
def create_bar_chart(df, x_col, y_col, title, color='#1f77b4'):
|
| 59 |
+
fig = px.bar(df, x=x_col, y=y_col, title=title,
|
| 60 |
+
color_discrete_sequence=[color])
|
| 61 |
+
fig.update_xaxis(tickangle=45)
|
| 62 |
+
return fig
|
| 63 |
+
|
| 64 |
+
# Fonction pour créer un nuage de points
|
| 65 |
+
def create_scatter_plot(df, x_col, y_col, size_col, hover_data, title, color_col=None):
|
| 66 |
+
fig = px.scatter(df, x=x_col, y=y_col, size=size_col,
|
| 67 |
+
hover_data=hover_data, title=title,
|
| 68 |
+
color=color_col if color_col else None)
|
| 69 |
+
return fig
|
| 70 |
+
|
| 71 |
+
# Fonction pour créer une série temporelle
|
| 72 |
+
def create_time_series(df, date_col, value_col, title):
|
| 73 |
+
daily_stats = df.groupby(df[date_col].dt.date)[value_col].mean().reset_index()
|
| 74 |
+
fig = px.line(daily_stats, x=date_col, y=value_col, title=title)
|
| 75 |
+
return fig
|
| 76 |
+
|
| 77 |
+
# Chargement des données
|
| 78 |
+
try:
|
| 79 |
+
df = load_data()
|
| 80 |
+
except FileNotFoundError as e:
|
| 81 |
+
st.error(f"Erreur lors du chargement des fichiers : {e}")
|
| 82 |
+
st.error("Assurez-vous que les fichiers 'youtube_channels_2025.csv' et 'category.csv' sont présents.")
|
| 83 |
+
st.stop()
|
| 84 |
+
|
| 85 |
+
# Sidebar pour les filtres
|
| 86 |
+
st.sidebar.title("🎛️ Filtres")
|
| 87 |
+
|
| 88 |
+
# Filtre par catégorie
|
| 89 |
+
if 'Category name' in df.columns:
|
| 90 |
+
categories = sorted(df['Category name'].dropna().unique())
|
| 91 |
+
selected_categories = st.sidebar.multiselect(
|
| 92 |
+
"📂 Sélectionner les catégories",
|
| 93 |
+
categories,
|
| 94 |
+
default=categories[:5] if len(categories) >= 5 else categories
|
| 95 |
+
)
|
| 96 |
+
else:
|
| 97 |
+
selected_categories = []
|
| 98 |
+
|
| 99 |
+
# Filtre par date de publication
|
| 100 |
+
if 'Published_date' in df.columns:
|
| 101 |
+
min_date = df['Published_date'].min().date()
|
| 102 |
+
max_date = df['Published_date'].max().date()
|
| 103 |
+
date_range = st.sidebar.date_input(
|
| 104 |
+
"📅 Période de publication",
|
| 105 |
+
[min_date, max_date],
|
| 106 |
+
min_value=min_date,
|
| 107 |
+
max_value=max_date
|
| 108 |
+
)
|
| 109 |
+
else:
|
| 110 |
+
date_range = []
|
| 111 |
+
|
| 112 |
+
# Filtre par chaîne YouTube
|
| 113 |
+
if 'Channel_name' in df.columns:
|
| 114 |
+
channels = sorted(df['Channel_name'].dropna().unique())
|
| 115 |
+
selected_channels = st.sidebar.multiselect(
|
| 116 |
+
"📺 Sélectionner les chaînes",
|
| 117 |
+
channels,
|
| 118 |
+
default=[]
|
| 119 |
+
)
|
| 120 |
+
else:
|
| 121 |
+
selected_channels = []
|
| 122 |
+
|
| 123 |
+
# Filtre par jour de la semaine
|
| 124 |
+
if 'day_of_week' in df.columns:
|
| 125 |
+
days = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']
|
| 126 |
+
selected_days = st.sidebar.multiselect(
|
| 127 |
+
"📆 Jours de la semaine",
|
| 128 |
+
days,
|
| 129 |
+
default=days
|
| 130 |
+
)
|
| 131 |
+
else:
|
| 132 |
+
selected_days = []
|
| 133 |
+
|
| 134 |
+
# Application des filtres
|
| 135 |
+
filtered_df = df.copy()
|
| 136 |
+
|
| 137 |
+
if selected_categories and 'Category name' in df.columns:
|
| 138 |
+
filtered_df = filtered_df[filtered_df['Category name'].isin(selected_categories)]
|
| 139 |
+
|
| 140 |
+
if len(date_range) == 2 and 'Published_date' in df.columns:
|
| 141 |
+
start_date, end_date = date_range
|
| 142 |
+
filtered_df = filtered_df[
|
| 143 |
+
(filtered_df['Published_date'].dt.date >= start_date) &
|
| 144 |
+
(filtered_df['Published_date'].dt.date <= end_date)
|
| 145 |
+
]
|
| 146 |
+
|
| 147 |
+
if selected_channels and 'Channel_name' in df.columns:
|
| 148 |
+
filtered_df = filtered_df[filtered_df['Channel_name'].isin(selected_channels)]
|
| 149 |
+
|
| 150 |
+
if selected_days and 'day_of_week' in df.columns:
|
| 151 |
+
filtered_df = filtered_df[filtered_df['day_of_week'].isin(selected_days)]
|
| 152 |
+
|
| 153 |
+
# Titre principal
|
| 154 |
+
st.title("📊 Analyse des tendances YouTube 2025")
|
| 155 |
+
st.markdown("*Explorez les données des chaînes YouTube qui ont été en tendance*")
|
| 156 |
+
|
| 157 |
+
# Métriques principales
|
| 158 |
+
st.header("📈 Indicateurs clés")
|
| 159 |
+
col1, col2, col3, col4, col5 = st.columns(5)
|
| 160 |
+
|
| 161 |
+
with col1:
|
| 162 |
+
st.metric("Nombre de vidéos", f"{len(filtered_df):,}")
|
| 163 |
+
|
| 164 |
+
with col2:
|
| 165 |
+
if 'Views' in filtered_df.columns:
|
| 166 |
+
avg_views = filtered_df['Views'].mean()
|
| 167 |
+
st.metric("Vues moyennes", f"{avg_views:,.0f}")
|
| 168 |
+
|
| 169 |
+
with col3:
|
| 170 |
+
if 'like_rate' in filtered_df.columns:
|
| 171 |
+
avg_like_rate = filtered_df['like_rate'].mean() * 100
|
| 172 |
+
st.metric("Taux de likes moyen", f"{avg_like_rate:.2f}%")
|
| 173 |
+
|
| 174 |
+
with col4:
|
| 175 |
+
if 'duration_minutes' in filtered_df.columns:
|
| 176 |
+
avg_duration = filtered_df['duration_minutes'].mean()
|
| 177 |
+
st.metric("Durée moyenne", f"{avg_duration:.1f} min")
|
| 178 |
+
|
| 179 |
+
with col5:
|
| 180 |
+
if 'views_per_subscriber' in filtered_df.columns:
|
| 181 |
+
avg_vps = filtered_df['views_per_subscriber'].mean()
|
| 182 |
+
st.metric("Vues/Abonnés", f"{avg_vps:.3f}")
|
| 183 |
+
|
| 184 |
+
# Visualisations principales
|
| 185 |
+
st.header("🔍 Visualisations")
|
| 186 |
+
|
| 187 |
+
# Première ligne de graphiques
|
| 188 |
+
col1, col2 = st.columns(2)
|
| 189 |
+
|
| 190 |
+
with col1:
|
| 191 |
+
if 'Views' in filtered_df.columns:
|
| 192 |
+
views_hist = create_histogram(filtered_df, 'Views', 'Distribution des vues', color='#FF0000', nbins=30)
|
| 193 |
+
st.plotly_chart(views_hist, use_container_width=True)
|
| 194 |
+
|
| 195 |
+
with col2:
|
| 196 |
+
if 'duration_minutes' in filtered_df.columns:
|
| 197 |
+
duration_hist = create_histogram(filtered_df, 'duration_minutes', 'Distribution des durées (minutes)', color='#00BFD6', nbins=25)
|
| 198 |
+
st.plotly_chart(duration_hist, use_container_width=True)
|
| 199 |
+
|
| 200 |
+
# Deuxième ligne de graphiques
|
| 201 |
+
col1, col2 = st.columns(2)
|
| 202 |
+
|
| 203 |
+
with col1:
|
| 204 |
+
if 'Category name' in filtered_df.columns and 'like_rate' in filtered_df.columns:
|
| 205 |
+
category_engagement = filtered_df.groupby('Category name').agg({
|
| 206 |
+
'like_rate': 'mean',
|
| 207 |
+
'comment_rate': 'mean' if 'comment_rate' in filtered_df.columns else 'count'
|
| 208 |
+
}).reset_index()
|
| 209 |
+
|
| 210 |
+
category_engagement['like_rate'] = category_engagement['like_rate'] * 100
|
| 211 |
+
|
| 212 |
+
likes_by_category = create_bar_chart(
|
| 213 |
+
category_engagement,
|
| 214 |
+
'Category name',
|
| 215 |
+
'like_rate',
|
| 216 |
+
'Taux de likes par catégorie (%)',
|
| 217 |
+
color='#FF9900'
|
| 218 |
+
)
|
| 219 |
+
st.plotly_chart(likes_by_category, use_container_width=True)
|
| 220 |
+
|
| 221 |
+
with col2:
|
| 222 |
+
if 'day_of_week' in filtered_df.columns and 'Views' in filtered_df.columns:
|
| 223 |
+
daily_stats = filtered_df.groupby('day_of_week')['Views'].mean().reset_index()
|
| 224 |
+
# Réorganiser les jours dans l'ordre
|
| 225 |
+
day_order = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']
|
| 226 |
+
daily_stats['day_of_week'] = pd.Categorical(daily_stats['day_of_week'], categories=day_order, ordered=True)
|
| 227 |
+
daily_stats = daily_stats.sort_values('day_of_week')
|
| 228 |
+
|
| 229 |
+
daily_views = create_bar_chart(
|
| 230 |
+
daily_stats,
|
| 231 |
+
'day_of_week',
|
| 232 |
+
'Views',
|
| 233 |
+
'Vues moyennes par jour de la semaine',
|
| 234 |
+
color='#00CC96'
|
| 235 |
+
)
|
| 236 |
+
st.plotly_chart(daily_views, use_container_width=True)
|
| 237 |
+
|
| 238 |
+
# Graphique de dispersion
|
| 239 |
+
if all(col in filtered_df.columns for col in ['Views', 'like_rate', 'Channel_subscribers']):
|
| 240 |
+
scatter_plot = create_scatter_plot(
|
| 241 |
+
filtered_df,
|
| 242 |
+
'Views',
|
| 243 |
+
'like_rate',
|
| 244 |
+
'Channel_subscribers',
|
| 245 |
+
['Title', 'Channel_name', 'Category name'],
|
| 246 |
+
'Relation entre vues et taux de likes (taille = nb d\'abonnés)',
|
| 247 |
+
'Category name'
|
| 248 |
+
)
|
| 249 |
+
st.plotly_chart(scatter_plot, use_container_width=True)
|
| 250 |
+
|
| 251 |
+
# Analyse temporelle
|
| 252 |
+
if 'Published_date' in filtered_df.columns and 'Views' in filtered_df.columns:
|
| 253 |
+
st.header("📅 Analyse temporelle")
|
| 254 |
+
|
| 255 |
+
col1, col2 = st.columns(2)
|
| 256 |
+
|
| 257 |
+
with col1:
|
| 258 |
+
time_series = create_time_series(filtered_df, 'Published_date', 'Views', 'Évolution des vues moyennes dans le temps')
|
| 259 |
+
st.plotly_chart(time_series, use_container_width=True)
|
| 260 |
+
|
| 261 |
+
with col2:
|
| 262 |
+
if 'hour_of_publication' in filtered_df.columns:
|
| 263 |
+
hourly_stats = filtered_df.groupby('hour_of_publication')['Views'].mean().reset_index()
|
| 264 |
+
hourly_chart = create_bar_chart(
|
| 265 |
+
hourly_stats,
|
| 266 |
+
'hour_of_publication',
|
| 267 |
+
'Views',
|
| 268 |
+
'Vues moyennes par heure de publication',
|
| 269 |
+
color='#9467bd'
|
| 270 |
+
)
|
| 271 |
+
st.plotly_chart(hourly_chart, use_container_width=True)
|
| 272 |
+
|
| 273 |
+
# Top vidéos
|
| 274 |
+
st.header("🏆 Top 10 des vidéos les plus vues")
|
| 275 |
+
if 'Views' in filtered_df.columns:
|
| 276 |
+
top_videos = filtered_df.nlargest(10, 'Views')[
|
| 277 |
+
['Title', 'Channel_name', 'Category name', 'Views', 'Likes', 'Comments', 'duration_minutes']
|
| 278 |
+
].copy()
|
| 279 |
+
|
| 280 |
+
# Renommer les colonnes pour l'affichage
|
| 281 |
+
top_videos = top_videos.rename(columns={
|
| 282 |
+
'Title': 'Titre',
|
| 283 |
+
'Channel_name': 'Chaîne',
|
| 284 |
+
'Category name': 'Catégorie',
|
| 285 |
+
'Views': 'Vues',
|
| 286 |
+
'Likes': 'Likes',
|
| 287 |
+
'Comments': 'Commentaires',
|
| 288 |
+
'duration_minutes': 'Durée (min)'
|
| 289 |
+
})
|
| 290 |
+
|
| 291 |
+
st.dataframe(top_videos, use_container_width=True)
|
| 292 |
+
|
| 293 |
+
# Statistiques par chaîne
|
| 294 |
+
st.header("📺 Top chaînes")
|
| 295 |
+
if all(col in filtered_df.columns for col in ['Channel_name', 'Views', 'Channel_subscribers']):
|
| 296 |
+
channel_stats = filtered_df.groupby('Channel_name').agg({
|
| 297 |
+
'Views': ['count', 'mean', 'sum'],
|
| 298 |
+
'Channel_subscribers': 'first',
|
| 299 |
+
'like_rate': 'mean',
|
| 300 |
+
'views_per_subscriber': 'mean'
|
| 301 |
+
}).round(2)
|
| 302 |
+
|
| 303 |
+
# Aplatir les colonnes multi-index
|
| 304 |
+
channel_stats.columns = ['Nb_vidéos', 'Vues_moyennes', 'Vues_totales', 'Abonnés', 'Taux_likes_moyen', 'Vues_par_abonné']
|
| 305 |
+
channel_stats = channel_stats.reset_index()
|
| 306 |
+
channel_stats = channel_stats.sort_values('Vues_totales', ascending=False).head(10)
|
| 307 |
+
|
| 308 |
+
st.dataframe(channel_stats, use_container_width=True)
|
| 309 |
+
|
| 310 |
+
# Export des données
|
| 311 |
+
st.header("📥 Télécharger les données filtrées")
|
| 312 |
+
csv = filtered_df.to_csv(index=False).encode('utf-8')
|
| 313 |
+
st.download_button(
|
| 314 |
+
label="Télécharger en CSV",
|
| 315 |
+
data=csv,
|
| 316 |
+
file_name="youtube_trends_filtered_2025.csv",
|
| 317 |
+
mime="text/csv",
|
| 318 |
+
)
|
| 319 |
+
|
| 320 |
+
# Informations sur l'application
|
| 321 |
+
st.sidebar.markdown("---")
|
| 322 |
+
st.sidebar.info("""
|
| 323 |
+
**À propos de cette application**
|
| 324 |
+
|
| 325 |
+
Cette application analyse les tendances YouTube de 2025 basées sur les chaînes qui ont été en tendance.
|
| 326 |
+
|
| 327 |
+
**Fonctionnalités :**
|
| 328 |
+
- Filtrage par catégorie, date, chaîne et jour
|
| 329 |
+
- Indicateurs clés de performance
|
| 330 |
+
- Visualisations interactives
|
| 331 |
+
- Analyse temporelle
|
| 332 |
+
- Export des données
|
| 333 |
+
|
| 334 |
+
Créé avec Streamlit et Plotly.
|
| 335 |
+
""")
|
| 336 |
+
|
| 337 |
+
# Statistiques globales en bas de page
|
| 338 |
+
with st.expander("📊 Statistiques globales du dataset"):
|
| 339 |
+
st.write(f"**Nombre total de vidéos :** {len(df):,}")
|
| 340 |
+
st.write(f"**Nombre de chaînes uniques :** {df['Channel_name'].nunique() if 'Channel_name' in df.columns else 'N/A'}")
|
| 341 |
+
st.write(f"**Nombre de catégories :** {df['Category name'].nunique() if 'Category name' in df.columns else 'N/A'}")
|
| 342 |
+
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'}")
|
category.csv
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
ID;Category name
|
| 2 |
+
1;Film & Animation
|
| 3 |
+
2;Autos & Vehicles
|
| 4 |
+
10;Music
|
| 5 |
+
15;Pets & Animals
|
| 6 |
+
17;Sports
|
| 7 |
+
19;Travel & Events
|
| 8 |
+
20;Gaming
|
| 9 |
+
22;People & Blogs
|
| 10 |
+
23;Comedy
|
| 11 |
+
24;Entertainment
|
| 12 |
+
25;News & Politics
|
| 13 |
+
26;Howto & Style
|
| 14 |
+
27;Education
|
| 15 |
+
28;Science & Technology
|
| 16 |
+
29;Nonprofits & Activism
|
requirements.txt
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
streamlit==1.29.0
|
| 2 |
+
pandas==2.1.4
|
| 3 |
+
numpy==1.26.2
|
| 4 |
+
plotly==5.18.0
|
youtube_channels_2025.csv
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:a36b0a503e5ee599fa13d2ba689508471e6a06333b74f1ab5ba2260f4ed433ba
|
| 3 |
+
size 22927587
|