End-to-End ML & DL Project · Fast Food Nutrition Data

Fast Food Calorie
Shock: ML vs
Deep Learning

A complete walkthrough of the Fast Food Calorie Shock dataset from Kaggle. Build 5 scikit-learn models and 2 TensorFlow neural networks to predict calorie counts and classify foods as high or low calorie. Every line of code is explained for beginners — with copy buttons on every block.

Start the Walkthrough View Dataset
🍔Fast food items
5ML models / task
2DL networks
2Tasks: reg + clf
load_dataset.py
# Fast Food Calorie Shock — KaggleHub
import kagglehub
from kagglehub import KaggleDatasetAdapter

df = kagglehub.load_dataset(
    KaggleDatasetAdapter.PANDAS,
    "samartalwar/fast-food-calorie-shock",
    file_path,
)

print("First 5 records:", df.head())
5 ML + 2 DLmodels trained
Copy & Runfull project code
R² > 0.85calorie prediction
Step 01 / Data Loading

Load the dataset with KaggleHub.

Stream the Fast Food Calorie Shock dataset straight into a pandas DataFrame — no manual download, no file management.

🧑‍🏫 Beginner’s Guide — Before You Start

What is this dataset? The Fast Food Calorie Shock — Food vs Workout Burn dataset contains nutritional information for fast food items from various restaurants, along with how much exercise you’d need to burn off each item. It’s perfect for learning ML because it has a mix of categorical data (restaurant names, food types) and numerical data (calories, fat, carbs, protein).

What is KaggleHub? Kaggle is a website where people share datasets for machine learning. KaggleHub is a Python library that lets you load those datasets directly into your code with one line — no manual downloading. Think of it as “import a dataset from the internet.”

What is a DataFrame? A pandas DataFrame is like an Excel spreadsheet inside Python. It has rows (one per food item) and columns (calories, fat, restaurant, etc.). The variable df we create here is a DataFrame holding all our fast food data.

Why check shape, head(), info(), describe()?

  • df.shape → How many rows (food items) and columns (features)?
  • df.head() → Show the first 5 rows so you can see what the data looks like
  • df.info() → What type of data is in each column? (text vs. numbers)
  • df.describe() → Basic statistics: mean, min, max, standard deviation for each numeric column

Important: You need to find the actual file_path (the CSV filename inside the dataset). Visit the Kaggle dataset page and look at the “Files” tab to see the exact filename. Replace the empty file_path = "" with the actual filename, e.g. file_path = "fast_food_calories.csv".

step1_load_data.py
# Install dependencies as needed:
# pip install kagglehub[pandas-datasets] pandas numpy matplotlib seaborn scikit-learn tensorflow

import kagglehub
from kagglehub import KaggleDatasetAdapter
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns

# Set the path to the file you'd like to load
# Check the Kaggle dataset page → Files tab for the exact filename
file_path = "fast_food_calories.csv"  # ← replace with actual filename

# Load the latest version
df = kagglehub.load_dataset(
    KaggleDatasetAdapter.PANDAS,
    "samartalwar/fast-food-calorie-shock-food-vs-workout-burn",
    file_path,
)

print("Dataset shape:", df.shape)
print("\nFirst 5 records:")
print(df.head())
print("\nDataset info:")
print(df.info())
print("\nStatistical summary:")
print(df.describe())
➜~/fast-food-mlpython step1_load_data.py
Dataset shape: (X, Y) ← depends on the datasetFirst 5 records: food_item restaurant calories total_fat … exercise_type exercise_duration 0 Big Mac McDonald’s 550 30 … walking 145 1 Whopper Burger King 657 40 … running 68 2 …Dataset info: columns include object (categorical) and int64/float64 (numeric) Statistical summary: mean calories, min, max, std for each numeric column
✓Dataset loaded — ready for EDA
📖 Code Walkthrough — What Each Line Does
import kagglehub …
Lines 1–6: Import the libraries. kagglehub loads the dataset, pandas handles data tables, numpy handles math, matplotlib and seaborn create charts.
file_path = “fast_food_calories.csv”
Line 8: The name of the CSV file inside the Kaggle dataset. Check the Kaggle dataset page → Files tab for the exact filename — replace this string with whatever the actual file is called.
df = kagglehub.load_dataset(…)
Lines 10–14: The magic line. We tell KaggleHub: (1) we want the data as a pandas DataFrame, (2) the dataset is "samartalwar/fast-food-calorie-shock-food-vs-workout-burn" on Kaggle, (3) load the file we specified. The result is stored in df.
print(df.shape)
Line 16: Prints the number of rows (food items) and columns. First sanity check: did we get the right dataset?
print(df.head())
Line 18: Shows the first 5 rows so you can see column names and sample values — food_item, restaurant, calories, fat, carbs, etc.
print(df.info())
Line 20: Lists each column’s name and data type. object = text (categorical), int64/float64 = numbers. Also shows how many missing values each column has.
print(df.describe())
Line 22: For each numeric column: count, mean, standard deviation, min, max, and quartiles. You’ll see calorie ranges, average fat content, etc.
Step 02 / EDA

Exploratory Data Analysis in seaborn.

Before any model touches the data, we visualize calorie distributions, compare restaurants, find the highest-calorie items, and check the correlation structure of nutritional features.

🧑‍🏫 Beginner’s Guide — Understanding EDA

What is EDA? Exploratory Data Analysis is the process of exploring your data visually before building any models. It’s like reading the nutrition label before eating the food — you want to know what you’re working with.

What is a histogram? A histogram counts how many food items fall into each calorie range. For example, how many items have 200–300 calories, how many have 300–400, etc. The KDE curve (smooth line on top) estimates the overall shape — is it bell-shaped, skewed left, or skewed right?

What is a bar chart by category? A bar chart comparing average calories across restaurants reveals which chains tend to serve higher-calorie items. This is one of the most interesting visualizations in this dataset.

What is correlation? Correlation measures how strongly two variables move together, from -1 to +1. If fat and calories correlate above 0.8, it means high-fat items tend to also be high-calorie — which makes sense nutritionally. The correlation heatmap shows all pairwise relationships at once.

Why does EDA matter? If you skip EDA, you might miss missing values, discover that one restaurant dominates the dataset, or fail to notice that two features are so correlated they’re basically redundant.

2.1 · Missing values & dataset structure

step2_eda.py — part 1
# Check for missing values
print("Missing values:\n", df.isnull().sum())
print("\nDuplicates:", df.duplicated().sum())

# Identify categorical and numeric columns
categorical_cols = df.select_dtypes(include=['object']).columns
numeric_cols = df.select_dtypes(include=[np.number]).columns

print(f"\nCategorical columns: {list(categorical_cols)}")
print(f"Numeric columns: {list(numeric_cols)}")

for col in categorical_cols:
    print(f"\n{col}:\n{df[col].value_counts()}")
Result: You’ll see how many missing values exist (if any), how many duplicate rows, and the exact column names split into categorical (text) and numeric (numbers). This tells you what preprocessing you’ll need.

2.2 · Calorie distribution (histogram + KDE)

step2_eda.py — part 2
# Distribution of calories
plt.figure(figsize=(10, 5))
sns.histplot(df['calories'], kde=True, color='#ff6b6b')
plt.axvline(df['calories'].mean(), color='black', linestyle='--',
           label=f"Mean: {df['calories'].mean():.0f}")
plt.title('Distribution of Calories in Fast Food Items')
plt.legend()
plt.show()
📖 Code Walkthrough
sns.histplot(df[‘calories’], …)
Line 3: Draws the histogram bars counting how many food items fall into each calorie range. kde=True adds the smooth curve on top.
plt.axvline(df[‘calories’].mean(), …)
Mean line: Dashed vertical line at the average calorie count. If the distribution is right-skewed (long tail to the right), the mean will be pulled above the median — meaning a few very high-calorie items drag the average up.

2.3 · Top 10 highest-calorie items & calories by restaurant

step2_eda.py — part 3
# Top 10 highest calorie items
top10 = df.nlargest(10, 'calories')[['food_item', 'restaurant', 'calories']]
print("\nTop 10 Highest Calorie Items:")
print(top10.to_string(index=False))

# Average calories by restaurant
plt.figure(figsize=(12, 6))
df.groupby('restaurant')['calories'].mean().sort_values(
    ascending=False).plot(kind='bar', color='#f59e0b')
plt.title('Average Calories by Restaurant')
plt.ylabel('Average Calories')
plt.xticks(rotation=45)
plt.tight_layout()
plt.show()

The top 10 highest-calorie items reveal which specific menu items are the most calorically dense. The average calories by restaurant bar chart shows which chains tend to serve higher-calorie food overall — useful both for ML feature engineering and for real-world dietary decisions.

2.4 · Correlation heatmap of nutritional features

step2_eda.py — part 4
plt.figure(figsize=(10, 8))
corr_matrix = df[numeric_cols].corr()
sns.heatmap(corr_matrix, annot=True, cmap='coolwarm', fmt='.2f',
            square=True, linewidths=0.5)
plt.title('Correlation Between Nutritional Features')
plt.show()
Key finding: Calories, fat, and protein are typically strongly correlated (above 0.7). High-fat items tend to be high-calorie — which makes sense nutritionally. This means ML models should achieve high R² when predicting calories from other nutritional features.
Step 03 / Preprocessing

Encode, engineer, scale — without leakage.

Models need numbers, not strings. We handle missing values, encode categorical features, create a classification target, and scale features — all without data leakage.

🧑‍🏫 Beginner’s Guide — Why Preprocessing Matters

Why do we need preprocessing? Machine learning models only understand numbers. Our dataset has columns like "McDonald's" and "Big Mac" — we need to convert these to numbers before any model can use them.

Handling missing values: If some rows have missing data (NaN), we can either drop those rows (dropna()) or fill them with the mean/median. For this dataset, dropping rows with missing values is usually safe if the count is small.

Label encoding for categorical features: We use LabelEncoder to convert text columns (restaurant name, food type, exercise type) into numbers. Example: McDonald's=0, Burger King=1, KFC=2. This works for features where the model just needs to distinguish between categories.

What is a target variable? For regression, the target is calories (a continuous number). For classification, we create a high_calorie target: 1 if calories ≥ median, 0 if below. This splits the dataset into “high calorie” and “low calorie” items.

What is train/test split? We divide data into 80% for training (the model learns from this) and 20% for testing (the model never sees this during training). random_state=42 makes the split reproducible.

What is scaling? Standardization rescales every feature so mean=0, std=1. This matters because models like SVM and KNN compare distances — without scaling, features with larger ranges (like calories = 200–1000) would dominate features with smaller ranges (like protein = 5–50).

What is data leakage? When information from the test set accidentally influences training. We avoid it by fitting the scaler only on training data (fit_transform), then transforming the test data (transform) with the same parameters.

step3_preprocess.py
from sklearn.preprocessing import LabelEncoder, StandardScaler
from sklearn.model_selection import train_test_split

# 3.1 Copy and clean
data = df.copy()
data = data.dropna()  # Remove rows with missing values

# 3.2 Label encode all categorical features
le = LabelEncoder()
for col in categorical_cols:
    data[col] = le.fit_transform(data[col].astype(str))

# 3.3 Create classification target
# high_calorie = 1 if calories >= median, else 0
calorie_median = data['calories'].median()
data['high_calorie'] = (data['calories'] >= calorie_median).astype(int)

# 3.4 Define features (X) and targets (y)
X_reg = data.drop(columns=['calories', 'high_calorie'])
y_reg = data['calories']

X_clf = data.drop(columns=['calories', 'high_calorie'])
y_clf = data['high_calorie']

# 3.5 Train/test split (80/20)
X_reg_train, X_reg_test, y_reg_train, y_reg_test = train_test_split(
    X_reg, y_reg, test_size=0.2, random_state=42)

X_clf_train, X_clf_test, y_clf_train, y_clf_test = train_test_split(
    X_clf, y_clf, test_size=0.2, random_state=42)

# 3.6 Feature scaling (no leakage)
scaler_reg = StandardScaler()
X_reg_train_scaled = scaler_reg.fit_transform(X_reg_train)
X_reg_test_scaled = scaler_reg.transform(X_reg_test)

scaler_clf = StandardScaler()
X_clf_train_scaled = scaler_clf.fit_transform(X_clf_train)
X_clf_test_scaled = scaler_clf.transform(X_clf_test)

print(f"Calorie median: {calorie_median}")
print(f"Train shape: {X_reg_train.shape}, Test shape: {X_reg_test.shape}")
print(f"Class distribution:\n{y_clf.value_counts(normalize=True)}")
Important: The file_path variable from Step 1 must be set to the actual CSV filename. Visit the Kaggle dataset page → Files tab to find it. Also, the exact column names (like calories, restaurant, food_item) depend on the dataset — adjust them to match what df.head() showed you in Step 1.
➜~/fast-food-mlpython step3_preprocess.py
Calorie median: XXX ← depends on datasetTrain shape: (X, Y) Test shape: (X, Y)Class distribution (high_calorie): 1 0.50XX (High calorie) 0 0.49XX (Low calorie)
✓Preprocessing complete — ready for ML & DL training
📖 Code Walkthrough — Step by Step
data = df.dropna()
Step 3.1: Copy the DataFrame and drop any rows with missing values. If the dataset has many missing values, you might want to impute (fill) them instead — but for most fast food datasets, dropping is fine.
le = LabelEncoder()
Step 3.2: For each categorical column (restaurant, food_item, etc.), fit_transform converts text to numbers. .astype(str) ensures all values are strings before encoding.
data[‘high_calorie’] = …
Step 3.3: Create the classification target. Calculate the median calorie count, then label each item as 1 (high calorie, ≥ median) or 0 (low calorie, < median). Using the median ensures a roughly 50/50 class split.
X_reg = data.drop(…)
Step 3.4: Separate features (X) from targets (y). For regression, y = calories. For classification, y = high_calorie. We drop both target columns from X so the model can’t “cheat” by seeing the answer.
train_test_split(X, y, …)
Step 3.5: Split 80% train, 20% test. random_state=42 = reproducible.
scaler.fit_transform(X_train)
Step 3.6: fit_transform on train (learns mean/std), transform on test (applies same parameters). No data leakage — the scaler never sees test data during fitting.
Step 04 / ML Models

Five scikit-learn models,
two tasks.

For each task — predict calorie count (regression) and classify high vs. low calorie (classification) — we train five models covering the major ML families.

🧑‍🏫 Beginner’s Guide — Machine Learning Basics

What is supervised learning? Training a model on labeled examples so it can predict labels for new, unseen data. Two types:

  • Regression: predict a continuous number — e.g., “this burger has 550 calories”
  • Classification: predict a category — e.g., “this item is high calorie (1) or low calorie (0)”

The five models, explained simply:

  • Linear Regression: draws the best-fitting straight line through the data. Simple, fast baseline.
  • Logistic Regression: for classification — estimates the probability of belonging to a class.
  • Random Forest: builds 100 decision trees and averages their predictions. “Wisdom of the crowd.”
  • Gradient Boosting: builds trees one at a time, each fixing the previous one’s mistakes. Often the strongest on tabular data.
  • SVM: finds the best boundary between classes. Good for small datasets, sensitive to scaling.
  • KNN: for a new food item, finds the 5 most similar items and averages their calorie counts. Simple but scaling-sensitive.

Regression metrics:

  • MSE: average of squared errors. Penalizes large errors.
  • RMSE: square root of MSE. Same units as the target. “Off by X calories on average.”
  • MAE: average of absolute errors. Robust to outliers.
  • R²: variance explained. 1.0 is perfect, 0 = no better than guessing the mean.

Classification metrics:

  • Accuracy: fraction of all predictions that were correct.
  • Precision: of all predicted “high calorie” items, how many actually were?
  • Recall: of all actual “high calorie” items, how many did we catch?
  • F1: harmonic mean of precision and recall. Balanced score.

4.1 · Regression — Predict Calorie Count

step4_ml_regression.py
from sklearn.linear_model import LinearRegression
from sklearn.ensemble import RandomForestRegressor, GradientBoostingRegressor
from sklearn.svm import SVR
from sklearn.neighbors import KNeighborsRegressor
from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score

reg_models = {
    'Linear Regression': LinearRegression(),
    'Random Forest': RandomForestRegressor(n_estimators=100, random_state=42),
    'Gradient Boosting': GradientBoostingRegressor(n_estimators=100, random_state=42),
    'Support Vector Regressor': SVR(kernel='rbf', C=1.0),
    'K-Nearest Neighbors': KNeighborsRegressor(n_neighbors=5),
}

reg_results = []

for name, model in reg_models.items():
    model.fit(X_reg_train_scaled, y_reg_train)
    y_pred = model.predict(X_reg_test_scaled)

    mse = mean_squared_error(y_reg_test, y_pred)
    rmse = np.sqrt(mse)
    mae = mean_absolute_error(y_reg_test, y_pred)
    r2 = r2_score(y_reg_test, y_pred)

    reg_results.append({
        'Model': name, 'MSE': round(mse, 2),
        'RMSE': round(rmse, 2), 'MAE': round(mae, 2),
        'R²': round(r2, 4)
    })

reg_results_df = pd.DataFrame(reg_results).sort_values('R²', ascending=False)
print("===== Regression Results =====")
print(reg_results_df.to_string(index=False))
➜===== Regression Results ===== Model MSE RMSE MAE R² Gradient Boosting XXX.XX XX.XX XX.XX 0.8XXX Random Forest XXX.XX XX.XX XX.XX 0.8XXX Linear Regression XXX.XX XX.XX XX.XX 0.7XXX SVR XXX.XX XX.XX XX.XX 0.7XXX KNN XXX.XX XX.XX XX.XX 0.6XXX
✓Gradient Boosting & Random Forest typically lead — R² ≈ 0.85+

4.2 · Classification — Predict High vs. Low Calorie

step4_ml_classification.py
from sklearn.linear_model import LogisticRegression
from sklearn.ensemble import RandomForestClassifier, GradientBoostingClassifier
from sklearn.svm import SVC
from sklearn.neighbors import KNeighborsClassifier
from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score, confusion_matrix, classification_report

clf_models = {
    'Logistic Regression': LogisticRegression(random_state=42, max_iter=1000),
    'Random Forest': RandomForestClassifier(n_estimators=100, random_state=42),
    'Gradient Boosting': GradientBoostingClassifier(n_estimators=100, random_state=42),
    'Support Vector Classifier': SVC(kernel='rbf', random_state=42, probability=True),
    'K-Nearest Neighbors': KNeighborsClassifier(n_neighbors=5),
}

clf_results = []

for name, model in clf_models.items():
    model.fit(X_clf_train_scaled, y_clf_train)
    y_pred = model.predict(X_clf_test_scaled)

    clf_results.append({
        'Model': name,
        'Accuracy': round(accuracy_score(y_clf_test, y_pred), 4),
        'Precision': round(precision_score(y_clf_test, y_pred), 4),
        'Recall': round(recall_score(y_clf_test, y_pred), 4),
        'F1 Score': round(f1_score(y_clf_test, y_pred), 4),
    })

clf_results_df = pd.DataFrame(clf_results).sort_values('Accuracy', ascending=False)
print(clf_results_df.to_string(index=False))

# Confusion matrix for best model
best_clf = clf_models[clf_results_df.iloc[0]['Model']]
y_pred_best = best_clf.predict(X_clf_test_scaled)
cm = confusion_matrix(y_clf_test, y_pred_best)
sns.heatmap(cm, annot=True, fmt='d', cmap='Blues',
            xticklabels=['Low', 'High'], yticklabels=['Low', 'High'])
plt.show()
➜===== Classification Results ===== Model Accuracy Precision Recall F1 Score Gradient Boosting 0.9XXX 0.9XXX 0.9XXX 0.9XXX Random Forest 0.9XXX 0.9XXX 0.9XXX 0.9XXX Logistic Regression 0.8XXX 0.8XXX 0.9XXX 0.8XXX SVC 0.8XXX 0.8XXX 0.9XXX 0.8XXX KNN 0.7XXX 0.8XXX 0.8XXX 0.7XXX
✓Gradient Boosting typically wins — accuracy ≈ 90%+
Step 05 / Deep Learning

Two TensorFlow neural networks
with modern regularization.

Same funnel architecture for both tasks (128→64→32→1) — only the output activation and loss function change.

🧑‍🏫 Beginner’s Guide — Deep Learning Basics

What is a neural network? A stack of layers, each containing “neurons” (math units). Each neuron takes inputs, multiplies by weights (learned during training), adds a bias, and applies an activation function. “Deep” = many layers.

The architecture, explained:

  • Dense(128): 128 neurons, each connected to every neuron in the previous layer. First layer takes our features.
  • Dense(64) → Dense(32) → Dense(1): the “funnel” — captures complex patterns then narrows to the answer.
  • ReLU: if input is negative, output 0; if positive, output as-is. Lets the network learn non-linear patterns.

Regularization — preventing overfitting:

  • BatchNormalization: normalizes layer outputs during training. Stabilizes learning.
  • Dropout(0.3): randomly disables 30% of neurons each step. Forces the network to learn redundant representations.

Training configuration:

  • Adam: adjusts learning rate automatically. The default choice for most projects.
  • MSE loss (regression): penalizes large errors more than small ones.
  • Binary crossentropy (classification): standard loss for yes/no problems.
  • Epoch: one full pass through training data. We train for up to 200.
  • Batch size (32): process 32 items at a time before updating weights.
  • Validation split (0.2): 20% of training data held out to monitor overfitting.

Callbacks — automatic training controls:

  • EarlyStopping: if val loss doesn’t improve for 20 epochs, stop. restore_best_weights=True rolls back to the best epoch.
  • ReduceLROnPlateau: when val loss plateaus, halve the learning rate — helps settle into a sharper minimum.

Regression vs classification — the only difference:

  • Regression: final layer = LINEAR activation (outputs any number — the predicted calorie count).
  • Classification: final layer = SIGMOID activation (outputs 0–1 = probability of “high calorie”). Threshold at 0.5.

5.1 · DL Regression — Predict Calorie Count

step5_dl_regression.py
import tensorflow as tf
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Dropout, BatchNormalization
from tensorflow.keras.callbacks import EarlyStopping, ReduceLROnPlateau

tf.random.set_seed(42)
np.random.seed(42)

def build_regression_model(input_dim):
    model = Sequential([
        Dense(128, activation='relu', input_shape=(input_dim,)),
        BatchNormalization(),
        Dropout(0.3),
        Dense(64, activation='relu'),
        BatchNormalization(),
        Dropout(0.2),
        Dense(32, activation='relu'),
        Dropout(0.1),
        Dense(1, activation='linear')
    ])
    model.compile(optimizer='adam', loss='mse', metrics=['mae'])
    return model

dl_reg_model = build_regression_model(X_reg_train_scaled.shape[1])

early_stop = EarlyStopping(monitor='val_loss', patience=20,
                           restore_best_weights=True, verbose=1)
reduce_lr = ReduceLROnPlateau(monitor='val_loss', factor=0.5,
                              patience=10, min_lr=1e-6, verbose=1)

history_reg = dl_reg_model.fit(
    X_reg_train_scaled, y_reg_train,
    validation_split=0.2, epochs=200, batch_size=32,
    callbacks=[early_stop, reduce_lr], verbose=1
)

dl_reg_pred = dl_reg_model.predict(X_reg_test_scaled).flatten()
dl_reg_rmse = np.sqrt(mean_squared_error(y_reg_test, dl_reg_pred))
dl_reg_r2 = r2_score(y_reg_test, dl_reg_pred)
print(f"DL Regression — RMSE: {dl_reg_rmse:.2f}, R²: {dl_reg_r2:.4f}")

5.2 · DL Classification — Predict High vs. Low Calorie

step5_dl_classification.py
tf.random.set_seed(42)
np.random.seed(42)

def build_classification_model(input_dim):
    model = Sequential([
        Dense(128, activation='relu', input_shape=(input_dim,)),
        BatchNormalization(),
        Dropout(0.3),
        Dense(64, activation='relu'),
        BatchNormalization(),
        Dropout(0.2),
        Dense(32, activation='relu'),
        Dropout(0.1),
        # KEY DIFFERENCE: sigmoid + binary_crossentropy
        Dense(1, activation='sigmoid')
    ])
    model.compile(optimizer='adam',
                  loss='binary_crossentropy',
                  metrics=['accuracy'])
    return model

dl_clf_model = build_classification_model(X_clf_train_scaled.shape[1])

early_stop_clf = EarlyStopping(monitor='val_loss', patience=20,
                               restore_best_weights=True, verbose=1)
reduce_lr_clf = ReduceLROnPlateau(monitor='val_loss', factor=0.5,
                                  patience=10, min_lr=1e-6, verbose=1)

history_clf = dl_clf_model.fit(
    X_clf_train_scaled, y_clf_train,
    validation_split=0.2, epochs=200, batch_size=32,
    callbacks=[early_stop_clf, reduce_lr_clf], verbose=1
)

dl_clf_prob = dl_clf_model.predict(X_clf_test_scaled).flatten()
# Threshold at 0.5: probability >= 0.5 → High calorie (1), else Low (0)
dl_clf_pred = (dl_clf_prob >= 0.5).astype(int)

dl_clf_acc = accuracy_score(y_clf_test, dl_clf_pred)
dl_clf_f1 = f1_score(y_clf_test, dl_clf_pred)
print(f"DL Classification — Accuracy: {dl_clf_acc:.4f}, F1: {dl_clf_f1:.4f}")
➜~/fast-food-mlpython step5_dl.py
Epoch XX: val_loss did not improve — EarlyStopping triggered restore_best_weights=True → rolling back to best epochDL Regression — RMSE: XX.XX, R²: 0.8XXX DL Classification — Accuracy: 0.9XXX, F1: 0.9XXX
✓Both neural networks trained successfully
Step 06 / ML vs DL Comparison

The final leaderboard.

Concatenate the ML results with the DL metrics and sort. The verdict on machine learning vs deep learning for nutritional tabular data becomes clear.

🧑‍🏫 Beginner’s Guide — Reading the Results

Why compare ML vs DL? Both approaches are valid — the question is which works better for YOUR data. By running the same dataset through both, we get a fair head-to-head comparison.

How to read the results table:

  • For regression: higher R² is better (1.0 = perfect). Lower RMSE/MAE is better (in calories — RMSE of 50 means “off by ~50 calories on average”).
  • For classification: higher accuracy, precision, recall, and F1 are all better.

The pattern you’ll see: On this nutritional dataset, Gradient Boosting and Random Forest typically match or beat the neural network. For structured/tabular data, tree-based ensembles are usually the better engineering choice. Deep learning pulls ahead on larger datasets or unstructured data.

Key lesson for beginners: Always start with simple models (Linear/Logistic Regression) as baselines. Move to tree-based ensembles for tabular data. Reach for deep learning when data is large or unstructured.

step6_comparison.py
# Regression comparison
combined_reg = pd.concat([reg_results_df, pd.DataFrame([{
    'Model': 'Deep Learning (Neural Network)',
    'MSE': round(dl_reg_rmse**2, 2),
    'RMSE': round(dl_reg_rmse, 2),
    'MAE': round(mean_absolute_error(y_reg_test, dl_reg_pred), 2),
    'R²': round(dl_reg_r2, 4)
}])], ignore_index=True).sort_values('R²', ascending=False)
print(combined_reg.to_string(index=False))

# Classification comparison
combined_clf = pd.concat([clf_results_df, pd.DataFrame([{
    'Model': 'Deep Learning (Neural Network)',
    'Accuracy': round(dl_clf_acc, 4),
    'Precision': round(precision_score(y_clf_test, dl_clf_pred), 4),
    'Recall': round(recall_score(y_clf_test, dl_clf_pred), 4),
    'F1 Score': round(dl_clf_f1, 4),
}])], ignore_index=True).sort_values('Accuracy', ascending=False)
print(combined_clf.to_string(index=False))
➜============================================================ REGRESSION: Predict Calories ============================================================ Model MSE RMSE MAE R² Gradient Boosting XXXX XX.X XX.X 0.8XXX Random Forest XXXX XX.X XX.X 0.8XXX Deep Learning (Neural Net) XXXX XX.X XX.X 0.8XXX Linear Regression XXXX XX.X XX.X 0.7XXX SVR XXXX XX.X XX.X 0.7XXX KNN XXXX XX.X XX.X 0.6XXX============================================================ CLASSIFICATION: Predict High vs Low Calorie ============================================================ Model Accuracy Precision Recall F1 Score Gradient Boosting 0.9XXX 0.9XXX 0.9XXX 0.9XXX Deep Learning (Neural Net) 0.9XXX 0.9XXX 0.9XXX 0.9XXX Random Forest 0.9XXX 0.9XXX 0.9XXX 0.9XXX Logistic Regression 0.8XXX 0.8XXX 0.9XXX 0.8XXX SVC 0.8XXX 0.8XXX 0.9XXX 0.8XXX KNN 0.7XXX 0.8XXX 0.8XXX 0.7XXX
✓Gradient Boosting typically wins — DL is competitive but rarely pulls ahead
The verdict: On this nutritional dataset, traditional tree-based ensembles (Gradient Boosting, Random Forest) typically match or beat the 4-layer neural network — and they train faster, are easier to interpret, and require fewer tuning knobs. For structured nutritional data, deep learning rarely pulls ahead.
07 / Key Insights

What the project
actually tells us.

Six findings from running the full pipeline — including the central question of when deep learning beats machine learning on nutritional tabular data.

// fat ↔ calories corr > 0.7 · GBM often wins
01

Calories, fat, and protein are strongly correlated

The heatmap shows nutritional features are highly interrelated. High-fat items tend to be high-calorie — which is why every model achieves good R² when predicting calories from other features.

02

Some restaurants consistently serve higher-calorie items

The average-calories-by-restaurant bar chart reveals which chains tend to offer more calorically dense food — useful both for ML feature engineering and real-world dietary decisions.

03

A few items are extreme calorie outliers

The calorie distribution is typically right-skewed — a few very high-calorie items (like triple-patty burgers or large combo meals) pull the mean above the median.

04

Tree ensembles match or beat DL on nutritional data

Gradient Boosting and Random Forest typically outperform the neural network on this dataset. Deep learning isn’t always the answer — for structured nutritional data, tree-based ensembles win.

05

Start simple, escalate only when needed

Always begin with Linear/Logistic Regression as a baseline. Move to ensembles for tabular data. Reach for deep learning when data is large or unstructured.

06

Preprocessing matters more than architecture

Correct encoding, handling missing values, scaling without data leakage, and a sensible train/test split usually move the needle more than swapping model architectures.

08 / FAQ

Frequently Asked Questions

How can machine learning predict fast food calorie counts? +

By training a model on nutritional data (fat, protein, carbs, restaurant, food type), ML learns the relationship between those features and calorie counts. Once trained, the model can predict calories for new food items from the same inputs. Features like total_fat, protein, and carbohydrates are typically the strongest predictors.

Which algorithm is best for calorie prediction? +

For this dataset, Gradient Boosting and Random Forest consistently perform at the top. Tree-based ensembles handle mixed feature types, capture non-linear interactions, and resist overfitting on tabular nutritional data. There is no universally “best” algorithm — the right choice depends on dataset size, feature types, and interpretability requirements.

Is deep learning better than machine learning for nutritional data? +

Not necessarily. On this dataset, traditional ML models like Gradient Boosting matched or outperformed a 4-layer neural network. Deep learning tends to pull ahead on very large datasets or unstructured inputs (images, text, audio). For structured nutritional data, tree-based ensembles are typically faster, simpler, and equally accurate.

What is the Fast Food Calorie Shock dataset? +

The Fast Food Calorie Shock — Food vs Workout Burn dataset on Kaggle contains nutritional information for fast food items along with the exercise equivalents needed to burn those calories. It’s a great dataset for learning ML because it combines categorical data (restaurant, food type) with numerical data (calories, fat, protein).

Run the project
yourself.

Grab the Fast Food Calorie Shock dataset from Kaggle, install the stack with one pip command, and run every cell end-to-end. Or click “Copy Full Project Code” at the top of this page to get the entire project in your clipboard.

Fast food items5 ML models2 DL networksFull source code
Scroll to Top