File size: 2,869 Bytes
021a69e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
library(shiny)
library(bslib)
library(tidymodels)
library(tidyverse)
library(ranger)
library(xgboost)

# Load Model (Single Best Model)
# Ensure 'model.rds' exists in the same directory (src/)
model <- readRDS("model.rds")

# UI Definition
ui <- page_sidebar(
  theme = bs_theme(bootswatch = "flatly"),
  title = "Bank Marketing AI (Interactive)",
  sidebar = sidebar(
    title = "Client Profile",
    numericInput("age", "Age", 35, 18, 100),
    selectInput("job", "Job", choices = c("admin.", "blue-collar", "technician", "services", "management", "retired", "entrepreneur", "self-employed", "housemaid", "unemployed", "student", "unknown")),
    selectInput("marital", "Marital Status", choices = c("married", "single", "divorced", "unknown")),
    selectInput("education", "Education", choices = c("university.degree", "high.school", "basic.9y", "professional.course", "basic.4y", "basic.6y", "unknown", "illiterate")),
    selectInput("default", "Has Credit in Default?", choices = c("no", "yes", "unknown")),
    selectInput("housing", "Has Housing Loan?", choices = c("no", "yes", "unknown")),
    selectInput("loan", "Has Personal Loan?", choices = c("no", "yes", "unknown")),
    hr(),
    actionButton("predict_btn", "Run Prediction", class = "btn-success w-100")
  ),
  
  layout_columns(
    col_widths = c(12),
    card(
      card_header("Prediction Output"),
      tableOutput("pred_results")
    )
  )
)

# Server Logic
server <- function(input, output) {
  
  predictions <- eventReactive(input$predict_btn, {
    
    # Construct Input DataFrame
    # Note: 'duration' is deliberately excluded as per model inference hygiene
    input_df <- data.frame(
      age = input$age,
      job = input$job,
      marital = input$marital,
      education = input$education,
      default = input$default,
      housing = input$housing,
      loan = input$loan,
      # Default mock values for other features to allow prediction
      contact = "cellular", 
      month = "may", 
      day_of_week = "mon",
      campaign = 1, 
      pdays = 999, 
      previous = 0, 
      poutcome = "nonexistent",
      emp.var.rate = -1.8, 
      cons.price.idx = 92.8, 
      cons.conf.idx = -46.2, 
      euribor3m = 1.2, 
      nr.employed = 5099
    )
    
    # Predict Class
    pred_class <- tryCatch({
       predict(model, input_df) %>% pull(.pred_class)
    }, error = function(e) "Error")
    
    # Predict Probability
    pred_prob <- tryCatch({
       predict(model, input_df, type = "prob") %>% pull(.pred_Yes)
    }, error = function(e) 0)
    
    data.frame(
      Result = c("Predicted Class", "Probability (Subscribes)"),
      Value = c(as.character(pred_class), paste0(round(pred_prob * 100, 2), "%"))
    )
  })
  
  output$pred_results <- renderTable({
    predictions()
  }, striped = TRUE, hover = TRUE, colnames = FALSE)
}

shinyApp(ui, server)