LAST / app.py
LEWOPO's picture
Update app.py
5588725 verified
raw
history blame
15 kB
import streamlit as st
from streamlit_option_menu import option_menu
import pandas as pd
import pickle
import lime
import lime.lime_tabular
import streamlit.components.v1 as components
from PIL import Image
import seaborn as sns
import matplotlib.pyplot as plt
from datetime import datetime
# 1=sidebar menu, 2=horizontal menu, 3=horizontal menu w/ custom menu
EXAMPLE_NO = 3
st.set_page_config(layout='wide')
st.markdown("""
<style>
.block-container {
padding-top: 4rem;
padding-bottom: 0rem;
padding-left: 4rem;
padding-right: 4rem;
}
</style>
""", unsafe_allow_html=True)
def streamlit_menu(example=1):
if example == 1:
# 1. as sidebar menu
with st.sidebar:
selected = option_menu(
menu_title="Main Menu", # required
options=["Acceuil", "Statistique", "Prédiction", "Suivi"], # required
icons=["house", "book", "envelope", "clipboard-data"], # optional
menu_icon="cast", # optional
default_index=0, # optional
)
return selected
if example == 2:
# 2. horizontal menu w/o custom style
selected = option_menu(
menu_title=None, # required
options=["Acceuil", "Statistique", "Prédiction", "Suivi"], # required
icons=["house", "bar-chart", "activity", "clipboard"], # optional
menu_icon="cast", # optional
default_index=0, # optional
orientation="horizontal",
)
return selected
if example == 3:
# 2. horizontal menu with custom style
selected = option_menu(
menu_title=None, # required
options=["Acceuil", "Statistique", "Prédiction", "Suivi"], # required
icons=["house", "bar-chart", "activity", "clipboard"], # optional
menu_icon="cast", # optional
default_index=0, # optional
orientation="horizontal",
styles={
"container": {"padding": "0!important", "background-color": "#fafafa"},
"icon": {"color": "orange", "font-size": "25px"},
"nav-link": {
"font-size": "25px",
"text-align": "left",
"margin": "0px",
"--hover-color": "#eee",
},
"nav-link-selected": {"background-color": "skyblue"},
},
)
return selected
selected = streamlit_menu(example=EXAMPLE_NO)
if selected == "Prédiction":
# st.title(f"You have selected {selected}")
# Load your trained model
with open('model.pkl', 'rb') as file:
model = pickle.load(file)
obesity_mapping = {
0: 'Normal',
1: 'Surpoid\Obése'
}
# Define the input features for the user to input
def user_input_features():
age = st.number_input('Age:',min_value=8, max_value=19, value=19, step=1, format="%d")
classe = st.radio('Classe_', ('Primaire','Secondaire'))
Zone = st.radio('zone', ('Rurale', 'Urbaine'))
Voler = st.radio('Voler', ('Oui', 'Non'))
Diversité = st.radio('Diversité', ('Mauvaise', 'Bonne'))
Region = st.selectbox(
'Region de ',
('Nord_ouest' ,'Sud_ouest', 'Ouest')
)
Source_eau=st.selectbox(
'Provenence ',
('Camwater','Eau_de_surface','forage','Puits','Eau_minérale')
)
Sexe = st.radio('Genre', ('F', 'M'))
Zone = 1 if Zone == 'Rurale' else 0
classe = 1 if classe == 'Primaire' else 0
Diversité = 1 if Diversité == 'Mauvaise' else 0
Region = ['Nord_ouest' ,'Sud_ouest', 'Ouest'].index(Region)
Source_eau=['Camwater','Eau_de_surface','forage','Puits','Eau_minérale'].index(Source_eau)
sex_f = 1 if Sexe == 'F' else 0
sex_m = 1 if Sexe == 'M' else 0
data = {
'Region': Region,
'Zone': Zone,
'Classe': classe,
'Age': age,
'Diversité': Diversité,
'Voler': Voler,
'Source_eau':Source_eau,
'Genre_F': sex_f,
'Genre_M': sex_m
}
features = pd.DataFrame(data, index=[0])
return features
# st.title('Obesity App')
# Display the input fields
input_df = user_input_features()
# Convertir toutes les colonnes non numériques en numérique si possible
input_df = input_df.apply(pd.to_numeric, errors='coerce')
# Remplacer les NaN par une valeur arbitraire (par exemple 0) si nécessaire
input_df = input_df.fillna(0)
# Initialiser LIME
explainer = lime.lime_tabular.LimeTabularExplainer(
training_data=input_df.values, # Entraînement sur la base des données d'entrée
feature_names=input_df.columns,
class_names=[obesity_mapping[0], obesity_mapping[1]],
mode='classification'
)
# Predict button
if st.button('Predict'):
# Make a prediction
prediction = model.predict(input_df)
prediction_proba = model.predict_proba(input_df)[0]
data = {
'Statut nutritionnel': [obesity_mapping[i] for i in range(len(prediction_proba))],
'Probabilité': prediction_proba
}
# Create a dataframe to display the results
result_df = pd.DataFrame(data)
# Transpose the dataframe to have obesity types as columns and add a row header
result_df = result_df.T
result_df.columns = result_df.iloc[0]
result_df = result_df.drop(result_df.index[0])
result_df.index = ['Probability']
# Display the results in a table with proper formatting
st.table(result_df.style.format("{:.4f}"))
# Générer l'explication LIME pour l'individu
# exp = explainer.explain_instance(input_df.values[0], model.predict_proba, num_features=5)
# # Afficher les explications dans Streamlit
# st.subheader('Explication LIME')
# exp.show_in_notebook(show_table=True, show_all=False)
# st.write(exp.as_list())
# Générer l'explication LIME pour l'individu
exp = explainer.explain_instance(input_df.values[0], model.predict_proba, num_features=4)
# Récupérer l'explication LIME sous forme HTML
explanation_html = exp.as_html()
# Afficher l'explication LIME dans Streamlit
st.subheader('Explication LIME')
# Utiliser Streamlit pour afficher du HTML
components.html(explanation_html, height=800) # Ajuster la hauteur selon le contenu
if selected == "Acceuil":
avant_propos = """
<div style="background-color: white; padding: 20px; border-radius: 10px;
display: flex; justify-content: center; align-items: center;
width: 800px; height: auto; margin: auto; flex-direction: column;
box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.1);">
<h2 style="color: blue; text-align: center; font-size: 24px;">Avant-propos</h2>
<p style="color: blue; text-align: center; font-size: 17px;">
L'obésité est l'une des principales préoccupations de santé publique à travers le monde, avec des répercussions notables sur la qualité de vie et les coûts des soins de santé.
Dans un contexte où les maladies chroniques liées à l'obésité, telles que le diabète et les maladies cardiovasculaires, continuent de croître, il est impératif de développer des outils capables de prédire et de prévenir cette condition.
</p>
<p style="color: blue; text-align: center; font-size: 16px;">
L'application que nous présentons ici repose sur les technologies modernes de <strong>machine learning</strong> pour prédire le risque d'obésité à partir de divers facteurs liés au mode de vie,
aux habitudes alimentaires et aux caractéristiques individuelles. Cette solution, développée à l'aide de <strong>Streamlit</strong>, permet non seulement d'offrir une interface intuitive et accessible,
mais également d'analyser rapidement et précisément les données des utilisateurs afin d'anticiper les risques associés au surpoids.
</p>
<p style="color: blue; text-align: center; font-size: 16px;">
L'objectif principal de cette application est de fournir une aide à la décision pour les professionnels de santé, les chercheurs, et même les utilisateurs individuels
qui souhaitent comprendre et gérer leur risque personnel. En quelques clics, les utilisateurs peuvent explorer les facteurs influents et recevoir des prévisions basées sur des algorithmes avancés d'apprentissage automatique.
</p>
<p style="color: blue; text-align: center; font-size: 16px;">
Cette application permet aussi de faire un suivi personnalisé sur l'indice de masse corporelle, precisement de
son statut nutritionnel.
</p>
</div>
"""
# Afficher le texte stylisé en bleu et centré sur un fond blanc
st.markdown(avant_propos, unsafe_allow_html=True)
# Ajouter un bouton qui redirige vers un site externe
url = "https://www.who.int/fr/news-room/fact-sheets/detail/obesity-and-overweight" # Remplacez par l'URL souhaitée
if st.button("pour plus d'informations"):
st.write(f"[Cliquez ici pour visiter le site]({url})")
if selected == "Statistique":
# Ouvrir l'image avec Pillow
#image = Image.open("az.JPEG")
# Redimensionner l'image (largeur, hauteur)
#image = image.resize((300, 200)) # Par exemple, 300x200 pixels
# Afficher l'image redimensionnée
#st.image(image, caption="Image redimensionnée", use_column_width=False)
# Titre de l'application
st.title("Visualisation des données avec Seaborn et Pandas")
# Charger le fichier CSV
uploaded_file = st.file_uploader("Choisissez un fichier", type=["csv", "xlsx", "json"])
if uploaded_file is not None:
# Lecture du fichier CSV
file_extension = uploaded_file.name.split('.')[-1]
if file_extension == 'csv':
# Lecture du fichier CSV
df = pd.read_csv(uploaded_file)
elif file_extension == 'xlsx':
# Lecture du fichier Excel
df = pd.read_excel(uploaded_file)
elif file_extension == 'json':
# Lecture du fichier JSON
df = pd.read_json(uploaded_file)
else:
st.error("Format de fichier non supporté!")
# Afficher le dataframe
st.write("Aperçu du dataset :")
st.write(df.head())
# Afficher les statistiques descriptives
st.write("Statistiques descriptives :")
st.write(df.describe())
# Sélection des variables pour les visualisations
numerical_columns = df.select_dtypes(include=['float64', 'int64']).columns.tolist()
categorical_columns = df.select_dtypes(include=['object', 'category']).columns.tolist()
# Distribution d'une variable
st.subheader("Distribution d'une variable numérique")
selected_column = st.selectbox("Choisissez une variable numérique", numerical_columns)
if st.button("Afficher la distribution"):
fig, ax = plt.subplots(figsize=(5, 6))
sns.histplot(df[selected_column], kde=True, ax=ax)
st.pyplot(fig)
# Scatter plot
st.subheader("Scatter Plot entre deux variables numériques")
x_axis = st.selectbox("Choisissez la variable pour l'axe X", numerical_columns)
y_axis = st.selectbox("Choisissez la variable pour l'axe Y", numerical_columns, key='scatter')
if st.button("Afficher le scatter plot"):
fig, ax = plt.subplots(figsize=(8, 4))
sns.scatterplot(x=df[x_axis], y=df[y_axis], ax=ax)
st.pyplot(fig)
# Boxplot
st.subheader("Boxplot d'une variable numérique par rapport à une variable catégorielle")
selected_categorical = st.selectbox("Choisissez une variable catégorielle", categorical_columns)
selected_numerical = st.selectbox("Choisissez une variable numérique", numerical_columns, key='boxplot')
if st.button("Afficher le boxplot"):
fig, ax = plt.subplots(figsize=(8, 4))
sns.boxplot(x=df[selected_categorical], y=df[selected_numerical], ax=ax)
st.pyplot(fig)
if selected == "Suivi":
# Charger ou initialiser les données de suivi
def load_data():
try:
data = pd.read_csv('imc_data.csv')
except FileNotFoundError:
data = pd.DataFrame(columns=['Date', 'Weight', 'Height', 'BMI', 'Status'])
return data
def save_data(data):
data.to_csv('imc_data.csv', index=False)
# Calculer l'IMC et le statut nutritionnel
def calculate_bmi(weight, height):
return weight / (height ** 2)
def get_nutritional_status(bmi):
if bmi < 18.5:
return "Insuffisance pondérale"
elif 18.5 <= bmi < 25:
return "Poids normal"
elif 25 <= bmi < 30:
return "Surpoids"
else:
return "Obésité"
# Interface utilisateur Streamlit
st.title("Suivi de l'IMC et du Statut Nutritionnel")
# Collecte des données utilisateur
weight = st.number_input("Poids (en kg)", min_value=30.0, max_value=200.0, value=70.0)
height = st.number_input("Taille (en mètres)", min_value=1.0, max_value=2.5, value=1.75)
# Calculer l'IMC et le statut nutritionnel
if height > 0:
bmi = calculate_bmi(weight, height)
status = get_nutritional_status(bmi)
st.write(f"Votre IMC est : {bmi:.2f}")
st.write(f"Statut nutritionnel : {status}")
# Charger et mettre à jour les données de suivi
data = load_data()
if st.button("Enregistrer vos données"):
new_entry = pd.DataFrame({
'Date': [datetime.now().strftime("%Y-%m-%d %H:%M:%S")],
'Weight': [weight],
'Height': [height],
'BMI': [bmi],
'Status': [status]
})
data = pd.concat([data, new_entry], ignore_index=True)
save_data(data)
st.success("Vos données ont été enregistrées avec succès !")
# Afficher l'évolution de l'IMC
if not data.empty:
st.subheader("Évolution de votre IMC")
data['Date'] = pd.to_datetime(data['Date'])
plt.figure(figsize=(10, 6))
plt.plot(data['Date'], data['BMI'], marker='o')
plt.title("Évolution de l'IMC")
plt.xlabel("Date")
plt.ylabel("IMC")
plt.grid(True)
st.pyplot(plt)
# Afficher l'historique des données soumises
st.subheader("Historique des données soumises")
st.dataframe(data[['Date', 'Weight', 'Height', 'BMI', 'Status']])
else:
st.warning("Veuillez entrer une taille valide pour calculer l'IMC.")