Spaces:
Sleeping
Sleeping
File size: 5,849 Bytes
e820479 |
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 |
import io
import time
import pandas as pd
import numpy as np
import streamlit as st
try:
from sdv.evaluation.single_table import evaluate
except Exception:
evaluate = None
st.set_page_config(page_title="Data Synthesizer Studio (Upload Only)", layout="wide")
st.title("🧪 Data Synthesizer Studio — Upload Only (CPU)")
st.write("""
**Genera datos sintéticos** a partir de tu CSV.
Esta versión **no carga archivos de ejemplo**: debes **subir un archivo** para continuar.
""")
with st.expander("ℹ️ Instrucciones"):
st.markdown("""
1. Sube un **CSV** pequeño (≤ 2–3 MB) con columnas numéricas y/o categóricas.
2. Elige el **modelo** (CTGAN/TVAE/ GaussianCopula).
3. Ajusta parámetros ligeros y presiona **Entrenar**.
4. Compara distribuciones y **descarga** el CSV sintético.
""")
# =============== Helpers ===============
def get_model(model_name: str, epochs: int, batch_size: int):
"""
Importación perezosa para evitar requerir torch si se usa GaussianCopula.
"""
name = model_name.lower()
if name == "ctgan":
from sdv.tabular import CTGAN # requiere torch
return CTGAN(epochs=epochs, batch_size=batch_size, verbose=True)
elif name == "tvae":
from sdv.tabular import TVAE # requiere torch
return TVAE(epochs=epochs, batch_size=batch_size, verbose=True)
else:
from sdv.tabular import GaussianCopula # no requiere torch
return GaussianCopula()
# =============== Layout ===============
left, right = st.columns([1, 1])
with left:
st.subheader("📥 1) Sube tu CSV")
up = st.file_uploader("Selecciona un archivo .csv", type=["csv"], key="csv_uploader")
df_real = None # se mantiene None hasta que haya archivo
if up is not None:
file_bytes = up.getvalue()
try:
# Autodetección de separador
df_real = pd.read_csv(io.BytesIO(file_bytes), sep=None, engine="python")
except Exception:
# Fallbacks comunes
try:
df_real = pd.read_csv(io.BytesIO(file_bytes), sep=";")
except Exception:
df_real = pd.read_csv(io.BytesIO(file_bytes), sep=",")
st.success(f"✅ Cargado: {df_real.shape[0]} filas × {df_real.shape[1]} columnas")
st.dataframe(df_real.head())
# Limpieza mínima
df_real = df_real.dropna(axis=1, how="all")
if df_real.shape[1] > 25:
df_real = df_real.iloc[:, :25]
st.info("Se detectaron muchas columnas. Para este demo se usan solo las primeras 25.")
else:
st.info("Sube un CSV para continuar.")
with right:
st.subheader("⚙️ 2) Modelo y parámetros")
model_name = st.selectbox("Modelo", ["CTGAN", "TVAE", "GaussianCopula"])
epochs = st.slider("Epochs (demo CPU)", 1, 25, 10, 1)
batch_size = st.select_slider("Batch size", options=[32, 64, 128, 256], value=64)
sample_size = st.slider("Filas sintéticas a generar", 100, 5000, 1000, 100)
st.caption("💡 Sugerencia: mantén `epochs` bajos en CPU para evitar timeouts.")
# =============== Train ===============
st.subheader("🚀 3) Entrenamiento y generación")
train_btn = st.button("Entrenar modelo y generar datos sintéticos")
if train_btn:
# Guardrails
df_train = df_real.copy()
if df_train.shape[1] >= 40 and sample_size > 2000:
sample_size = 2000
st.warning("Muchas columnas detectadas; se limita sample_size a 2000.")
# Construir modelo
try:
model = get_model(model_name, epochs=epochs, batch_size=batch_size)
except Exception as e:
st.error("No se pudo inicializar el modelo. Posible falta de dependencias (torch para CTGAN/TVAE).")
st.code(str(e))
st.stop()
with st.spinner("Entrenando modelo…"):
t0 = time.time()
model.fit(df_train)
dt = time.time() - t0
st.success(f"✅ Entrenamiento completado en {dt:.1f} s")
with st.spinner("Generando datos sintéticos…"):
df_syn = model.sample(sample_size)
st.write("### 📤 Muestra de datos sintéticos")
st.dataframe(df_syn.head())
st.write("### 📊 Evaluación de calidad (SDV evaluate)")
if evaluate is None:
st.info("`evaluate` no disponible en esta versión de SDV; omitiendo evaluación.")
else:
try:
score = evaluate(df_syn, df_train)
st.metric("Puntaje de similitud", f"{score:.3f}", help="0–1 (1 = distribuciones idénticas)")
except Exception as e:
st.warning(f"No se pudo calcular `evaluate`: {e}")
st.write("### 🔎 Comparación univariante (hasta 6 columnas)")
cols = df_train.columns[:6]
tabs = st.tabs([str(c) for c in cols])
for i, c in enumerate(cols):
with tabs[i]:
c1, c2 = st.columns(2)
with c1:
st.write("Real")
if pd.api.types.is_numeric_dtype(df_train[c]):
st.bar_chart(df_train[c].dropna().value_counts(bins=20))
else:
st.bar_chart(df_train[c].astype(str).value_counts().head(30))
with c2:
st.write("Sintético")
if c in df_syn.columns:
if pd.api.types.is_numeric_dtype(df_syn[c]):
st.bar_chart(df_syn[c].dropna().value_counts(bins=20))
else:
st.bar_chart(df_syn[c].astype(str).value_counts().head(30))
else:
st.info("Columna no generada.")
st.write("### 💾 Descargar CSV sintético")
buf = io.StringIO()
df_syn.to_csv(buf, index=False)
st.download_button(
"Descargar synthetic.csv",
data=buf.getvalue().encode("utf-8"),
file_name="synthetic.csv",
mime="text/csv"
) |