Dataset Overview and Source

Fetal Health Dataset

For this project I used a dataset of Cardiotocogram (CTG) exam results to look at what separates Normal fetal health from Pathological cases.

Data Source: Kaggle / UCI Machine Learning Repository

Key Variables:

  • baseline_value: Baseline Fetal Heart Rate in bpm
  • accelerations: Number of accelerations per second
  • abnormal_short_term_variability: Percentage of time with abnormal short term variability
  • histogram_tendency: The shape of the CTG histogram
  • fetal_health: The outcome — Normal (1) or Pathological (3)

R Code for Data Preparation

Here is the code I used to load and clean the data:

# Load required libraries
library(ggplot2)
library(plotly)
library(dplyr)

# Load the data
fetal <- read.csv("fetal_health.csv")
colnames(fetal)[1] <- "baseline_value"

# Keep only Normal (1) and Pathological (3) cases
fetal <- fetal[fetal$fetal_health %in% c(1, 3), ]

# Convert to factors so R treats them as categories
fetal$fetal_health <- factor(fetal$fetal_health,
                              levels = c(1, 3),
                              labels = c("Normal", "Pathological"))

3D Plotly: Baseline HR, Variability & Accelerations

3D Plot Analysis

What I noticed:

  • Baseline HR: Honestly, both groups look pretty similar here — they both sit in the 120–160 bpm range, so baseline HR alone does not tell you much.

  • Abnormal Variability: This is where things get interesting. Pathological cases are clearly bunched up at the higher end of the Y-axis, meaning their CTG exams show a lot more abnormal short-term variability.

  • Accelerations: Normal cases are spread out, while Pathological cases cluster at the very bottom near zero. No accelerations seems like a big red flag.

  • Overall: When you combine low accelerations and high abnormal variability, that’s where most of the Pathological cases live.

Plotly Scatter: Baseline HR vs Variability

ggplot Boxplot: Accelerations by Histogram Tendency

ggplot Bar Chart: Health Outcomes by Tendency & Sex

Statistical Analysis: Summary Statistics

# Group by health status and summarize the main variables
fetal %>%
  group_by(fetal_health) %>%
  summarise(
    Count            = n(),
    Mean_Baseline_HR = round(mean(baseline_value), 1),
    Mean_Abnormal_Var = round(mean(abnormal_short_term_variability), 1),
    Mean_Accelerations = round(mean(accelerations), 4)
  )
## # A tibble: 2 × 5
##   fetal_health Count Mean_Baseline_HR Mean_Abnormal_Var Mean_Accelerations
##   <fct>        <int>            <dbl>             <dbl>              <dbl>
## 1 Normal        1655             132               42.5             0.004 
## 2 Pathological   176             132.              64.5             0.0004

Summary Statistics: What the Numbers Tell Us

Breaking down the results:

  • Dataset is imbalanced: There are 1,655 Normal exams compared to only 176 Pathological ones. That is a pretty big gap and something worth keeping in mind when interpreting results.

  • Baseline HR is basically the same: Normal cases average 131.9 bpm and Pathological cases average 131.7 bpm. So looking at heart rate alone would not help a doctor tell them apart.

  • Abnormal variability is a clear signal: Pathological cases average 64.6% abnormal variability versus 42.4% for Normal cases. That is a 22 percentage point difference which is pretty significant.

  • Accelerations are the biggest differentiator: Normal cases average 0.0039 accelerations per second while Pathological cases are near zero at just 0.0003. That gap really stands out.

Statistical Analysis: T-Test

# Two-sample t-test: do the two groups have different acceleration means?
normal_acc  <- fetal$accelerations[fetal$fetal_health == "Normal"]
disease_acc <- fetal$accelerations[fetal$fetal_health == "Pathological"]

t_test_result <- t.test(normal_acc, disease_acc)
t_test_result
## 
##  Welch Two Sample t-test
## 
## data:  normal_acc and disease_acc
## t = 28.966, df = 965.03, p-value < 2.2e-16
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
##  0.003356192 0.003844007
## sample estimates:
##    mean of x    mean of y 
## 0.0039921450 0.0003920455

T-Test: What This Means

Interpreting the results:

  • The p-value is essentially zero (2.2e-16): This tells us the difference in accelerations between the two groups is not just random noise — it is statistically real. This is about as strong as a result gets.

  • The actual difference in means is huge relative to the scale: Normal cases average 0.0039 vs 0.0003 for Pathological. That is more than a 10x difference, which clinically makes a lot of sense.

  • 95% Confidence Interval (0.0033 to 0.0039): We can be pretty confident the true difference in the population falls somewhere in this range.

  • Clinical takeaway: A fetus that is showing very few or no accelerations during a CTG exam should be flagged immediately — the data strongly supports this as a warning sign.

Key Takeaways

What I found from this analysis:

First: Accelerations turned out to be the most important variable by a wide margin. The t-test confirmed that the difference between groups is extremely statistically significant (p < 0.001).

Second: Baseline heart rate was basically useless on its own. Both groups had nearly identical averages, which was actually a bit surprising to me at first.

Third: Abnormal short-term variability is also a strong indicator. Pathological cases showed about 22% higher abnormal variability on average, which paired with low accelerations seems to be the real danger zone.

Clinical Implications and Limitations

Practical takeaways from this data:

Doctors using CTG exams should pay special attention to accelerations and short-term variability — not just baseline heart rate. The baseline number alone can be misleading.

Limitations I noticed:

The dataset has a major class imbalance — about 1,655 Normal cases vs only 176 Pathological. This means any model built on this data would need to account for that, or it would just predict “Normal” almost every time and still look accurate.

Where this could go next:

  • It would be interesting to bring in maternal health data alongside the CTG readings to understand root causes better.
  • Machine learning models that handle imbalanced data (like SMOTE or weighted classifiers) could make better use of this dataset for real predictions.

Thank You