Spaces:
Running
Running
| 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:") |