1. Introduction

This project implements a complete end-to-end Machine Learning Operations (MLOps) pipeline in R for predicting heart disease.

The objective of this work is not only to train a machine learning model, but also to follow industry-style ML workflows, including:

This report acts as the execution and documentation layer of the pipeline, while the core logic is implemented in separate R scripts.


2. Project Structure

The project follows a modular and production-oriented structure: r_project/ ├── R/ │ ├── load_data.R │ ├── preprocess.R │ ├── train.R │ └── evaluate.R ├── data/ │ └── heart_cleaned1.csv ├── models/ │ └── rf_model.rds ├── tests/ │ └── test_schema.R │ └── test_reproducibility.R │ └── test_prediction.R │ └── test_failure.R ├── run_train.R ├── run_evaluate.R ├── app.R └── Heart_Disease_Report.Rmd

Each stage of the ML lifecycle is implemented independently and reused across training, evaluation, testing, and reporting.


3. Data Ingestion

The dataset is loaded using the centralized data ingestion module.

source("D:/MLOPS/r_project/R/load_data.R")

data <- load_data("D:/MLOPS/r_project/data/heart_cleaned1.csv")
head(data)
## # A tibble: 6 × 14
##     age   sex chest_pain_type resting_blood_pressure serum_cholesterol
##   <dbl> <dbl>           <dbl>                  <dbl>             <dbl>
## 1    63     1               1                    145               233
## 2    67     1               4                    160               286
## 3    67     1               4                    120               229
## 4    37     1               3                    130               250
## 5    41     0               2                    130               204
## 6    56     1               2                    120               236
## # ℹ 9 more variables: fasting_blood_sugar <dbl>,
## #   resting_electrocardiographic_results <dbl>,
## #   maximum_heart_rate_achieved <dbl>, exercise_induced_angina <dbl>,
## #   st_depression_exercise <dbl>, st_slope <dbl>,
## #   number_of_major_vessels <dbl>, thalassemia <dbl>,
## #   heart_disease_target <dbl>

The load_data() function abstracts file reading and ensures consistent data ingestion across all stages of the pipeline. # 4.Data Preprocessing Preprocessing and train–test splitting are handled using the existing preprocessing module.

source("D:/MLOPS/r_project/R/preprocess.R")
## 
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
## Loading required package: ggplot2
## Loading required package: lattice
data$heart_disease_target <- factor(
  data$heart_disease_target,
  levels = c(0, 1),
  labels = c("no_disease", "disease")
)

splits <- preprocess_data(data, "heart_disease_target")

train_data <- splits$train
test_data  <- splits$test

dim(train_data)
## [1] 238  14
dim(test_data)
## [1] 59 14

5. Model Training

source("D:/MLOPS/r_project/R/train.R")
## randomForest 4.7-1.2
## Type rfNews() to see new features/changes/bug fixes.
## 
## Attaching package: 'randomForest'
## The following object is masked from 'package:ggplot2':
## 
##     margin
## The following object is masked from 'package:dplyr':
## 
##     combine
set.seed(42)

model <- train_model(
  train_data,
  target_col = "heart_disease_target",
  model_type = "random_forest"
)

model
## Random Forest 
## 
## 238 samples
##  13 predictor
##   2 classes: 'no_disease', 'disease' 
## 
## No pre-processing
## Resampling: Cross-Validated (5 fold) 
## Summary of sample sizes: 191, 190, 190, 190, 191 
## Resampling results across tuning parameters:
## 
##   mtry  ROC        Sens       Spec     
##    2    0.8953147  0.8904615  0.7454545
##    7    0.8777972  0.8116923  0.7454545
##   13    0.8690280  0.8116923  0.7545455
## 
## ROC was used to select the optimal model using the largest value.
## The final value used for the model was mtry = 2.

6.Model Persistence

dir.create("models", showWarnings = FALSE)
saveRDS(model, "models/rf_model.rds")

Saving the model as an .rds file enables:

7.Model Evaluation

source("D:/MLOPS/r_project/R/evaluate.R")
## Type 'citation("pROC")' for a citation.
## 
## Attaching package: 'pROC'
## The following objects are masked from 'package:stats':
## 
##     cov, smooth, var
metrics <- evaluate_model(
  model,
  test_data,
  target_col = "heart_disease_target"
)
## Setting levels: control = no_disease, case = disease
## Setting direction: controls < cases
metrics
## $accuracy
## Accuracy 
## 0.779661 
## 
## $roc_auc
## Area under the curve: 0.9271

The evaluation step computes standard classification metrics such as:

This ensures objective assessment of model performance.

8.Reproducibility Verification

set.seed(42)

model_repro <- train_model(
  train_data,
  "heart_disease_target",
  "random_forest"
)

all.equal(model$results, model_repro$results)
## [1] TRUE

Identical results under a fixed seed confirm that the pipeline is deterministic and reproducible.

9.MLOps Readiness

This project demonstrates several core MLOps principles: - Modular code design - Reusable preprocessing and training functions - Reproducible experiments - Model persistence - Automated testing compatibility (testthat) - CI/CD compatibility (GitHub Actions) - Deployment readiness (Plumber API)

10.Conclusion

This report validates a fully functional MLOps pipeline implemented in R for heart disease prediction.

By separating data ingestion, preprocessing, training, evaluation, and reporting into independent components, the project mirrors real-world production ML systems.

Overall, the project demonstrates both machine learning knowledge and MLOps workflow implementation using R.