iedda-predict / app.py
javifmz's picture
Update app.py
df181b5 verified
import time
import streamlit as st
import pandas as pd
import altair as alt
import matplotlib.pyplot as plt
st.markdown("""
<style>
h1 {
padding-top: 0px !important;
}
</style>
<div class="custom-container">
""", unsafe_allow_html=True)
st.write('__INVESTIGACIÓN EN ENTORNOS DIGITALES, DATA Y ANALÍTICA__')
st.title('Mi primera predicción')
'''
👋 ¡Hola! Bienvenid@ a esta introducción a la __predicción de datos__.
Con esta aplicación web podrás subir un archivo con __ejemplos__ de los que quieres aprender,
realizar un breve __análisis exploratorio__ de variables y entrenar un modelo de __predicción__ sencillo.
'''
#----------------------------------------
# Cargar datos
#----------------------------------------
st.header('Carga de datos')
file = st.file_uploader("Archivo CSV", type=["csv"])
if file is None :
st.info('Para empezar, sube un archivo en __formato CSV__. Asegúrate de que el archivo no sea demasiado grande (menos de 2 MB) y que contenga una variable objetivo que quieras predecir.', icon=":material/north:")
st.stop()
# st.write("XSRF:", st.get_option("server.enableXsrfProtection"))
st.success(f"Archivo __{file.name}__ subido con éxito (también se han limpiado los datos inválidos)", icon=":material/check:")
df = pd.read_csv(file)
df = df.dropna()
num_rows, num_cols = df.shape
num_numeric_cols = df.select_dtypes(include='number').shape[1]
num_categorial_cols = df.columns.size - num_numeric_cols
col1, col2, col3, col4 = st.columns(4)
col1.container(border=True).metric("Ejemplos", f"{num_rows}")
col2.container(border=True).metric("Variables", f"{num_cols}")
col3.container(border=True).metric("Variables numéricas", f"{num_numeric_cols}")
col4.container(border=True).metric("Variables categóricas", f"{num_categorial_cols}")
with st.expander('Ver cómo son los datos (50 primeros)') :
st.dataframe(df.head(50))
#----------------------------------------
# Seleccionar variable objetivo
#----------------------------------------
st.header('Variable objetivo')
target = st.selectbox("Variable objetivo", df.columns, index=None)
if target is None:
st.info('El siguiente paso es seleccionar la variable que queremos predecir a partir de las demás, que se denomina __variable objetivo__. Elige una del desplegable.', icon=":material/north:")
st.stop()
is_numeric = pd.api.types.is_numeric_dtype(df[target])
if is_numeric :
st.success(f"Has seleccionado _{target}_, que es una variable __numérica__", icon=':material/check:')
else:
st.success(f"Has seleccionado _{target}_, que es una variable __categórica__", icon=':material/check:')
st.caption(f'Distribución de la variable objetivo __{target}__')
if is_numeric :
chart = alt.Chart(df).mark_bar().encode(
x=alt.X(f'{target}:Q', bin=alt.Bin(maxbins=30)),
y='count()',
).properties(
height=300
)
st.altair_chart(chart, width='stretch')
else:
chart = alt.Chart(df).mark_bar().encode(
x=alt.X(f'{target}:N', sort='-y').axis(labelAngle=0),
y='count()',
).properties(
height=300
)
st.altair_chart(chart, width='stretch')
#----------------------------------------
# Preprocesamiento
#----------------------------------------
X_raw = df.drop(columns=[target])
y = df[target]
X = pd.get_dummies(X_raw, drop_first=True)
st.success(f'Se han eliminado __valores inválidos__ (sin valor) y se han convertido el resto de variables en __variables numéricas__ (importante para poder aprender y hacer predicciones)', icon=":material/check:")
with st.expander('Ver como han quedado los datos (50 primeros)') :
st.dataframe(X.head(50))
#----------------------------------------
# Análisis exploratorio
#----------------------------------------
st.header('Análisis exploratorio')
f'''
Abajo tienes la lista de variables y su relación con la variable objetivo _{target}_. Cuanto más alto el valor, más afecta la variable a la variable objetivo _{target}_.
'''
if is_numeric :
from sklearn.feature_selection import mutual_info_regression
scores = mutual_info_regression(X, y, random_state=42)
else :
from sklearn.feature_selection import mutual_info_classif
scores = mutual_info_classif(X, y, random_state=42)
df_features = pd.DataFrame({
'Variable': X.columns,
'Importancia': scores,
}).sort_values('Importancia', ascending=False)
st.dataframe(
df_features,
column_config={
# 'Importancia': st.column_config.ProgressColumn('Importancia', min_value=0, max_value=df_features['Importancia'].max()),
'Importancia': st.column_config.ProgressColumn('Importancia', min_value=0, max_value=df_features['Importancia'].max(), format='%.2f'),
},
use_container_width=True
)
st.caption(':material/info: La primera barra siempre aparece llena, se pone a modo de comparación')
selected = st.multiselect('Variables para el entrenamiento',
options=X.columns,
)
if len(selected) == 0 :
st.info('Tras los resultados del análisis exploratorio, elige qué __variables__ utilizarás para el __entrenamiento__ del modelo. Cuantas más pongas, menos eficiente será, y poner más variables no es sinónimo de mejores resultados (pero normalmente ayuda).', icon=":material/north:")
st.stop()
X_selected = X[selected]
st.success(f'Has elegido __{len(selected)} {"variables" if len(selected) > 1 else "variable"}__ para el entrenamiento (las demás se han eliminado)', icon=":material/check:")
with st.expander('Ver como han quedado los datos (50 primeros)') :
st.dataframe(pd.concat([X_selected.head(50), y.loc[X_selected.head(50).index]], axis=1))
#----------------------------------------
# Entrenamiento
#----------------------------------------
st.header('Entrenamiento')
if is_numeric :
algorithm = st.selectbox("Algoritmo de aprendizaje automático",
options=[
"Regresión lineal",
"Árbol de decisión",
], index=None
)
else :
algorithm = st.selectbox("Algoritmo de aprendizaje automático",
options=[
"Máquinas de soporte vectorial",
"Naive Bayes",
"Árbol de decisión",
], index=None
)
if algorithm is None :
st.info('Elige un algoritmo de __aprendizaje automático__', icon=":material/north:")
st.stop()
st.success(f'Has seleccionado el algoritmo __{algorithm}__')
from sklearn.model_selection import train_test_split
train, test = train_test_split(X_selected, test_size=0.2, random_state=42)
if is_numeric :
from sklearn.metrics import r2_score
if algorithm == "Regresión lineal" :
from sklearn.linear_model import LinearRegression
model = LinearRegression()
elif algorithm == "Árbol de decisión" :
from sklearn.tree import DecisionTreeRegressor
model = DecisionTreeRegressor(random_state=42)
ellapsed = time.time()
model.fit(train, y.loc[train.index])
y_pred = model.predict(test)
ellapsed = time.time() - ellapsed
r2 = r2_score(y.loc[test.index], y_pred) * 100
r2 = max(r2, 0)
col1, col2, col3 = st.columns(3)
col1.container(border=True).metric("Calidad (R²)", f"{r2:.1f}%")
col2.container(border=True).metric("Tiempo (s)", f"{ellapsed:.3f}")
else :
from sklearn.metrics import accuracy_score, classification_report
if algorithm == "Naive Bayes":
from sklearn.naive_bayes import GaussianNB
model = GaussianNB()
elif algorithm == "Árbol de decisión":
from sklearn.tree import DecisionTreeClassifier
model = DecisionTreeClassifier(random_state=42)
elif algorithm == "Máquinas de soporte vectorial":
from sklearn.svm import SVC
model = SVC()
ellapsed = time.time()
model.fit(train, y.loc[train.index])
y_pred = model.predict(test)
ellapsed = time.time() - ellapsed
accuracy = accuracy_score(y.loc[test.index], y_pred) * 100
accuracy = max(accuracy, 0)
col1, col2 = st.columns(2)
col1.container(border=True).metric("Calidad (exactitud)", f"{accuracy:.1f}%")
col2.container(border=True).metric("Tiempo (s)", f"{ellapsed:.3f}")
st.success('¡Modelo entrenado!', icon=':material/check:')
#----------------------------------------
# Predicción
#----------------------------------------
st.header('Predicción')
st.info('Introduce valores para las variables seleccionadas y obtén una predicción', icon=':material/south:')
input_data = {}
for i, col_name in enumerate(selected):
if pd.api.types.is_numeric_dtype(X[col_name]):
input_data[col_name] = st.number_input(col_name, value=float(X[col_name].mean()))
else:
input_data[col_name] = st.selectbox(col_name, X[col_name].unique())
input_df = pd.DataFrame([input_data])
input_df = pd.get_dummies(input_df, drop_first=True)
for col in X_selected.columns:
if col not in input_df.columns:
input_df[col] = 0
input_df = input_df[X_selected.columns]
model.fit(X_selected, y)
if st.button('Realizar predicción', type='primary', icon=":material/wand_stars:", width='stretch') :
prediction = model.predict(input_df)[0]
st.success(f'Predicción: __{prediction:.2f}__' if is_numeric else f'Predicción: __{prediction}__', icon=":material/check:")