Elegbede commited on
Commit
33b26a5
·
verified ·
1 Parent(s): 87d6ed4

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +165 -2
app.py CHANGED
@@ -1,5 +1,160 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  demo = gr.Interface(
2
- ...
 
 
 
3
  description="""
4
  ⚠️ **DISCLAIMER**: This is a **research prototype** developed using DHS data.
5
  **External validation has not been performed**. This tool is for
@@ -8,6 +163,14 @@ demo = gr.Interface(
8
 
9
  Predicts stunting risk at ages 6, 12, 18, 24, 36, and 48 months using a
10
  Random Survival Forest model.
11
- """
 
 
 
 
 
 
12
  )
13
 
 
 
 
1
+ import gradio as gr
2
+ import joblib
3
+ import numpy as np
4
+ import pandas as pd
5
+ import matplotlib.pyplot as plt
6
+
7
+ # Load model and scaler
8
+ model = joblib.load('rsf_tuned.pkl')
9
+ scaler = joblib.load('scaler.pkl')
10
+
11
+ # --- ORDINAL MAPPINGS ---
12
+ wealth_map = {
13
+ "poorest": 0, "poorer": 1, "middle": 2, "richer": 3, "richest": 4
14
+ }
15
+
16
+ mat_edu_map = {
17
+ "no education": 0, "primary": 1, "secondary": 2, "higher": 3
18
+ }
19
+
20
+ # --- FEATURE NAMES (same as training) ---
21
+ numeric_cols = [
22
+ 'birth_order', 'mat_age', 'mat_height_cm', 'mat_weight_kg',
23
+ 'wealth_ordinal', 'mat_edu_ordinal', 'multiple_birth_binary'
24
+ ]
25
+
26
+ categorical_cols = [
27
+ 'child_sex', 'religion', 'water_improved', 'sanitation_improved',
28
+ 'partner_edu', 'region', 'residence'
29
+ ]
30
+
31
+ cat_feature_names = [
32
+ 'child_sex_female', 'child_sex_male',
33
+ 'religion_catholic', 'religion_islam', 'religion_Not asked/Missing',
34
+ 'religion_other', 'religion_other christian', 'religion_traditionalist',
35
+ 'water_improved_Improved', 'water_improved_Not asked/Missing', 'water_improved_Unimproved',
36
+ 'sanitation_improved_Improved', 'sanitation_improved_Not asked/Missing', 'sanitation_improved_Unimproved',
37
+ 'partner_edu_don\'t know', 'partner_edu_higher', 'partner_edu_no education',
38
+ 'partner_edu_Not asked/Missing', 'partner_edu_primary', 'partner_edu_secondary',
39
+ 'region_North Central', 'region_North East', 'region_North West',
40
+ 'region_South East', 'region_South South', 'region_South West',
41
+ 'residence_rural', 'residence_urban'
42
+ ]
43
+
44
+ def create_inputs():
45
+ return [
46
+ gr.Number(label="Birth Order", value=1, minimum=1, maximum=20),
47
+ gr.Number(label="Maternal Age (years)", value=25, minimum=12, maximum=49),
48
+ gr.Number(label="Maternal Height (cm)", value=160, minimum=100, maximum=200),
49
+ gr.Number(label="Maternal Weight (kg)", value=60, minimum=30, maximum=120),
50
+ gr.Dropdown(
51
+ choices=[("Poorest", "poorest"), ("Poorer", "poorer"), ("Middle", "middle"),
52
+ ("Richer", "richer"), ("Richest", "richest")],
53
+ label="Wealth Index",
54
+ value="middle"
55
+ ),
56
+ gr.Dropdown(
57
+ choices=[("No Education", "no education"), ("Primary", "primary"),
58
+ ("Secondary", "secondary"), ("Higher", "higher")],
59
+ label="Maternal Education",
60
+ value="primary"
61
+ ),
62
+ gr.Dropdown(choices=[("No", 0), ("Yes", 1)], label="Multiple Birth", value=0),
63
+ gr.Dropdown(choices=["male", "female"], label="Child Sex", value="male"),
64
+ gr.Dropdown(
65
+ choices=["islam", "catholic", "other christian", "traditionalist", "other"],
66
+ label="Religion",
67
+ value="islam"
68
+ ),
69
+ gr.Dropdown(
70
+ choices=["Improved", "Unimproved"],
71
+ label="Water Source",
72
+ value="Improved"
73
+ ),
74
+ gr.Dropdown(
75
+ choices=["Improved", "Unimproved"],
76
+ label="Sanitation",
77
+ value="Improved"
78
+ ),
79
+ gr.Dropdown(
80
+ choices=["no education", "primary", "secondary", "higher"],
81
+ label="Partner Education",
82
+ value="primary"
83
+ ),
84
+ gr.Dropdown(
85
+ choices=["North West", "North East", "North Central", "South West", "South East", "South South"],
86
+ label="Region",
87
+ value="North West"
88
+ ),
89
+ gr.Dropdown(choices=["rural", "urban"], label="Residence", value="rural")
90
+ ]
91
+
92
+ def predict_stunting(birth_order, mat_age, mat_height_cm, mat_weight_kg,
93
+ wealth_label, mat_edu_label, multiple_birth_binary,
94
+ child_sex, religion, water_improved, sanitation_improved,
95
+ partner_edu, region, residence):
96
+
97
+ wealth_ordinal = wealth_map[wealth_label]
98
+ mat_edu_ordinal = mat_edu_map[mat_edu_label]
99
+
100
+ # Build raw input (14 features)
101
+ input_data = pd.DataFrame([[
102
+ birth_order, mat_age, mat_height_cm, mat_weight_kg,
103
+ wealth_ordinal, mat_edu_ordinal, multiple_birth_binary,
104
+ child_sex, religion, water_improved, sanitation_improved,
105
+ partner_edu, region, residence
106
+ ]], columns=numeric_cols + categorical_cols)
107
+
108
+ # One-hot encoding
109
+ one_hot_data = pd.DataFrame(0, index=input_data.index, columns=cat_feature_names)
110
+ for col in categorical_cols:
111
+ val = input_data[col].iloc[0]
112
+ if pd.isna(val) or val in ["Not asked/Missing", "don't know"]:
113
+ col_name = f"{col}_Not asked/Missing"
114
+ else:
115
+ col_name = f"{col}_{val}"
116
+ if col_name in one_hot_data.columns:
117
+ one_hot_data[col_name] = 1
118
+
119
+ # Combine → 35 features (EXACTLY like notebook's X_sksurv)
120
+ X_sksurv = pd.concat([input_data[numeric_cols], one_hot_data], axis=1)
121
+
122
+ # Scale ALL 35 features (this is what the notebook does)
123
+ X_scaled = pd.DataFrame(
124
+ scaler.transform(X_sksurv),
125
+ columns=X_sksurv.columns,
126
+ index=X_sksurv.index
127
+ )
128
+
129
+ # Predict
130
+ risk = model.predict(X_scaled)[0]
131
+
132
+ # Survival probabilities
133
+ surv_funcs = model.predict_survival_function(X_scaled)
134
+ times = np.array([6, 12, 18, 24, 36, 48])
135
+ surv_probs = surv_funcs[0](times)
136
+ stunting_risks = 1 - surv_probs
137
+
138
+ # Plot
139
+ fig, ax = plt.subplots(figsize=(8, 4))
140
+ ax.plot(times, stunting_risks, marker='o', linestyle='-', color='steelblue', linewidth=2, markersize=8)
141
+ ax.axhline(y=0.20, color='red', linestyle='--', label='20% Risk Threshold')
142
+ ax.set_xlabel('Age (months)')
143
+ ax.set_ylabel('Stunting Risk')
144
+ ax.set_title('Stunting Risk by Age')
145
+ ax.set_ylim(0, 1)
146
+ ax.grid(True, linestyle=':', alpha=0.7)
147
+ ax.legend()
148
+ ax.set_xticks(times)
149
+
150
+ return f"## Risk Score: {risk:.4f}", fig
151
+
152
+ inputs = create_inputs()
153
  demo = gr.Interface(
154
+ fn=predict_stunting,
155
+ inputs=inputs,
156
+ outputs=[gr.Markdown(label="Risk Score"), gr.Plot(label="Stunting Risk Curve")],
157
+ title="Stunting Risk Predictor",
158
  description="""
159
  ⚠️ **DISCLAIMER**: This is a **research prototype** developed using DHS data.
160
  **External validation has not been performed**. This tool is for
 
163
 
164
  Predicts stunting risk at ages 6, 12, 18, 24, 36, and 48 months using a
165
  Random Survival Forest model.
166
+ """,
167
+ examples=[
168
+ [1, 25, 160, 60, "middle", "primary", 0, "male", "islam", "Improved", "Improved", "primary", "North West", "rural"],
169
+ [4, 18, 150, 55, "poorest", "no education", 0, "female", "catholic", "Unimproved", "Unimproved", "no education", "South East", "rural"],
170
+ [2, 35, 170, 70, "richest", "higher", 1, "male", "other christian", "Improved", "Improved", "secondary", "South West", "urban"]
171
+ ],
172
+ allow_flagging="never"
173
  )
174
 
175
+ if __name__ == "__main__":
176
+ demo.launch()