|
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 |
|
|
|
|
|
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: |
|
|
|
with st.sidebar: |
|
selected = option_menu( |
|
menu_title="Main Menu", |
|
options=["Acceuil", "Statistique", "Prédiction", "Suivi"], |
|
icons=["house", "book", "envelope", "clipboard-data"], |
|
menu_icon="cast", |
|
default_index=0, |
|
) |
|
return selected |
|
|
|
if example == 2: |
|
|
|
selected = option_menu( |
|
menu_title=None, |
|
options=["Acceuil", "Statistique", "Prédiction", "Suivi"], |
|
icons=["house", "bar-chart", "activity", "clipboard"], |
|
menu_icon="cast", |
|
default_index=0, |
|
orientation="horizontal", |
|
) |
|
return selected |
|
|
|
if example == 3: |
|
|
|
selected = option_menu( |
|
menu_title=None, |
|
options=["Acceuil", "Statistique", "Prédiction", "Suivi"], |
|
icons=["house", "bar-chart", "activity", "clipboard"], |
|
menu_icon="cast", |
|
default_index=0, |
|
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": |
|
|
|
|
|
with open('model.pkl', 'rb') as file: |
|
model = pickle.load(file) |
|
|
|
obesity_mapping = { |
|
0: 'Normal', |
|
1: 'Surpoid\Obése' |
|
} |
|
|
|
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 |
|
|
|
|
|
|
|
|
|
input_df = user_input_features() |
|
|
|
input_df = input_df.apply(pd.to_numeric, errors='coerce') |
|
|
|
|
|
input_df = input_df.fillna(0) |
|
|
|
|
|
explainer = lime.lime_tabular.LimeTabularExplainer( |
|
training_data=input_df.values, |
|
feature_names=input_df.columns, |
|
class_names=[obesity_mapping[0], obesity_mapping[1]], |
|
mode='classification' |
|
) |
|
|
|
|
|
if st.button('Predict'): |
|
|
|
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 |
|
} |
|
|
|
|
|
result_df = pd.DataFrame(data) |
|
|
|
|
|
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'] |
|
|
|
|
|
st.table(result_df.style.format("{:.4f}")) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
exp = explainer.explain_instance(input_df.values[0], model.predict_proba, num_features=4) |
|
|
|
|
|
explanation_html = exp.as_html() |
|
|
|
|
|
st.subheader('Explication LIME') |
|
|
|
|
|
components.html(explanation_html, height=800) |
|
|
|
|
|
|
|
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> |
|
""" |
|
|
|
|
|
st.markdown(avant_propos, unsafe_allow_html=True) |
|
|
|
url = "https://www.who.int/fr/news-room/fact-sheets/detail/obesity-and-overweight" |
|
if st.button("pour plus d'informations"): |
|
st.write(f"[Cliquez ici pour visiter le site]({url})") |
|
if selected == "Statistique": |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
st.title("Visualisation des données avec Seaborn et Pandas") |
|
|
|
|
|
uploaded_file = st.file_uploader("Choisissez un fichier", type=["csv", "xlsx", "json"]) |
|
|
|
if uploaded_file is not None: |
|
|
|
file_extension = uploaded_file.name.split('.')[-1] |
|
if file_extension == 'csv': |
|
|
|
df = pd.read_csv(uploaded_file) |
|
elif file_extension == 'xlsx': |
|
|
|
df = pd.read_excel(uploaded_file) |
|
elif file_extension == 'json': |
|
|
|
df = pd.read_json(uploaded_file) |
|
else: |
|
st.error("Format de fichier non supporté!") |
|
|
|
|
|
|
|
st.write("Aperçu du dataset :") |
|
st.write(df.head()) |
|
|
|
|
|
st.write("Statistiques descriptives :") |
|
st.write(df.describe()) |
|
|
|
|
|
numerical_columns = df.select_dtypes(include=['float64', 'int64']).columns.tolist() |
|
categorical_columns = df.select_dtypes(include=['object', 'category']).columns.tolist() |
|
|
|
|
|
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) |
|
|
|
|
|
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) |
|
|
|
|
|
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": |
|
|
|
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) |
|
|
|
|
|
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é" |
|
|
|
|
|
st.title("Suivi de l'IMC et du Statut Nutritionnel") |
|
|
|
|
|
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) |
|
|
|
|
|
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}") |
|
|
|
|
|
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 !") |
|
|
|
|
|
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) |
|
|
|
|
|
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.") |
|
|