Deployment PimaIndia Diabetes

Deploy Random Forest Diabetes Prediction (Shiny)

Packages

library(mlbench)
## Warning: package 'mlbench' was built under R version 4.3.3
library(tidymodels)
## ── Attaching packages ────────────────────────────────────── tidymodels 1.4.1 ──
## ✔ broom        1.0.10     ✔ recipes      1.3.1 
## ✔ dials        1.4.2      ✔ rsample      1.3.1 
## ✔ dplyr        1.1.4      ✔ tailor       0.1.0 
## ✔ ggplot2      4.0.1      ✔ tidyr        1.3.1 
## ✔ infer        1.0.9      ✔ tune         2.0.1 
## ✔ modeldata    1.5.1      ✔ workflows    1.3.0 
## ✔ parsnip      1.3.3      ✔ workflowsets 1.1.1 
## ✔ purrr        1.2.0      ✔ yardstick    1.3.2
## Warning: package 'dplyr' was built under R version 4.3.3
## Warning: package 'tidyr' was built under R version 4.3.3
## Warning: package 'yardstick' was built under R version 4.3.3
## ── Conflicts ───────────────────────────────────────── tidymodels_conflicts() ──
## ✖ purrr::discard() masks scales::discard()
## ✖ dplyr::filter()  masks stats::filter()
## ✖ dplyr::lag()     masks stats::lag()
## ✖ recipes::step()  masks stats::step()
library(ranger)
## Warning: package 'ranger' was built under R version 4.3.3
library(dplyr)
library(shiny)
## 
## Attaching package: 'shiny'
## The following object is masked from 'package:infer':
## 
##     observe
library(DT)
## 
## Attaching package: 'DT'
## The following objects are masked from 'package:shiny':
## 
##     dataTableOutput, renderDataTable
library(glue)
## Warning: package 'glue' was built under R version 4.3.3
set.seed(123)

Load Data

Data & target

data("PimaIndiansDiabetes")
df <- PimaIndiansDiabetes

# Pastikan target berbentuk factor
df$diabetes <- as.factor(df$diabetes)

Train dan Save Model

Split data

split <- initial_split(df, prop = 0.8, strata = diabetes)
train <- training(split)

Recipe preprocessing

rec <- recipe(diabetes ~ ., data = train) %>%
  step_impute_median(all_numeric_predictors()) %>%
  step_normalize(all_numeric_predictors())

Random Forest Model Specification

rf_spec <- rand_forest(
  trees = 500,
  mtry = NULL,
  min_n = 5
) %>% 
  set_engine("ranger", importance = "impurity", probability = TRUE) %>%
  set_mode("classification")

Workflow (model + preprocessing)

wf <- workflow() %>%
  add_model(rf_spec) %>%
  add_recipe(rec)

rf_fit <- fit(wf, data = train)
saveRDS(rf_fit, file = "rf_diabetes_workflow.rds")

Shiny App

rf_wf <- readRDS("rf_diabetes_workflow.rds")

# Load dataset untuk referensi default UI values
data("PimaIndiansDiabetes")
df <- PimaIndiansDiabetes

num_cols <- names(df)[names(df) != "diabetes"]

# Summary untuk nilai default input
num_summary <- df %>% summarise(
  across(where(is.numeric), list(
    min = ~min(., na.rm = TRUE),
    max = ~max(., na.rm = TRUE),
    med = ~median(., na.rm = TRUE)
  ))
)

med <- function(nm) as.numeric(num_summary[[paste0(nm, "_med")]])


# UI
ui <- fluidPage(
  
  titlePanel("Prediksi Diabetes (Random Forest)"),
  tags$small("Model sudah dilatih & disimpan — hanya untuk prediksi."),
  
  tabsetPanel(
    
    # TAB 1: Single Prediction
    tabPanel(
      "Single Prediction",
      sidebarLayout(
        sidebarPanel(
          
          do.call(tagList, lapply(num_cols, function(col){
  numericInput(col, col, value = med(col))
}))
,
          
          actionButton("predict_one", "Prediksi")
        ),
        mainPanel(
          h4("Hasil Prediksi"),
          verbatimTextOutput("single_pred"),
          DTOutput("single_proba")
        )
      )
    ),
    
    # TAB 2: Batch CSV Prediction
    tabPanel(
      "Batch Prediction (CSV)",
      fileInput("csv_file", "Upload CSV tanpa kolom 'diabetes'"),
      DTOutput("batch_out"),
      downloadButton("download_preds", "Download hasil prediksi")
    )
  )
)


# SERVER
server <- function(input, output, session){
  
  # --------------- SINGLE INPUT ----------------
  observeEvent(input$predict_one, {
    
   newdata <- as_tibble(setNames(
  lapply(num_cols, function(col) input[[col]]),
  num_cols
))

    
    cls <- predict(rf_wf, new_data = newdata, type = "class")
    prob <- predict(rf_wf, new_data = newdata, type = "prob")
    
    output$single_pred <- renderText({
      glue("Prediksi: {cls$.pred_class}")
    })
    
    output$single_proba <- renderDT({
      datatable(prob, rownames = FALSE)
    })
  })
  
  # ---------------- CSV INPUT -------------------
  batch_data <- reactive({
    req(input$csv_file)
    read.csv(input$csv_file$datapath)
  })
  
  batch_pred <- reactive({
    df_new <- batch_data()
    cls <- predict(rf_wf, new_data = df_new, type = "class")
    prob <- predict(rf_wf, new_data = df_new, type = "prob")
    bind_cols(df_new, tibble(pred_diabetes = cls$.pred_class), prob)
  })
  
  output$batch_out <- renderDT({
    req(batch_pred())
    datatable(batch_pred(), options = list(pageLength = 10))
  })
  
  output$download_preds <- downloadHandler(
    filename = function() "prediksi_diabetes.csv",
    content = function(file){
      write.csv(batch_pred(), file, row.names = FALSE)
    }
  )
}

shinyApp(ui, server)
Shiny applications not supported in static R Markdown documents