Spaces:
Sleeping
Sleeping
File size: 7,691 Bytes
1d12e6c 5217123 337b68c 5217123 1d12e6c 9975da0 1d12e6c 9975da0 1d12e6c 9975da0 337b68c 15de49c 337b68c 5217123 9975da0 337b68c 5217123 337b68c 5217123 337b68c 5217123 337b68c 5217123 337b68c 9975da0 337b68c 5217123 337b68c 5217123 337b68c 5217123 9975da0 337b68c 9975da0 337b68c 460491a 337b68c 460491a 9975da0 337b68c 460491a 337b68c 460491a 337b68c 9975da0 337b68c 460491a 337b68c 5217123 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 |
import gradio as gr
import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets
from sklearn.utils import shuffle
EXPLAIN_MD = """
### Wat testen we hier?
We bekijken of er een **lineair verband** is tussen **BMI** en de **diabetes-progressiescore** in een bekende (openbare) dataset.
Dat doen we met *supervised learning*: het model ziet voorbeelden `(BMI → score)` en leert een lijn \(y = w x + b\) die dit verband benadert.
**Hoe meten we of dat gelukt is?**
- We splitsen de data in **train (80%)** en **test (20%)**.
- We **trainen** het model alleen op de **trainset**.
- We **toetsen** het resultaat op de **testset** die het model niet gezien heeft.
- We rapporteren **MSE** (gemiddelde kwadratische fout) en **R²** (uitlegvariantie) op de testset.
> Let op: in deze sklearn-dataset is BMI **genormaliseerd** (geschaald). De helling `w` geeft wel de **richting en sterkte** aan (positief = hogere BMI hangt samen met hogere score).
"""
STORY_MD = r"""
### Waarom kijken we naar BMI en diabetes?
Stel je voor dat je arts wilt begrijpen of **het gewicht van mensen** (uitgedrukt als *Body Mass Index*, BMI)
iets zegt over hun **gezondheid**. Een van de dingen die onderzocht wordt is het verband tussen BMI en de
**ernst van diabetes**.
We gebruiken hier **echte gegevens** uit een medische dataset (dus **geen foto’s**, maar gemeten waarden van mensen
die in een onderzoek hebben meegedaan). Elke deelnemer heeft:
- een **BMI-waarde** (hoe zwaar of licht iemand is ten opzichte van zijn lengte),
- en een **score** die aangeeft hoe ernstig de diabetes bij die persoon verloopt.
Met lineaire regressie testen we: *kunnen we een lijn tekenen die laat zien of een hogere BMI vaak samenvalt met een
hogere (of juist lagere) score?*
**Waarom is dat belangrijk?**
- Als er wél een duidelijk verband is, kan dit helpen om **risico’s eerder te signaleren**.
- Als er géén verband is, leren we dat BMI misschien niet de juiste voorspeller is en moet er verder gekeken worden
naar andere factoren.
Kortom: dit experiment laat je zien hoe data ons kan helpen om **patronen in gezondheid** te ontdekken — en dat doen
we hier stap voor stap, live op je scherm.
"""
CONCLUSION_MD = r"""
# **Conclusie**
Mensen met een hogere **BMI** hebben in dit onderzoek gemiddeld vaker een ernstiger verloop van **diabetes**.
Maar **BMI is niet de enige factor** — leeftijd, erfelijkheid, leefstijl en andere medische waarden spelen ook mee.
"""
def load_bmi_diabetes():
d = datasets.load_diabetes()
X = d.data[:, 2] # BMI feature (genormaliseerd)
y = d.target # Progressiescore
return X.astype(np.float64), y.astype(np.float64), "Diabetes: BMI vs. score"
def train_test_split_1d(x, y, test_size=0.2, seed=42):
rng = np.random.RandomState(seed)
idx = np.arange(x.shape[0])
rng.shuffle(idx)
n_test = int(len(idx) * test_size)
test_idx = idx[:n_test]
train_idx = idx[n_test:]
return x[train_idx], y[train_idx], x[test_idx], y[test_idx]
def sgd_train_generator(lr, epochs, batch_size, seed, split_seed):
# Data & split
x, y, label = load_bmi_diabetes()
x_tr, y_tr, x_te, y_te = train_test_split_1d(x, y, test_size=0.2, seed=int(split_seed))
n = x_tr.shape[0]
w, b = 0.0, 0.0
x_min, x_max = float(np.min(x)), float(np.max(x))
train_losses, test_losses = [], []
rng = np.random.RandomState(int(seed))
for epoch in range(1, int(epochs) + 1):
# shuffle train set
x_tr, y_tr = shuffle(x_tr, y_tr, random_state=rng)
# SGD over mini-batches
for start in range(0, n, int(batch_size)):
end = min(start + int(batch_size), n)
xb, yb = x_tr[start:end], y_tr[start:end]
yhat = w * xb + b
err = yb - yhat
dw = -(2.0 / xb.size) * np.sum(xb * err)
db = -(2.0 / xb.size) * np.sum(err)
w -= lr * dw
b -= lr * db
# Metrics on train and test
y_tr_pred = w * x_tr + b
y_te_pred = w * x_te + b
mse_tr = float(np.mean((y_tr - y_tr_pred)**2))
mse_te = float(np.mean((y_te - y_te_pred)**2))
# R^2 on test
ss_res = float(np.sum((y_te - y_te_pred)**2))
ss_tot = float(np.sum((y_te - np.mean(y_te))**2))
r2_te = 1.0 - ss_res / ss_tot if ss_tot > 0 else float("nan")
train_losses.append(mse_tr)
test_losses.append(mse_te)
# Plot 1: data (train vs test) + regressielijn
fig_main = plt.figure(figsize=(7, 4))
ax1 = fig_main.add_subplot(111)
ax1.scatter(x_tr, y_tr, alpha=0.6, s=18, label="train")
ax1.scatter(x_te, y_te, alpha=0.8, s=22, marker="x", label="test")
xs = np.linspace(x_min, x_max, 200)
ax1.plot(xs, w * xs + b, linewidth=2, label="model")
ax1.set_title(f"{label} — Epoch {epoch}/{epochs}")
ax1.set_xlabel("BMI (genormaliseerd)")
ax1.set_ylabel("Progressiescore")
ax1.legend()
ax1.grid(True, linestyle=":", linewidth=0.6)
plt.tight_layout()
# Plot 2: loss-curve (train & test)
fig_loss = plt.figure(figsize=(7, 3.5))
ax2 = fig_loss.add_subplot(111)
ax2.plot(range(1, len(train_losses)+1), train_losses, marker="o", label="Train MSE")
ax2.plot(range(1, len(test_losses)+1), test_losses, marker="o", linestyle="--", label="Test MSE")
ax2.set_title("Loss-curve (MSE per epoch) — lager is beter")
ax2.set_xlabel("Epoch")
ax2.set_ylabel("MSE")
ax2.legend()
ax2.grid(True, linestyle=":", linewidth=0.6)
plt.tight_layout()
# Resultaten + opvallende conclusie
verdict = "positief" if w >= 0 else "negatief"
summary = (
f"**Wat levert dit op?**\n"
f"- Huidige regressielijn: `y = {w:.4f} * x + {b:.4f}`\n"
f"- Train MSE: `{mse_tr:.2f}` — Test MSE: `{mse_te:.2f}` — Test R²: `{r2_te:.3f}`\n"
f"- Interpretatie: het verband tussen BMI en progressiescore is **{verdict}** in deze dataset "
f"(hogere BMI hangt samen met hogere score als `w > 0`).\n\n"
f"{CONCLUSION_MD}"
)
yield fig_main, fig_loss, summary
with gr.Blocks(title="Diabetes: BMI → Progressiescore (Live Regressie)") as demo:
gr.Markdown("# Diabetes: BMI → Progressiescore (Live Lineaire Regressie)")
gr.Markdown(EXPLAIN_MD)
with gr.Row():
with gr.Column(scale=1):
lr = gr.Slider(1e-4, 1e-0, value=5e-3, step=1e-4, label="Learning rate")
epochs = gr.Slider(5, 200, value=60, step=1, label="Epochs")
batch = gr.Slider(8, 256, value=64, step=1, label="Batchgrootte")
seed = gr.Slider(0, 9999, value=42, step=1, label="Training seed")
split_seed = gr.Slider(0, 9999, value=7, step=1, label="Train/test split seed")
train_btn = gr.Button("Train live")
# Story direct onder de knop
gr.Markdown(STORY_MD)
with gr.Column(scale=2):
plot_main = gr.Plot(label="Data (train/test) & regressielijn (live)")
plot_loss = gr.Plot(label="Loss-curve (MSE per epoch) — train vs test")
results = gr.Markdown()
# Training starten via knop
train_btn.click(
fn=sgd_train_generator,
inputs=[lr, epochs, batch, seed, split_seed],
outputs=[plot_main, plot_loss, results]
)
# Auto-train bij laden met default-waarden
demo.load(
fn=sgd_train_generator,
inputs=[lr, epochs, batch, seed, split_seed],
outputs=[plot_main, plot_loss, results]
)
if __name__ == "__main__":
demo.launch()
|