Clinical Health EDA with Git Branching

Clean and analyze a real clinical dataset using pandas, seaborn, and Git.

Introduction

30 Second Summary

When a doctor reviews your lab results, they trust that every number is real. But what happens when a dataset of patient records hides hundreds of missing values behind innocent-looking zeros?

In this project, you will perform an exploratory data analysis on a real clinical dataset containing 768 patient records. You will uncover disguised missing data, clean it, and build visualizations that reveal which health metrics most strongly predict diabetes.

What You'll Build

You will run a Jupyter notebook that loads 768 real patient records into a pandas DataFrame, exposes missing values hiding as zeros, and produces a correlation heatmap that reveals the strongest predictor of diabetes.

By the end of this project, you'll have:

  • A cleaned clinical dataset where you can point to exactly which measurements had hidden zeros and verify that every value now holds a real, imputed number.
  • A set of statistical visualizations including histograms, boxplots, and a correlation heatmap that visually prove which health metrics matter most for predicting diabetes.
  • A Git feature-branch workflow with a commit history you can show to any team, where each analysis phase was developed on its own branch and merged back to main.
  • Secret Mission: an optional challenge to push your data analysis skills further.

Are there any prerequisites?

This project assumes you already have Python, VS Code, and Git installed on a Windows machine. If you need to install any of these tools, do that before starting Step 1.

Before We Start

Before we dive in, let's lock in what you're about to build and why it matters. Taking a moment to commit to the goal now makes every step that follows click into place.

Set Up Your Data Science Environment

Before you can explore a single patient record, you need a workspace that keeps your project organized and your results reproducible. A dedicated folder with its own Python environment ensures your data science packages don't interfere with anything else on your machine.

In this step, you'll create a project folder, set up an isolated virtual environment, and install the packages you need. You'll also initialize a Git repository and configure VS Code with the extensions that turn it into a full data science workstation.

In this step, get ready to:
  • Create a project folder with an isolated Python virtual environment and install data science packages.
  • Initialize a Git repository and commit your project setup files.
  • Create a Jupyter notebook in VS Code with the correct kernel selected.
Create the project folder and virtual environment

A virtual environment is a self-contained copy of Python that holds only the packages your project needs. This prevents version conflicts between different projects on your machine.

  • Press the Windows key to open your search bar.
  • Type PowerShell and press Enter to open it.
  • Move to your Desktop by running this command:
cd ~/Desktop
  • Create your project folder and move into it by running these commands:
mkdir diabetes-eda
cd diabetes-eda
  • Create your virtual environment and activate it by running these commands:
python -m venv .venv
.venv\Scripts\activate

You should see (.venv) appear at the start of your terminal prompt. This confirms the virtual environment is active.

Don't see (.venv) in your prompt?

If you get an error about running scripts being disabled, PowerShell's execution policy is blocking the activation script. Run Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy RemoteSigned and then try the activate command again.

Make sure you are in the diabetes-eda folder. Run pwd to check your current directory.

Help me activate my Python virtual environment on Windows.

  • Install the data science packages by running this command:
pip install pandas matplotlib seaborn numpy ipykernel

What are these packages?

  • pandas loads and manipulates tabular data (think spreadsheets in Python).
  • matplotlib is the core plotting library for creating charts and graphs.
  • seaborn builds on matplotlib and adds statistical visualizations like heatmaps and boxplots.
  • numpy handles numerical operations and is used under the hood by pandas.
  • ipykernel lets VS Code run your Jupyter notebook cells using your virtual environment.

You should see a stream of download and install messages ending with Successfully installed followed by a list of package names.

Before you run the next command, what do you think will happen if the packages installed correctly?

  • Verify all packages are available by running this command:
python -c "import pandas; import matplotlib; import seaborn; print('All packages installed')"

You should see All packages installed printed in the terminal.

Seeing a ModuleNotFoundError?

Make sure (.venv) still appears in your prompt. If it disappeared, reactivate by running .venv\Scripts\activate and then run the pip install command again.

Help me fix a ModuleNotFoundError after installing packages in my virtual environment.

Open VS Code and initialize version control

Now that your environment is ready, you need version control to track every change you make to the analysis. Git lets you create a clean history of your work and experiment on separate branches without risking your main code.

  • Open the project in VS Code by running this command:
code .

VS Code opens with your diabetes-eda folder loaded in the Explorer sidebar on the left.

VS Code didn't open?

If you see an error that code is not recognized, VS Code may not be in your system PATH. Press the Windows key, type Visual Studio Code, and open it manually. Then click File, then Open Folder, and select the diabetes-eda folder on your Desktop.

Next, you need two VS Code extensions that add Jupyter notebook and Python support.

  • Click the Extensions icon in the left sidebar (it looks like four small squares).
  • Type Python in the search bar at the top of the Extensions panel.
  • Find the extension published by Microsoft (extension ID: ms-python.python) and click Install.
  • Search for Jupyter in the Extensions panel.
  • Find the extension published by Microsoft (extension ID: ms-toolsai.jupyter) and click Install.

Already have these extensions?

If you see Uninstall instead of Install on either extension, it's already set up. Skip to the next instruction.

  • Open the integrated terminal by pressing Ctrl+` (macOS: Cmd+`).
  • Activate the virtual environment in this terminal by running:
.venv\Scripts\activate

Confirm you see (.venv) in the terminal prompt before continuing.

  • Initialize a Git repository by running this command:
git init

You should see a message saying the repository was initialized.

Now create two project files. The first tells Git which files to ignore. The second records your project's package dependencies.

  • In the Explorer sidebar, right-click in the empty space below any listed files.
  • Select New File.
  • Type .gitignore as the file name and press Enter.
  • Paste the following contents into the file:
__pycache__/
*.pyc
.ipynb_checkpoints/
.venv/

What does .gitignore do?

This file tells Git to skip certain files and folders when tracking changes. You don't want to commit your virtual environment (.venv/), compiled Python files (__pycache__/), or Jupyter checkpoint files.

  • Save the file with Ctrl+S (macOS: Cmd+S).
  • Right-click in the Explorer sidebar again and select New File.
  • Type requirements.txt as the file name and press Enter.
  • Paste the following contents into the file:
pandas
matplotlib
seaborn
numpy
ipykernel

What is requirements.txt?

This file records every Python package your project depends on. Anyone who clones your repository can install the same packages by running pip install -r requirements.txt. It's a standard convention in Python projects.

  • Save requirements.txt with Ctrl+S (macOS: Cmd+S).
  • Confirm both files exist by running this in the integrated terminal:
ls

You should see .gitignore, .venv, and requirements.txt in the output.

  • Commit these setup files to Git by running these commands:
git add .
git commit -m "Initial commit: project setup with .gitignore and requirements"

You should see output listing the files that were committed, including .gitignore and requirements.txt.

Git asking you to set your name and email?

If Git prompts you to configure your identity, run these two commands with your own name and email before trying the commit again:

git config --global user.name "Your Name"
git config --global user.email "your.email@example.com"

Help me configure Git for the first time on Windows.

✔️ Awesome, I've got everything!

Great. Double check that you've saved both files.

ⓧ I'd like to double check the full code

Here's what each file should contain.

__pycache__/
*.pyc
.ipynb_checkpoints/
.venv/
pandas
matplotlib
seaborn
numpy
ipykernel
Create the Jupyter notebook

Jupyter notebooks let you write and run Python code in small cells, seeing results inline. They're the standard tool for data exploration because you can mix code, output, and charts in one document.

  • Open the Command Palette by pressing Ctrl+Shift+P (macOS: Cmd+Shift+P).
  • Type Jupyter: Create New Jupyter Notebook and select it from the dropdown.
  • A new notebook tab opens. Save it immediately by pressing Ctrl+S (macOS: Cmd+S).
  • In the save dialog, name the file diabetes_eda.ipynb and save it in the diabetes-eda folder.

The last thing to do is connect the notebook to your virtual environment so it uses the packages you installed.

  • Click Select Kernel in the top-right corner of the notebook.
  • Select Python Environments from the dropdown that appears.
  • Choose the option that shows .venv in its path. It may display as .venv (Python 3.x.x) or similar.

The top-right corner of the notebook now shows the .venv kernel name instead of Select Kernel. This confirms your notebook is connected to the virtual environment where your packages live.

Don't see .venv in the kernel list?

Make sure ipykernel is installed. Switch to your integrated terminal, confirm (.venv) is active, and run pip install ipykernel. Then click the kernel selector again.

If it still doesn't appear, open the Command Palette and search for Notebook: Select Notebook Kernel to access the full kernel picker.

Help me connect my Jupyter notebook to my virtual environment in VS Code.

Your data science environment is locked and loaded. Next up, you'll load a real clinical dataset and get your first look at the patient records.

Load and Explore the Raw Data

Your environment is set up and your notebook is ready. Now it's time to meet the dataset you'll be analyzing: a real collection of clinical records from 768 patients.

Before you can draw any conclusions, you need to see what the raw data looks like. In this step, you'll load the dataset, run summary statistics, and check for missing values. Pay close attention to the numbers you see.

In this step, get ready to:
  • Load the Pima Indians Diabetes Dataset into a pandas DataFrame.
  • Run summary statistics and check for missing values.
  • Commit your initial exploration to Git.
Import libraries and load the dataset

The Pima Indians Diabetes Dataset is a real clinical dataset from the National Institute of Diabetes and Digestive and Kidney Diseases. It contains 768 patient records with 8 health measurements plus a diabetes outcome column.

The raw CSV file is hosted on GitHub with no header row, so you'll need to supply column names yourself.

  • In the first cell of your diabetes_eda.ipynb notebook, add these import statements:
# Cell 1: Imports
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
  • Click the + Code button below Cell 1 to create a new cell.
  • Add this code to load the dataset from a public URL:
# Cell 2: Load dataset
url = "https://raw.githubusercontent.com/jbrownlee/Datasets/master/pima-indians-diabetes.data.csv"
columns = [
    "Pregnancies", "Glucose", "BloodPressure", "SkinThickness",
    "Insulin", "BMI", "DiabetesPedigreeFunction", "Age", "Outcome"
]
df = pd.read_csv(url, header=None, names=columns)
print(f"Dataset shape: {df.shape}")
df.head(10)

What does this code do?

pd.read_csv(url, header=None, names=columns) downloads the CSV directly from a URL. header=None tells pandas the file has no header row, and names=columns assigns the column names you defined.

df.shape returns the number of rows and columns as a tuple. df.head(10) displays the first 10 rows so you can see the raw patient records.

  • Run both cells by pressing Shift+Enter in each cell, starting from Cell 1.

Cell 1 produces no visible output (imports run silently). Cell 2 prints Dataset shape: (768, 9) followed by a table showing the first 10 patient records with columns like Pregnancies, Glucose, and BloodPressure.

What is the Pima Indians Diabetes Dataset?

This dataset comes from the National Institute of Diabetes and Digestive and Kidney Diseases. Every record is from a female patient of Pima Indian heritage, at least 21 years old.

The 8 input columns capture health measurements like glucose tolerance, blood pressure, and BMI. The Outcome column is 1 if the patient developed diabetes and 0 if they did not.

Seeing a connection error or empty output?

  • Make sure you are connected to the internet. pd.read_csv() fetches the file from a remote URL.
  • Check that the kernel shown in the top right of the notebook is your .venv environment, not a system Python. If it shows a different kernel, click it and select the .venv interpreter.
  • If you see a ModuleNotFoundError for pandas, your kernel is not using the virtual environment where you installed the packages. Help me fix a ModuleNotFoundError when running my notebook cell.
Run initial summary statistics and check for missing values

You have 768 rows and 9 columns of patient data. The next question is: how clean is this data? Summary statistics and a missing-value check will tell you.

  • Create a new cell below Cell 2 by clicking + Code.
  • Add this code to generate summary statistics for every column:
# Cell 3: Summary statistics
df.describe()
  • Run Cell 3 by pressing Shift+Enter.

You should see a table with rows for count, mean, std, min, 25%, 50%, 75%, and max. Take a close look at the min row. Several columns show 0.000000 as the minimum value.

Before you check for missing values, how many do you think this dataset has? Make a prediction based on the min values you just saw.

  • Create another new cell and add this code to check for null values:
# Cell 4: Check for missing values
print("Missing values per column:")
print(df.isnull().sum())
print(f"\nTotal missing values: {df.isnull().sum().sum()}")

What does this code do?

df.isnull().sum() counts how many NaN (null) values exist in each column. df.isnull().sum().sum() totals all the nulls across the entire DataFrame.

  • Run Cell 4 by pressing Shift+Enter.

The result says 0 missing values for every column. Total missing values: 0. The data looks perfectly clean.

Wait. Is this data really clean?

Scroll back up to your df.describe() output and look at the min row again. Glucose, BloodPressure, SkinThickness, Insulin, and BMI all show a minimum of 0.

A patient cannot have a glucose level of 0. A BMI of 0 is physically impossible. A blood pressure of 0 means the patient is dead. Those zeros are not real measurements. They are missing data hiding in plain sight.

The null check reported zero missing values because the dataset used 0 instead of NaN to represent missing data. You'll unmask and fix this problem in the next step.

✔️ Awesome, I've got everything!

Make sure you've saved diabetes_eda.ipynb by pressing Ctrl+S.

ⓧ I'd like to double check the full code

Here is the full notebook content across all 4 cells. Compare each cell against your notebook:

# Cell 1: Imports
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns

# Cell 2: Load dataset
url = "https://raw.githubusercontent.com/jbrownlee/Datasets/master/pima-indians-diabetes.data.csv"
columns = [
    "Pregnancies", "Glucose", "BloodPressure", "SkinThickness",
    "Insulin", "BMI", "DiabetesPedigreeFunction", "Age", "Outcome"
]
df = pd.read_csv(url, header=None, names=columns)
print(f"Dataset shape: {df.shape}")
df.head(10)

# Cell 3: Summary statistics
df.describe()

# Cell 4: Check for missing values
print("Missing values per column:")
print(df.isnull().sum())
print(f"\nTotal missing values: {df.isnull().sum().sum()}")
Commit the initial exploration to main

You have your first round of analysis saved in the notebook. Time to lock it into your Git history before making any changes to the data.

  • Save diabetes_eda.ipynb by pressing Ctrl+S.
  • Switch to the integrated terminal in VS Code by pressing Ctrl+`.
  • Commit your notebook by running these commands:
git add diabetes_eda.ipynb
git commit -m "feat: load dataset and run initial exploration"
  • You should see a message confirming the commit with 1 file changed.

Seeing 'nothing to commit'?

  • Make sure you saved the notebook with Ctrl+S before running git add. Unsaved changes in VS Code do not appear on disk.
  • Check that your terminal is in the diabetes-eda folder by running pwd (macOS/Linux) or cd (Windows PowerShell) to see the current directory.
  • Help me fix a 'nothing to commit' message when trying to commit my notebook.

Your initial exploration is committed. You loaded 768 patient records, saw that standard null checks report zero missing values, and spotted something suspicious in the min row. Next up, you'll unmask those impossible zeros and clean the data so your analysis can actually be trusted.

Unmask and Clean the Hidden Missing Data

In the last step, you loaded the dataset and checked for missing values. df.isnull().sum() reported zero nulls across all 9 columns, making the data look perfectly clean.

But the df.describe() output told a different story. Columns like Glucose, BloodPressure, and BMI showed minimum values of 0, which is physically impossible for a living patient.

Those zeros are missing data hiding in plain sight. In this step, you will unmask the hidden zeros and replace them with reliable values using a Git feature branch workflow.

In this step, get ready to:
  • Count how many hidden zeros exist in 5 medical columns.
  • Replace impossible zeros with NaN and impute with median values.
  • Commit the cleaned data on a Git feature branch and merge it back to main.
Create a feature branch and count the hidden zeros

Feature branches let you isolate each phase of your analysis so that main always contains a stable version of the notebook. You will create a branch specifically for the data-cleaning work.

  • Switch to the VS Code integrated terminal and create a new branch by running this command:
git checkout -b feature/data-cleaning

You should see Switched to a new branch 'feature/data-cleaning' printed in the terminal.

Seeing a Git error?

Make sure your virtual environment is activated (you should see (.venv) in your terminal prompt). If the terminal shows a different directory, run cd diabetes-eda first.

help me fix a Git checkout error in my diabetes-eda project

Now it is time to see how many zeros are lurking in the medical columns. Remember, these are values like Glucose, BloodPressure, and BMI where 0 is not a valid reading.

  • Count the hidden zeros by adding this code in a new notebook cell (Cell 5):
# Cell 5: Count zeros in medical columns
zero_columns = ["Glucose", "BloodPressure", "SkinThickness", "Insulin", "BMI"]
print("Zero counts in medical columns:")
print((df[zero_columns] == 0).sum())

What does this code do?

  • zero_columns lists the 5 columns where a value of 0 is physiologically impossible.
  • (df[zero_columns] == 0).sum() checks every cell in those columns for a zero, then counts how many zeros appear in each column.
  • Run the cell by pressing Shift+Enter.

You should see Insulin with 374 zeros, SkinThickness with 227, BloodPressure with 35, BMI with 11, and Glucose with 5. That is 652 data points across 5 columns disguised as zeros instead of being marked as missing.

Not seeing the zero counts?

Make sure you ran all earlier cells first (Cells 1 through 4). The df variable must already exist in memory from Cell 2.

Check that the kernel in the top-right corner of the notebook shows your .venv environment. If it shows a different kernel, click it and select the .venv Python interpreter.

help me debug why my zero counts cell is not working

Replace zeros with NaN, visualize, and impute with median

You now know where the hidden zeros are. The next task is to convert them into proper missing values, see the full picture, and then fill them in with sensible replacements.

  • Replace all zeros in the medical columns with NaN by adding this code in a new cell (Cell 6):
# Cell 6: Replace zeros with NaN
df[zero_columns] = df[zero_columns].replace(0, np.nan)
print("True missing values after unmasking zeros:")
print(df.isnull().sum())

What does this code do?

  • .replace(0, np.nan) swaps every 0 in the five medical columns with NaN (Not a Number), which is how pandas represents missing data.
  • Now df.isnull().sum() will finally report the true count of missing values that were hiding as zeros all along.
  • Run the cell.

You should see Insulin with 374 missing, SkinThickness with 227, BloodPressure with 35, BMI with 11, and Glucose with 5. The "zero missing values" claim from Step 2 is now fully exposed.

Still seeing 0 missing values?

Double check that Cell 6 references zero_columns, not a hardcoded list. The variable was defined in Cell 5 and must be in memory.

help me figure out why my zeros were not replaced with NaN

Numbers are helpful, but a chart makes the scale of the problem immediately obvious.

  • Visualize the missing data as a bar chart by adding this code in a new cell (Cell 7):
# Cell 7: Visualize missing data
fig, ax = plt.subplots(figsize=(8, 5))
missing = df.isnull().sum()
missing = missing[missing > 0].sort_values(ascending=False)
missing.plot(kind="bar", ax=ax, color="coral", edgecolor="white")
ax.set_title("Missing Values After Unmasking Zeros")
ax.set_ylabel("Count")
plt.tight_layout()
plt.show()

What does this code do?

  • missing[missing > 0] filters to only the columns that actually have missing values, so columns like Pregnancies and Age (which had no zeros) do not appear.
  • .sort_values(ascending=False) orders the bars from tallest to shortest, making it easy to see which column has the worst missing data problem.
  • Run the cell.

You should see a bar chart with Insulin as the tallest bar (374), followed by SkinThickness (227), BloodPressure (35), BMI (11), and Glucose (5).

Bar chart not displaying?

Make sure you ran Cell 6 first. The bar chart relies on the NaN values that Cell 6 created. If you skipped Cell 6, all columns will show 0 missing and no bars will appear.

If you see a blank plot or no output, check that matplotlib was imported in Cell 1.

help me fix my missing values bar chart

The chart makes it clear that Insulin has the most severe missing data problem. Nearly half of all Insulin readings in the dataset were recorded as zeros instead of being properly marked as missing.

Why use the median instead of the mean?

Medical data often has extreme outliers. For example, Insulin values in this dataset range up to 846. The mean would be pulled toward those outliers, producing a less representative fill value.

The median (the middle value when all values are sorted) is resistant to outliers, making it a more reliable choice for skewed clinical distributions.

Before you run the next cell, what do you think df.isnull().sum().sum() will show after the imputation?

  • Impute the missing values with each column's median by adding this code in a new cell (Cell 8):
# Cell 8: Impute with median
for col in zero_columns:
    median_val = df[col].median()
    df[col] = df[col].fillna(median_val)
    print(f"{col}: imputed with median = {median_val}")

print(f"\nRemaining missing values: {df.isnull().sum().sum()}")

What does this code do?

  • The loop iterates through each of the 5 medical columns, calculates the median of the non-missing values, and stores it in median_val.
  • .fillna(median_val) replaces every NaN in the column with the calculated median.
  • The final print confirms that zero missing values remain in the entire DataFrame.
  • Run the cell.

You should see each column's median printed (for example, Glucose imputed with its median value), followed by Remaining missing values: 0. The dataset is now fully clean.

Still seeing missing values after imputation?

Make sure your Cell 8 code uses df[col] = df[col].fillna(median_val) with the assignment back to df[col]. Without the assignment, .fillna() returns a new Series but does not modify the original DataFrame.

help me fix my median imputation code

✔️ Awesome, I've got everything!

Great. Make sure you have saved diabetes_eda.ipynb before moving on to the commit step.

ⓧ I'd like to double check the full code

Your notebook now has 8 cells total. Scroll through and confirm each one is present in this order:

  • Cell 1: Imports (pandas, numpy, matplotlib, seaborn).
  • Cell 2: Load dataset from URL, print shape, display df.head(10).
  • Cell 3: Summary statistics with df.describe().
  • Cell 4: Check for missing values with df.isnull().sum().
  • Cell 5: Count zeros in zero_columns.
  • Cell 6: Replace zeros with np.nan and print true missing counts.
  • Cell 7: Bar chart of missing values (Insulin tallest at 374).
  • Cell 8: Impute with median, remaining missing values is 0.
Commit and merge back to main

The data-cleaning work is done. Time to save it to your Git history and merge it back into main.

  • Save diabetes_eda.ipynb by pressing Ctrl+S.
  • Commit your changes and merge the branch back to main by running these commands in the terminal:
git add diabetes_eda.ipynb
git commit -m "feat: unmask zero values as missing data and impute with median"
git checkout main
git merge feature/data-cleaning

What do these commands do?

  • git add stages the updated notebook for commit.
  • git commit -m saves a snapshot of your work on the feature/data-cleaning branch with a descriptive message.
  • git checkout main switches you back to the main branch.
  • git merge feature/data-cleaning brings the data-cleaning work into main, combining the branch histories.

You should see a merge message confirencing the fast-forward merge. Your terminal prompt should now show main as the active branch.

Seeing a merge conflict?

Merge conflicts should not happen here because you are the only person editing the notebook. If you see one, it usually means you edited the notebook on main after creating the branch. Run git merge --abort to undo the merge attempt, then re-check your branch history.

help me resolve a Git merge conflict in my notebook

Your dataset is clean, your Git history is tidy, and you have a complete record of the data-cleaning phase. Next up, you will visualize how the health metrics are distributed and see which ones look different between diabetic and non-diabetic patients.

Visualize Feature Distributions

In the previous step, you unmasked hundreds of hidden zeros and replaced them with median-imputed values. Your dataset is now clean and trustworthy.

Clean data alone does not tell you much. You need to see the shape of each feature's distribution and how those distributions differ between diabetic and non-diabetic patients. That visual comparison will guide the correlation analysis you build in the next step.

In this step, get ready to:
  • Create a Git feature branch for the visualization phase.
  • Plot histograms showing the distribution of all 9 features.
  • Plot boxplots comparing each feature between diabetic and non-diabetic patients.
Create a feature branch and plot histograms

Each analysis phase gets its own Git branch. This keeps your commit history organized and mirrors how professional data science teams separate their work.

  • In the VS Code integrated terminal, create and switch to a new branch by running this command:
git checkout -b feature/visualization

You should see Switched to a new branch 'feature/visualization' printed in the terminal.

Now you are ready to build the first visualization. Histograms show you the overall shape of each feature's distribution after cleaning.

  • Switch back to diabetes_eda.ipynb in the editor.
  • Click the + Code button at the top of the notebook to add a new cell below Cell 8.
  • Paste the following code into the new cell:
# Cell 9: Feature distribution histograms
fig, axes = plt.subplots(3, 3, figsize=(14, 10))
for i, col in enumerate(df.columns):
    ax = axes[i // 3, i % 3]
    df[col].hist(bins=25, ax=ax, color="steelblue", edgecolor="white")
    ax.set_title(col)
fig.suptitle("Feature Distributions (After Cleaning)", fontsize=14)
plt.tight_layout()
plt.show()

What does this code do?

  • plt.subplots(3, 3) creates a 3x3 grid of subplots, one for each of the 9 columns in the DataFrame.
  • The loop iterates over every column and places a histogram in the matching grid position using integer division (i // 3 for row, i % 3 for column).
  • bins=25 splits each feature's value range into 25 bars, giving you a detailed view of how values are spread.
  • Run the cell by clicking the play button to its left, or pressing Shift+Enter.

You should see a 3x3 grid of histograms appear below the cell. Each histogram shows the distribution shape of one feature after cleaning.

Not seeing any charts?

  • Make sure you ran all the cells above this one first (Cells 1 through 8). The df variable must exist from earlier cells.
  • Check that your kernel is set to the .venv environment. The kernel name appears in the top-right of the notebook.
  • Help me debug why my histogram cell is not producing output.
Plot boxplots comparing diabetic vs non-diabetic groups

Histograms show overall distribution shapes, but they do not tell you how features differ between groups. Boxplots split each feature by the Outcome column so you can compare diabetic patients (Outcome 1) against non-diabetic patients (Outcome 0) side by side.

  • Add a new cell below Cell 9 and paste the following code:
# Cell 10: Boxplots by Outcome
fig, axes = plt.subplots(2, 4, figsize=(16, 8))
features = [col for col in df.columns if col != "Outcome"]
for i, col in enumerate(features):
    ax = axes[i // 4, i % 4]
    sns.boxplot(x="Outcome", y=col, data=df, ax=ax, palette="Set2")
    ax.set_title(col)
fig.suptitle("Feature Distributions by Diabetes Outcome", fontsize=14)
plt.tight_layout()
plt.show()

What does this code do?

  • The features list grabs every column except Outcome, since Outcome is the grouping variable, not a feature to compare.
  • sns.boxplot(x="Outcome", y=col) creates a seaborn boxplot that splits each feature by diabetes status, showing the median, quartiles, and outliers for each group.
  • The 2x4 grid fits all 8 features neatly. Each plot makes it easy to spot which features have noticeably different distributions between the two groups.

Before you run this cell, think about which features you expect to differ most between diabetic and non-diabetic patients based on the histograms you just saw.

  • Run the cell with Shift+Enter.

You should see a 2x4 grid of boxplots. Look at the Glucose and BMI plots. The diabetic group (Outcome 1) shows notably higher values for both features compared to the non-diabetic group (Outcome 0).

Seeing an error about Outcome or columns?

  • If you see a KeyError about Outcome, make sure Cell 2 (which loads the dataset with named columns) was run successfully.
  • If the chart looks squished or overlapping, check that plt.tight_layout() is present before plt.show().
  • Help me fix my boxplot cell that is throwing an error.

✔️ Awesome, I've got everything!

Great. Make sure you have saved diabetes_eda.ipynb before moving on to the commit.

ⓧ I'd like to double check the full code

Scroll through your notebook and confirm you have these two new cells in order, below Cell 8:

  • Cell 9: Feature distribution histograms. Creates a 3x3 subplot grid with plt.subplots(3, 3), loops over all columns, and calls .hist(bins=25) on each.
  • Cell 10: Boxplots by Outcome . Creates a 2x4 subplot grid, filters out the Outcome column, and calls sns.boxplot(x="Outcome", y=col) for each feature.

Both cells should produce chart output when run. If either is missing, add it from the code blocks above and re-run.

Commit and merge back to main

Your visualization cells are complete. Time to commit this work on the feature/visualization branch and merge it back to main.

  • Save diabetes_eda.ipynb by pressing Ctrl+S.
  • Switch to the VS Code integrated terminal and commit, then merge by running these commands:
git add diabetes_eda.ipynb
git commit -m "feat: add distribution histograms and outcome boxplots"
git checkout main
git merge feature/visualization

What do these commands do?

  • git add stages the notebook changes on the feature/visualization branch.
  • git commit saves a snapshot of your visualization work with a descriptive message.
  • git checkout main switches back to the main branch, and git merge brings the visualization branch's commits into main.

You should see a merge message confirencing the fast-forward merge. Your visualization work is now part of the main branch history.

Seeing 'nothing to commit' or a merge conflict?

  • If you see "nothing to commit", make sure you saved the notebook file before running git add. Save it, then run the commands again.
  • If you see a merge conflict, it likely means a cell was edited on main after the last merge. Run git merge --abort to cancel, then try the commit and merge again.
  • Help me resolve my Git commit or merge issue.

You now have two visualization cells committed and merged. The histograms revealed overall distribution shapes, and the boxplots showed that Glucose and BMI stand out as features that differ most between the two patient groups. Next up, you will quantify those differences with a correlation analysis to confirm exactly which features predict diabetes most strongly.

Analyze Correlations with Diabetes

Your histograms and boxplots from Step 4 showed that features like Glucose and BMI look different between diabetic and non-diabetic patients.

"Looking different" is not precise enough to draw conclusions from. In this step, you will compute correlation coefficients that quantify exactly how strongly each feature relates to the diabetes outcome. You will also build a pairplot to see the strongest relationships all at once.

In this step, get ready to:
  • Build a correlation heatmap showing how every feature relates to every other feature.
  • Identify the strongest predictors of diabetes from the correlation values.
  • Create a pairplot of the top correlated features, colored by diabetes status.
Create a feature branch and build the correlation heatmap

A correlation matrix is a grid of numbers showing how strongly each pair of features moves together. Values close to +1 or -1 mean a strong relationship. Values near 0 mean the features are largely unrelated.

  • Switch to the VS Code integrated terminal and create a new Git branch for this analysis phase by running:
git checkout -b feature/correlation

You should see a message confirming you switched to the new feature/correlation branch.

Based on the boxplots you built in Step 4, which feature do you think will show the strongest correlation with the Outcome column?

  • Return to diabetes_eda.ipynb and create a new cell below Cell 10. Add the following code to compute the correlation matrix and display it as a seaborn heatmap:
# Cell 11: Correlation heatmap
fig, ax = plt.subplots(figsize=(10, 8))
corr = df.corr(numeric_only=True)
sns.heatmap(corr, annot=True, fmt=".2f", cmap="coolwarm", center=0,
            square=True, linewidths=0.5, ax=ax)
ax.set_title("Feature Correlation Matrix")
plt.tight_layout()
plt.show()

What does this code do?

  • df.corr(numeric_only=True) computes the pairwise correlation between every numeric column in the DataFrame. The numeric_only=True flag ensures compatibility with both pandas 2.x and 3.x.
  • sns.heatmap() turns the correlation matrix into a color-coded grid. Red squares mean positive correlation, blue means negative, and white means no relationship.
  • annot=True prints the actual correlation numbers on each square so you can read exact values.
  • Run Cell 11 by clicking the play button to the left of the cell, or by pressing Shift+Enter.

You should see a large square heatmap titled "Feature Correlation Matrix". Look at the Outcome row (or column). Glucose shows the highest positive correlation with Outcome at approximately 0.47, followed by BMI and Age.

Seeing a blank or tiny chart?

  • Make sure you ran all previous cells in order first (Cells 1 through 10). The df variable needs to exist in memory for the correlation to compute.
  • If the heatmap looks squished, check that figsize=(10, 8) is set in the plt.subplots() call.
  • Still stuck? My correlation heatmap is blank or not rendering in VS Code. How can I fix this?
Extract top correlations and create a pairplot

The heatmap gives you the big picture, but it is easier to read the exact correlation values when they are sorted in a list. After that, a pairplot will show scatter plots of the top features so you can visually confirm the relationships.

  • Create a new cell below Cell 11. Add this code to extract the correlations with the Outcome column and sort them by strength:
# Cell 12: Correlations with Outcome
outcome_corr = corr["Outcome"].drop("Outcome").sort_values(ascending=False)
print("Correlations with Diabetes Outcome (sorted):")
print(outcome_corr)

What does this code do?

  • corr["Outcome"] pulls just the Outcome column from the full correlation matrix, giving you one correlation value per feature.
  • .drop("Outcome") removes the self-correlation of Outcome with itself (which is always 1.0 and not useful).
  • .sort_values(ascending=False) puts the strongest positive correlations at the top of the list so you can instantly see the most important predictors.
  • Run Cell 12.

You should see a sorted list of correlations with Glucose at the top (approximately 0.47), followed by BMI and Age. This confirms what the boxplots hinted at: Glucose is the single strongest predictor of diabetes in this dataset.

  • Create a new cell below Cell 12. Add this code to build a pairplot of the four most correlated features:
# Cell 13: Pairplot of top correlated features
top_cols = outcome_corr.head(4).index.tolist() + ["Outcome"]
sns.pairplot(df[top_cols], hue="Outcome", palette="Set1", diag_kind="kde")
plt.suptitle("Pairplot of Top Correlated Features", y=1.02)
plt.show()

What does this code do?

  • outcome_corr.head(4).index.tolist() grabs the names of the top 4 features from the sorted correlation list you just printed.
  • sns.pairplot() creates a grid of scatter plots for every pair of those features. The diagonal shows density curves (diag_kind="kde") instead of histograms.
  • hue="Outcome" colors each data point by diabetes status, so you can see how the two groups separate across different feature combinations.
  • Run Cell 13. This cell may take a few seconds because seaborn is plotting many scatter plots at once.

You should see a grid of scatter plots titled "Pairplot of Top Correlated Features", with red and blue dots representing diabetic and non-diabetic patients. The diagonal shows density curves for each feature split by group.

Pairplot not showing or taking too long?

  • Make sure Cell 12 ran successfully before Cell 13. Cell 13 depends on the outcome_corr variable that Cell 12 creates.
  • Pairplots can take 5-10 seconds to render on slower machines. Wait for the cell's run indicator to finish before assuming something is wrong.
  • Need more help? My seaborn pairplot is not rendering or is throwing an error. What should I check?

✔️ Awesome, I've got everything!

Great. Make sure you have saved diabetes_eda.ipynb before moving on to the commit step.

ⓧ I'd like to double check the full code

Scroll up through your notebook and confirm that you have the following three cells, in order, after Cell 10:

  • Cell 11: Correlation heatmap. Computes df.corr(numeric_only=True) and displays a seaborn heatmap with annotations.
  • Cell 12: Correlations with Outcome . Extracts, sorts, and prints the correlations with the Outcome column.
  • Cell 13: Pairplot of top correlated features . Creates a pairplot of the top 4 features plus Outcome, colored by diabetes status.

If any cell is missing, scroll back up to the matching substep and add it. Then save the file.

Commit and merge back to main

Your correlation analysis is complete. Time to lock it into your Git history and merge this branch back to main, just like you did with the data-cleaning and visualization branches.

  • Save diabetes_eda.ipynb by pressing Ctrl+S.
  • Switch to the integrated terminal and commit your changes, then merge back to main by running these commands:
git add diabetes_eda.ipynb
git commit -m "feat: add correlation heatmap and pairplot analysis"
git checkout main
git merge feature/correlation

What do these commands do?

  • git add stages your updated notebook for commit.
  • git commit -m saves a snapshot of the correlation analysis on the feature/correlation branch.
  • git checkout main switches you back to the main branch. git merge feature/correlation brings the correlation work into main.

You have now merged three feature branches into main across this project. Before you run the next command, how many merge commits do you expect to see in the Git log?

  • View your full branching history by running:
git log --oneline --graph

You should see a clean history showing your initial commit, followed by the three feature-branch merges: feature/data-cleaning, feature/visualization, and feature/correlation. Each phase of your analysis has its own commit with a descriptive message.

Merge failed or seeing conflicts?

  • If Git says you have uncommitted changes, save your notebook first and re-run the git add and git commit commands before switching branches.
  • If you see a merge conflict on the notebook file, it likely means the notebook was modified on main after the last merge. Run git merge --abort to undo and try again after checking which branch you are on with git branch.
  • Need help? My git merge failed with a conflict on my Jupyter notebook file. How do I resolve this?

Your analysis now has hard numbers behind the visual patterns. Glucose at ~0.47 is the single strongest predictor, and your Git log proves every phase was tracked on its own branch. Next up, you will take on an optional Secret Mission to push your analysis even further.

Secret mission

Grouped Statistical Comparison

Your correlation analysis proved Glucose, BMI, and Age matter most for diabetes prediction. But by how much? Stakeholders want concrete numbers, not just correlation coefficients. In this mission, you will compute grouped statistics that quantify exactly how much each health metric differs between diabetic and non-diabetic patients.

Clean Up Your Resources

Clean Up Your Resources

This project runs entirely on your local machine using free, open-source tools. There are no ongoing costs or cloud resources to worry about.

Resources you used:

  • diabetes-eda project folder (includes the .venv virtual environment, diabetes_eda.ipynb notebook, and Git history).
  • VS Code extensions (Python and Jupyter) installed during the project.

Keep everything running

No action needed. Choose this if you plan to revisit or extend the analysis.

  • Your diabetes-eda folder stays on your machine with all notebook cells, cleaned data outputs, and Git history intact.
  • The VS Code Python and Jupyter extensions will be useful for any future data science projects.
  • Everything is local and free, so nothing will incur costs while sitting idle.

Pause - I'll come back to this later

Shut down running processes to free up memory. Your project files stay on disk for when you return.

  • If your virtual environment is still active in the terminal, deactivate it by running:
deactivate
  • Close the VS Code window.
  • When you return, reopen the diabetes-eda folder in VS Code, activate the virtual environment with .venv\Scripts\activate, and pick up where you left off.

Delete - I don't want to use this again

Remove all project files and start fresh. This permanently deletes the project folder, virtual environment, and Git history.

  • Close VS Code if it is still open.
  • If your virtual environment is still active in the terminal, run deactivate first.
  • In your terminal, navigate to the folder that contains diabetes-eda and delete it:

macOS

cd ~/Desktop
rm -rf diabetes-eda

Windows

cd ~\Desktop
Remove-Item -Recurse -Force diabetes-eda
  • To uninstall the VS Code extensions, open the Extensions sidebar in VS Code.
  • Find the Python and Jupyter extensions, click the gear icon on each, and select Uninstall.

Nice Work!

Nice Work!

Nice work! You just built a complete exploratory data analysis of real clinical data, uncovering hidden patterns in diabetes health metrics while practicing a professional Git workflow.

You've learned how to:

  • Uncover hidden missing data disguised as zeros across 5 medical columns in a real clinical dataset, and clean it using median imputation to make the data trustworthy for analysis.
  • Build statistical visualizations including histograms, boxplots, a correlation heatmap, and a pairplot that revealed Glucose as the strongest predictor of diabetes with a ~0.47 correlation.
  • Practice a Git feature-branch workflow, creating and merging 3 separate branches with descriptive commit messages to organize each phase of the analysis.
  • Secret Mission: Built a grouped statistical comparison quantifying the exact percentage difference in every health metric between diabetic and non-diabetic patients.

Ready to quiz yourself?