<Rshiny 이용해보기>
*데이터들의 소수점 자릿수가 많아서 슬라이더가 적합한 것 같지 않지만 일단 만들어 봤습니다.
library(shiny)
library(caret)
library(class)
library(ggplot2)
library(plotly)
# 1단계: 데이터 수집 및 전처리
data(Glass)
Glass2 <- Glass[, -10] # 정답(Type)을 제외
# 정규화 함수 수정
normalize <- function(x, min_val, max_val) { return((x - min_val) / (max_val - min_val)) }
Glass_n <- as.data.frame(lapply(Glass2, function(col) normalize(col, min(col), max(col))))
# 훈련 데이터와 테스트 데이터 분리
set.seed(1)
trainIndex <- createDataPartition(Glass$Type, p = 0.9, list = FALSE)
Glass_train <- Glass_n[trainIndex, ]
Glass_test <- Glass_n[-trainIndex, ]
Glass_train_label <- Glass$Type[trainIndex]
Glass_test_label <- Glass$Type[-trainIndex]
# KNN 모델 훈련 함수
knn_model <- function(new_data, k) {
knn(train = Glass_train, test = new_data, cl = Glass_train_label, k = k)
}
# Shiny UI 정의
ui <- fluidPage(
titlePanel("Glass 데이터 분류 예측"),
sidebarLayout(
sidebarPanel(
sliderInput("RI", "굴절률 (Refractive Index):", min = min(Glass$RI), max = max(Glass$RI), value = mean(Glass$RI), step = 0.00001),
sliderInput("Na", "나트륨 함량 (Sodium):", min = min(Glass$Na), max = max(Glass$Na), value = mean(Glass$Na), step = 0.01),
sliderInput("Mg", "마그네슘 함량 (Magnesium):", min = min(Glass$Mg), max = max(Glass$Mg), value = mean(Glass$Mg), step = 0.01),
sliderInput("Al", "알루미늄 함량 (Aluminum):", min = min(Glass$Al), max = max(Glass$Al), value = mean(Glass$Al), step = 0.01),
sliderInput("Si", "실리콘 함량 (Silicon):", min = min(Glass$Si), max = max(Glass$Si), value = mean(Glass$Si), step = 0.01),
sliderInput("K", "칼륨 함량 (Potassium):", min = min(Glass$K), max = max(Glass$K), value = mean(Glass$K), step = 0.01),
sliderInput("Ca", "칼슘 함량 (Calcium):", min = min(Glass$Ca), max = max(Glass$Ca), value = mean(Glass$Ca), step = 0.01),
sliderInput("Ba", "바륨 함량 (Barium):", min = min(Glass$Ba), max = max(Glass$Ba), value = mean(Glass$Ba), step = 0.01),
sliderInput("Fe", "철 함량 (Iron):", min = min(Glass$Fe), max = max(Glass$Fe), value = mean(Glass$Fe), step = 0.01),
actionButton("predict", "Predict"),
actionButton("reset", "Reset"),
br(), br(),
textOutput("result")
),
mainPanel(
plotOutput("plot1"),
plotOutput("plot2")
)
)
)
# Shiny Server 정의
server <- function(input, output, session) {
observeEvent(input$predict, {
new_data <- data.frame(
RI = normalize(input$RI, min(Glass$RI), max(Glass$RI)),
Na = normalize(input$Na, min(Glass$Na), max(Glass$Na)),
Mg = normalize(input$Mg, min(Glass$Mg), max(Glass$Mg)),
Al = normalize(input$Al, min(Glass$Al), max(Glass$Al)),
Si = normalize(input$Si, min(Glass$Si), max(Glass$Si)),
K = normalize(input$K, min(Glass$K), max(Glass$K)),
Ca = normalize(input$Ca, min(Glass$Ca), max(Glass$Ca)),
Ba = normalize(input$Ba, min(Glass$Ba), max(Glass$Ba)),
Fe = normalize(input$Fe, min(Glass$Fe), max(Glass$Fe))
)
prediction <- knn_model(new_data, k = 1)
output$result <- renderText({
paste("예측 결과: Glass의 종류는", as.character(prediction), "입니다(정확도는 약 83.33%입니다).")
})
# 2차원 시각화
Glass_pca <- prcomp(Glass_n, center = TRUE, scale. = TRUE)
Glass_pca_df <- as.data.frame(Glass_pca$x)
Glass_pca_df$Type <- Glass$Type
test_pca <- predict(Glass_pca, newdata = new_data)
test_pca_df <- data.frame(PC1 = test_pca[1], PC2 = test_pca[2], Predicted = prediction)
# 2차원 시각화 (실제 라벨)
output$plot1 <- renderPlot({
ggplot(Glass_pca_df, aes(x = PC1, y = PC2, color = Type)) +
geom_point(size = 3) +
ggtitle("Glass 데이터의 실제 라벨")
})
# 2차원 시각화 (예측된 라벨)
output$plot2 <- renderPlot({
ggplot() +
geom_point(data = Glass_pca_df, aes(x = PC1, y = PC2, color = Type), size = 3, alpha = 0.2) +
geom_point(data = test_pca_df, aes(x = PC1, y = PC2, color = Predicted), size = 6) +
ggtitle("Glass 데이터의 예측된 라벨")
})
})
observeEvent(input$reset, {
updateSliderInput(session, "RI", value = mean(Glass$RI))
updateSliderInput(session, "Na", value = mean(Glass$Na))
updateSliderInput(session, "Mg", value = mean(Glass$Mg))
updateSliderInput(session, "Al", value = mean(Glass$Al))
updateSliderInput(session, "Si", value = mean(Glass$Si))
updateSliderInput(session, "K", value = mean(Glass$K))
updateSliderInput(session, "Ca", value = mean(Glass$Ca))
updateSliderInput(session, "Ba", value = mean(Glass$Ba))
updateSliderInput(session, "Fe", value = mean(Glass$Fe))
output$result <- renderText({ "" })
})
}
# Shiny 앱 실행
shinyApp(ui = ui, server = server)