Journal-based Case Study

Obesity Risk & Meal Planning berbasis AI

Studi kasus machine learning untuk memprediksi risiko obesitas dari kebiasaan makan, kondisi fisik, dan gaya hidup, lalu menghubungkannya dengan meal planning edukatif.

Mulai TutorialDownload Notebook
Obesity Risk & Meal Planning berbasis AI
Springer Endocrine · Predicting risk of obesity and meal planning to reduce the obese in adulthood using artificial intelligence

Machine learning sering digunakan bukan hanya untuk mengenali gambar atau memprediksi angka, tetapi juga untuk membaca pola dari kebiasaan manusia. Dalam studi kasus ini, kita akan melihat bagaimana data kebiasaan makan, aktivitas fisik, dan kondisi tubuh dapat digunakan untuk memprediksi kategori risiko obesitas.

Catatan penting

Materi ini hanya untuk edukasi machine learning dan bukan saran medis, diagnosis, atau rekomendasi gizi personal.

Ringkasan Paper

Dari paper ke workflow praktik.

Paper sumber membahas pemanfaatan artificial intelligence untuk membaca risiko obesitas dan menghubungkannya dengan ide meal planning. Fokus pembelajaran kita bukan menyalin hasil paper, tetapi membangun ulang workflow yang mudah diikuti: dari dataset, preprocessing, training, evaluasi, sampai interpretasi.

Masalah machine learning-nya adalah multiclass classification. Input berupa kebiasaan makan, aktivitas fisik, kondisi tubuh, dan lifestyle-related features. Output berupa kategori level obesitas. Karena konteksnya sensitif, hasil model harus dibaca sebagai eksperimen data, bukan keputusan medis.

Apa yang akan dibangun?

Alur eksperimen dari data sampai insight.

  • Load dataset dari URL publik
  • Exploratory Data Analysis sederhana
  • Encoding fitur kategorikal
  • Train-test split dengan stratifikasi target
  • Training Random Forest, Gradient Boosting, SVM, dan KNN
  • Evaluasi accuracy, precision, recall, F1, confusion matrix, dan classification report
  • Feature importance untuk membaca faktor yang paling berpengaruh
  • Contoh meal planning hint yang aman sebagai output edukatif
Problem Framing

Ubah masalah nyata menjadi task machine learning.

Kita ingin menjawab pertanyaan praktis: dari data kebiasaan dan kondisi tubuh, apakah model dapat mengenali kategori risiko obesitas dengan cukup stabil? Dalam tutorial ini target utama diambil dari kolom NObeyesdad jika tersedia, lalu setiap fitur kategorikal diubah menjadi angka agar dapat dipakai model scikit-learn.

setup

Setup Environment

Kita memakai pandas, numpy, matplotlib, dan scikit-learn saja supaya notebook ringan dan mudah dijalankan di Colab atau Jupyter.

Python
import pandas as pd
import numpy as np

import matplotlib.pyplot as plt

from sklearn.model_selection import train_test_split
from sklearn.preprocessing import LabelEncoder, StandardScaler
from sklearn.metrics import (
    accuracy_score,
    precision_score,
    recall_score,
    f1_score,
    classification_report,
    confusion_matrix
)

import warnings
warnings.filterwarnings("ignore")
Output preview

Environment siap. Tidak ada dependency tambahan seperti seaborn agar tutorial tetap sederhana.

load dataset

Load Dataset

Dataset dibaca langsung dari tautan publik. Jika URL berubah, kamu bisa mengganti DATA_URL dengan file CSV lokal.

Python
import pandas as pd

DATA_URL = "https://autotrain.app/opendata92bd.html?file=ObesityDataSet_raw_and_data_sinthetic.csv"

df = pd.read_csv(DATA_URL)
df.head()
Output preview

Output yang diharapkan: beberapa baris awal berisi fitur seperti gender, age, height, weight, family history, kebiasaan konsumsi, aktivitas fisik, dan target kategori obesitas.

data understanding

Data Understanding

Sebelum training, kita cek ukuran data, tipe kolom, missing value, dan distribusi target. Distribusi target penting karena data tidak selalu seimbang.

Python
print("Shape:", df.shape)
df.info()

df.isnull().sum().sort_values(ascending=False)

target_col = "NObeyesdad" if "NObeyesdad" in df.columns else df.columns[-1]

print("Target column:", target_col)
df[target_col].value_counts()
Output preview

Jika kolom NObeyesdad tidak ditemukan, kode otomatis memakai kolom terakhir sebagai target. Catatan ini penting saat dataset dari sumber lain punya nama kolom berbeda.

target plot

Visualisasi Distribusi Target

Plot batang membantu melihat apakah kelas target relatif seimbang atau ada kelas yang jauh lebih dominan.

Python
df[target_col].value_counts().plot(kind="bar", figsize=(10, 4))
plt.title("Distribusi Kategori Obesitas")
plt.xlabel("Kategori")
plt.ylabel("Jumlah Data")
plt.xticks(rotation=45, ha="right")
plt.tight_layout()
plt.show()
Output preview

Jika ada kelas yang kecil, metrik macro average menjadi penting karena setiap kelas diberi bobot perhatian yang lebih setara.

Project Access

Bagian praktik lengkap: preprocessing, training, evaluasi, interpretasi, dan file download.

Ringkasan, problem framing, dataset overview, dan preview kode awal tetap bisa dibaca gratis. Untuk mengikuti workflow penuh seperti notebook praktik, gunakan Project Access.

Buka Project Access
preprocessing

Feature, Target, dan Encoding

Fitur kategorikal seperti kebiasaan makan atau transportasi perlu diubah menjadi angka. Label target juga diencode agar model membaca kelas sebagai integer.

Python
target_col = "NObeyesdad" if "NObeyesdad" in df.columns else df.columns[-1]

X = df.drop(columns=[target_col])
y = df[target_col]

print("Features:", X.shape)
print("Target:", y.shape)

X_encoded = X.copy()

for col in X_encoded.columns:
    if X_encoded[col].dtype == "object":
        le = LabelEncoder()
        X_encoded[col] = le.fit_transform(X_encoded[col].astype(str))

target_encoder = LabelEncoder()
y_encoded = target_encoder.fit_transform(y.astype(str))

print("Target classes:")
for idx, label in enumerate(target_encoder.classes_):
    print(idx, "->", label)
Output preview

Output target classes membantu membaca kembali arti angka prediksi, misalnya 0 -> Insufficient Weight atau 4 -> Obesity Type I.

split

Train Test Split

Stratifikasi menjaga proporsi target di train dan test set agar evaluasi lebih adil.

Python
X_train, X_test, y_train, y_test = train_test_split(
    X_encoded,
    y_encoded,
    test_size=0.2,
    random_state=42,
    stratify=y_encoded
)

print(X_train.shape, X_test.shape)
Output preview

Sekitar 80 persen data masuk training dan 20 persen data masuk testing.

training

Training Beberapa Model

Kita membandingkan model ensemble dan model berbasis jarak/margin. SVM dan KNN dibungkus Pipeline dengan StandardScaler karena sensitif terhadap skala fitur.

Python
from sklearn.ensemble import RandomForestClassifier, GradientBoostingClassifier
from sklearn.svm import SVC
from sklearn.neighbors import KNeighborsClassifier
from sklearn.pipeline import Pipeline

models = {
    "Random Forest": RandomForestClassifier(
        n_estimators=200,
        random_state=42,
        class_weight="balanced"
    ),
    "Gradient Boosting": GradientBoostingClassifier(
        random_state=42
    ),
    "SVM": Pipeline([
        ("scaler", StandardScaler()),
        ("model", SVC(kernel="rbf", probability=True, random_state=42))
    ]),
    "KNN": Pipeline([
        ("scaler", StandardScaler()),
        ("model", KNeighborsClassifier(n_neighbors=5))
    ])
}
Output preview

Model belum dilatih pada cell ini. Kita hanya menyiapkan daftar eksperimen yang akan dijalankan pada loop evaluasi.

evaluation

Evaluation Loop

Akurasi saja belum cukup. Macro precision, recall, dan F1 membantu membaca performa lintas kelas.

Python
results = []

for name, model in models.items():
    model.fit(X_train, y_train)
    preds = model.predict(X_test)

    results.append({
        "model": name,
        "accuracy": accuracy_score(y_test, preds),
        "precision_macro": precision_score(y_test, preds, average="macro", zero_division=0),
        "recall_macro": recall_score(y_test, preds, average="macro", zero_division=0),
        "f1_macro": f1_score(y_test, preds, average="macro", zero_division=0)
    })

results_df = pd.DataFrame(results).sort_values(by="f1_macro", ascending=False)
results_df
Output preview

results_df mengurutkan model berdasarkan F1 macro. Angka final dapat berbeda tergantung versi library, split data, dan preprocessing.

confusion matrix

Confusion Matrix Model Terbaik

Confusion matrix memperlihatkan kelas mana yang sering tertukar. Ini sangat berguna untuk task multiclass.

Python
best_model_name = results_df.iloc[0]["model"]
best_model = models[best_model_name]

best_preds = best_model.predict(X_test)

cm = confusion_matrix(y_test, best_preds)

fig, ax = plt.subplots(figsize=(8, 6))
im = ax.imshow(cm)

ax.set_title(f"Confusion Matrix - {best_model_name}")
ax.set_xlabel("Predicted Label")
ax.set_ylabel("True Label")

ax.set_xticks(range(len(target_encoder.classes_)))
ax.set_yticks(range(len(target_encoder.classes_)))
ax.set_xticklabels(target_encoder.classes_, rotation=45, ha="right")
ax.set_yticklabels(target_encoder.classes_)

for i in range(cm.shape[0]):
    for j in range(cm.shape[1]):
        ax.text(j, i, cm[i, j], ha="center", va="center")

plt.tight_layout()
plt.show()
Output preview

Diagonal utama menunjukkan prediksi benar. Nilai di luar diagonal menunjukkan kelas yang tertukar.

classification report

Classification Report

Report ini memberi precision, recall, dan F1 untuk setiap kelas target.

Python
print(classification_report(
    y_test,
    best_preds,
    target_names=target_encoder.classes_,
    zero_division=0
))
Output preview

Perhatikan kelas dengan recall rendah karena berarti banyak data kelas tersebut gagal ditemukan.

feature importance

Feature Importance

Untuk interpretasi tambahan, kita memakai Random Forest agar bisa melihat fitur mana yang paling sering membantu pemisahan kelas.

Python
rf_model = models["Random Forest"]
rf_model.fit(X_train, y_train)

importance_df = pd.DataFrame({
    "feature": X_encoded.columns,
    "importance": rf_model.feature_importances_
}).sort_values(by="importance", ascending=False)

importance_df.head(15)

top_features = importance_df.head(15).sort_values("importance")

plt.figure(figsize=(8, 6))
plt.barh(top_features["feature"], top_features["importance"])
plt.title("Top 15 Feature Importance - Random Forest")
plt.xlabel("Importance")
plt.tight_layout()
plt.show()
Output preview

Feature importance bukan bukti sebab-akibat. Ia hanya memberi sinyal fitur yang sering dipakai model untuk membuat keputusan.

meal planning

Meal Planning Hint Edukatif

Bagian ini sengaja dibuat hati-hati: outputnya hanya contoh edukatif, bukan saran diet personal.

Python
def educational_meal_planning_hint(predicted_label):
    label = predicted_label.lower()

    if "obesity" in label or "overweight" in label:
        return {
            "focus": "Porsi seimbang dan pilihan makanan padat nutrisi",
            "plate_idea": "Perbanyak sayur, sumber protein tanpa lemak, karbohidrat kompleks, dan batasi makanan tinggi gula.",
            "note": "Ini hanya contoh edukatif, bukan saran medis atau diet personal."
        }

    if "insufficient" in label:
        return {
            "focus": "Kecukupan energi dan nutrisi",
            "plate_idea": "Pastikan asupan karbohidrat, protein, lemak sehat, dan mikronutrien cukup.",
            "note": "Ini hanya contoh edukatif, bukan saran medis atau diet personal."
        }

    return {
        "focus": "Menjaga pola makan seimbang",
        "plate_idea": "Pertahankan variasi makanan, aktivitas fisik, dan kebiasaan makan yang konsisten.",
        "note": "Ini hanya contoh edukatif, bukan saran medis atau diet personal."
    }

sample_index = 0
sample = X_test.iloc[[sample_index]]

pred_class_id = best_model.predict(sample)[0]
pred_label = target_encoder.inverse_transform([pred_class_id])[0]

pred_label, educational_meal_planning_hint(pred_label)
Output preview

Output berupa label prediksi dan dictionary berisi fokus edukatif, ide piring makan, serta catatan batasan.

Interpretasi

Insight akhir dan batasan eksperimen.

  • Model dapat membaca pola dari fitur gaya hidup, tetapi pola tersebut sangat bergantung pada kualitas dataset.
  • Evaluasi lintas kelas penting karena akurasi tinggi bisa menyembunyikan kegagalan pada kelas tertentu.
  • Feature importance membantu menjelaskan fitur yang berpengaruh, tetapi tidak boleh dibaca sebagai sebab-akibat medis.
  • Meal planning dalam tutorial ini hanya contoh format output edukatif, bukan rekomendasi gizi personal.
Download

File pendukung studi kasus.

Gunakan notebook untuk belajar bertahap, atau pakai source code jika ingin langsung menjalankan eksperimen di environment sendiri.