Spaces:
Sleeping
Sleeping
File size: 9,196 Bytes
8817849 a860e2e 4b29ff0 44e2991 4b29ff0 c051e07 8817849 7af98ed c051e07 44e2991 c051e07 8817849 c051e07 44e2991 c051e07 44e2991 c051e07 44e2991 c051e07 44e2991 c051e07 44e2991 c051e07 44e2991 c051e07 8817849 c051e07 44e2991 c051e07 728a360 a860e2e 44e2991 c051e07 02e7211 c051e07 44e2991 a860e2e 44e2991 c051e07 44e2991 c051e07 44e2991 c051e07 44e2991 c051e07 44e2991 c051e07 44e2991 c051e07 44e2991 c051e07 44e2991 c051e07 44e2991 c051e07 44e2991 c051e07 44e2991 c051e07 44e2991 c051e07 44e2991 c051e07 8817849 c051e07 44e2991 c051e07 44e2991 c051e07 44e2991 c051e07 44e2991 c051e07 8817849 c051e07 44e2991 c051e07 8817849 02e7211 8817849 |
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 |
import streamlit as st
import pandas as pd
import duckdb
import polars as pl
import time
import os
import matplotlib.pyplot as plt
import numpy as np
import tempfile
from io import BytesIO
# Configuration de la page Streamlit
st.set_page_config(
page_title="Comparaison de vitesse de chargement des données",
layout="wide"
)
# --- FONCTION DE CHARGEMENT TECHNIQUE ---
def load_file_and_measure_time(file_path, library, file_ext, read_kwargs):
try:
start_time = time.time()
df = None
# --- PARQUET ---
if file_ext == '.parquet':
if library == 'pandas':
df = pd.read_parquet(file_path)
elif library == 'pyarrow':
df = pd.read_parquet(file_path, engine='pyarrow')
elif library == 'duckdb':
con = duckdb.connect()
df = con.execute(f"SELECT * FROM read_parquet('{file_path}')").fetchdf()
con.close()
elif library == 'polars':
df = pl.read_parquet(file_path)
# --- EXCEL ---
elif file_ext in ['.xlsx', '.xls']:
sheet_idx = read_kwargs.get('sheet_idx', 0)
header = 0 if read_kwargs.get('header') else None
if library in ['pandas', 'pyarrow']:
df = pd.read_excel(file_path, sheet_name=sheet_idx, header=header)
elif library == 'duckdb':
df = pd.read_excel(file_path, sheet_name=sheet_idx, header=header)
elif library == 'polars':
df = pl.read_excel(file_path, sheet_id=sheet_idx + 1)
# --- CSV ---
else:
header_val = 0 if read_kwargs.get('header') else None
if library == 'pandas':
df = pd.read_csv(file_path, sep=None, engine='python', header=header_val)
elif library == 'pyarrow':
df = pd.read_csv(file_path, sep=None, engine='python', header=header_val, dtype_backend='pyarrow')
elif library == 'duckdb':
con = duckdb.connect()
header_flag = "TRUE" if read_kwargs.get('header') else "FALSE"
df = con.execute(f"SELECT * FROM read_csv_auto('{file_path}', HEADER={header_flag})").fetchdf()
con.close()
elif library == 'polars':
df = pl.read_csv(file_path, has_header=read_kwargs.get('header'))
end_time = time.time()
return end_time - start_time, len(df)
except Exception as e:
return f"Erreur: {e}", 0
# --- FONCTION POUR CHARGER DEPUIS UN BUFFER UPLOADÉ ---
def load_from_buffer(uploaded_file, library, file_ext, read_kwargs):
"""Charge un fichier depuis un buffer Streamlit et mesure le temps"""
try:
# Créer un fichier temporaire
with tempfile.NamedTemporaryFile(delete=False, suffix=file_ext) as tmp_file:
tmp_file.write(uploaded_file.getvalue())
tmp_path = tmp_file.name
# Utiliser la fonction existante avec le fichier temporaire
load_time, row_count = load_file_and_measure_time(tmp_path, library, file_ext, read_kwargs)
# Nettoyer le fichier temporaire
os.unlink(tmp_path)
return load_time, row_count
except Exception as e:
return f"Erreur: {e}", 0
# --- GESTION DU FICHIER CIBLE DANS LE SESSION STATE ---
if 'target_file' not in st.session_state:
st.session_state.target_file = None
if 'file_ext' not in st.session_state:
st.session_state.file_ext = None
if 'uploaded_buffer' not in st.session_state:
st.session_state.uploaded_buffer = None
st.title("⚡ Comparaison de vitesse de chargement des données")
st.markdown("Téléchargez un fichier **CSV, Excel ou Parquet** pour comparer **Pandas**, **PyArrow**, **DuckDB** et **Polars**.")
# --- SIDEBAR ---
st.sidebar.header("⚙️ Paramètres du fichier")
# CSS global pour les boutons
st.markdown(
"""
<style>
.stButton > button {
height: 80px !important;
}
</style>
""",
unsafe_allow_html=True
)
# Boutons de démo
st.sidebar.subheader("🧪 Fichiers de test (30Mo)")
c1, c2 = st.sidebar.columns(2)
if c1.button("📄 Faker Text"):
if os.path.exists("faker_text.csv"):
st.session_state.target_file = "faker_text.csv"
st.session_state.file_ext = ".csv"
# Vérification des dimensions
try:
test_df = pd.read_csv("faker_text.csv", nrows=5)
st.sidebar.info(f"✅ Fichier détecté : {len(pd.read_csv('faker_text.csv'))} lignes, {len(test_df.columns)} colonnes")
except:
pass
else:
st.sidebar.error("❌ Fichier faker_text.csv introuvable à la racine")
if c2.button("📊 Numeric Only"):
if os.path.exists("numeric_only.csv"):
st.session_state.target_file = "numeric_only.csv"
st.session_state.file_ext = ".csv"
# Vérification des dimensions
try:
test_df = pd.read_csv("numeric_only.csv", nrows=5)
st.sidebar.info(f"✅ Fichier détecté : {len(pd.read_csv('numeric_only.csv'))} lignes, {len(test_df.columns)} colonnes")
except:
pass
else:
st.sidebar.error("❌ Fichier numeric_only.csv introuvable à la racine")
# Uploader manuel
uploaded_file = st.sidebar.file_uploader("Ou choisissez un fichier", type=["csv", "parquet", "xlsx", "xls"])
if uploaded_file is not None:
try:
file_ext = os.path.splitext(uploaded_file.name)[1].lower()
# Stockage du buffer dans session_state
st.session_state.uploaded_buffer = uploaded_file
st.session_state.target_file = "uploaded_file" # Marqueur pour savoir qu'on a un upload
st.session_state.file_ext = file_ext
# Afficher la taille du fichier uploadé
file_size_mb = uploaded_file.size / (1024 * 1024)
st.sidebar.success(f"✅ Fichier uploadé : {uploaded_file.name} ({file_size_mb:.2f} Mo)")
except Exception as e:
st.sidebar.error(f"❌ Erreur lors de l'upload : {str(e)}")
# --- ACTIONS ET AFFICHAGE ---
if st.session_state.target_file is not None:
st.sidebar.success(f"Actif : **{st.session_state.target_file}**")
has_header = st.sidebar.radio("Ligne de titres en première ligne ?", ["Oui", "Non"], index=0) == "Oui"
read_kwargs = {'header': has_header}
if st.session_state.file_ext in ['.xlsx', '.xls']:
sheet_num = st.sidebar.number_input("Numéro de l'onglet (1 = premier)", min_value=1, value=1)
read_kwargs['sheet_idx'] = sheet_num - 1
run_comparison = st.sidebar.button("Lancer la comparaison")
if run_comparison:
st.subheader("⏱️ Résultats de la vitesse de chargement")
libraries = {'Pandas (Baseline)': 'pandas', 'PyArrow': 'pyarrow', 'DuckDB': 'duckdb', 'Polars': 'polars'}
results = []
for lib_name, lib_key in libraries.items():
with st.spinner(f"Test en cours : **{lib_name}**..."):
# Choix de la fonction selon la source
if st.session_state.target_file == "uploaded_file" and st.session_state.uploaded_buffer is not None:
# Fichier uploadé : passer directement l'objet uploaded_file
load_time, row_count = load_from_buffer(st.session_state.uploaded_buffer, lib_key, st.session_state.file_ext, read_kwargs)
else:
# Fichier de test : utiliser le chemin
load_time, row_count = load_file_and_measure_time(st.session_state.target_file, lib_key, st.session_state.file_ext, read_kwargs)
results.append({'Librairie': lib_name, 'Temps de chargement (s)': load_time, 'Nombre de lignes': row_count})
results_df = pd.DataFrame(results)
valid_counts = results_df[results_df['Nombre de lignes'] > 0]['Nombre de lignes']
if not valid_counts.empty:
st.markdown(f"**Nombre de lignes détectées :** **{int(valid_counts.iloc[0]):,}**".replace(',', ' '))
chart_data = results_df[results_df['Temps de chargement (s)'].apply(lambda x: isinstance(x, (int, float)))]
if not chart_data.empty:
chart_data = chart_data.sort_values(by='Temps de chargement (s)', ascending=True)
fig, ax = plt.subplots(figsize=(8, 2.5))
bars = ax.barh(chart_data['Librairie'], chart_data['Temps de chargement (s)'],
color=['#4CAF50', '#2196F3', '#FFC107', '#E91E63'])
max_time = chart_data['Temps de chargement (s)'].max()
ax.set_xlim(right=max_time * 1.35)
for bar in bars:
ax.text(bar.get_width() + (max_time * 0.03), bar.get_y() + bar.get_height()/2,
f'{bar.get_width():.4f}s', va='center', fontsize=10, fontweight='bold')
ax.set_xlabel('Temps (secondes)')
ax.set_title('Comparaison des vitesses de lecture')
st.pyplot(fig)
plt.close(fig)
else:
st.info("Veuillez charger un fichier ou utiliser un bouton de test à gauche.")
|