ch0nny_log

[빅데이터분석] R _ 54. 나이브 베이즈 확율 본문

빅데이터 분석(with 아이티윌)/R

[빅데이터분석] R _ 54. 나이브 베이즈 확율

chonny 2024. 7. 11. 17:04
※ 머신러닝 종류 3가지
1. 지도학습 정답이 있는 데이터로 기계가 학습
예)
 입력:  프랑스의 수도 ?
 정답:  파리
2. 비지도 학습 정답 없이 데이터의 패턴과 구조를 학습하는 학습방
예)
입력 : the quick brown fox  jumps  over  the 
모델이 예측 :  lazy dog 가능성이 높다.
3. 강화 학습 주어진 환경을 기계가 스스로 이해하면서 데이터를 만들어가며 학습하는 것

naivebaise 알고리즘_v7.pdf
0.39MB

 

 

■ 나이브 베이즈 알고리즘이 사용되는 분야?

1. 스팸 이메일 필터링과 같은 텍스트 분류

2. 컴퓨터 네트워크에 침입한 비 정상적인 행위 탐지

3. 일련의 관찰된 증상에 따른 의학적 질병 진단

 

현업 실제 사례:  
컴퓨터에 여러 워드,엑셀등의 문서들이 있는데 이중에 랜썸웨어같은 악성 코드가 있는 문서가 1개가 있다고 하면 여러개의 문서들을 모델에 넣어서 악성코드가 있는 문서를 찾아내는 코드를 개발
실습1.1. 비아그라가 포함되어져 있는 메일이 스팸메일일 확률을 구하시오 !

설명: 확율이 0.8 이므로 비아그라가 포함되어있으면 스팸메일로 분류해야함


실습1.2. 비아그라 뿐만 아니라 다른 단어들도 여러개 있는 경우의 스팸일 확률?  

비아그라 단어 하나만 가지고 스팸 메일인지를 분류하려면 정확하게 분류가 안될 수  있으니 다른 단어들도 같이 포함시켜야 합니다.

비아그라와 구독취소는 포함되어져있는데 돈과 식료품은 포함되지 않은 메일이 스팸일 확률 ?

 왜 분모를 무시하는지?
-> 나이브 베이즈정리에서 우리가 구하고자 하는 것은 주어진 조건하에 사건 A가 발생할 확률임(우리가 예측을 비교할 때 관심이 있는 것은 상대적인 확률 값이기 때문. 즉, 스팸일 확률을 구하면 되고 햄일 확률을 구하면 됨)


비아그라
빈도 아니오 총계 우도 아니오 총계
스팸 4 16 20 스팸 4/20 16/20 20
1 79 80 1/80 79/80 80
총계 5 95 100 총계 5/100 95/100 100

  비아그라(W1) 돈(W2) 식료품(W3) 구독취소(W4)  
빈도 아니오 아니오 아니오 아니오 총계
스팸 4/20 16/20 10/20 10/20 0/20 20/20 12/20 8/20 20
1/80 79/80 14/80 66/80 8/80 71/80 23/80 57/80 80
총계 5/100 95/100 24/100 79/100 8/100 91/100 35/100 65/100 100

이 메세지에 있는 단어 패턴에 대해  85.7% 의 확률로 메세지가 스팸이고 14.3% 의 확률로 햄이라고 예상을 합니다. 

실습2. 나이브 베이즈 확률 실습 
#1. 데이터를 불러옵니다.

movie <- read.csv("c:\\data\\movie2.csv", stringsAsFactors=TRUE)
View(movie)
dim(movie)  #  39  6

#2. 결측치를 확인합니다. 
colSums( is.na(movie)) 

#3. 데이터를 살펴봅니다. 
str(movie)

#4. 훈련 데이터와 테스트 데이터로 분리합니다. 
library(caret)
set.seed(1)

k  <-  createDataPartition( movie$장르, p=0.8, list=F )

train_data <- movie[  k ,     ]
test_data <-  movie[  -k,    ]
nrow(train_data)
nrow(test_data)

#5. 나이브 베이즈 모델을 생성합니다. 
library(e1071)

# naiveBayes( 정답컬럼 ~ . , data=정답을 포함한 훈련 데이터 ) 

model <-  naiveBayes( 장르 ~ . ,  data=train_data)
model

1. 각 영화 장르의 사전확률을 나타냅니다. 각 장르가 얼마나 자주 등장하는지

SF   공포 로맨틱   무협 스릴러   액션 코미디 
0.125  0.125  0.250  0.125  0.125  0.125  0.125

2. 조건부 확률 

나이에 대한 영화장르별 조건부 확률 

Conditional probabilities:
  나이
Y        10대 20대 30대 40대
SF     0.00 0.00 1.00 0.00
공포   0.00 0.00 0.00 1.00
로맨틱 0.50 0.50 0.00 0.00
무협   0.25 0.25 0.25 0.25
스릴러 0.00 0.00 1.00 0.00
액션   1.00 0.00 0.00 0.00
코미디 0.00 0.50 0.25 0.25

정리하면 2가지 ?
  
  1. 사전확률 :  각 장르가 데이터셋에 나타나는 비율
2. 조건부 확률 : 각 입력변수(나이,성별,직업, 결혼여부, 이성친구여부) 에 따라 각 장르가
나타날 확률 

#6. 훈련한 모델로 테스트 데이터를 예측합니다. 

result  <-  predict( model,  test_data[  , -6] )   # 6번째 장르 컬럼 정답을 빼고 예측
result


#7. 모델의 성능을 평가합니다. 

sum( result == test_data[  , 6 ] )  / length( test_data[  , 6] ) * 100

#8. 이원 교차표를 그려서 어떻게 맞췄는지 확인합니다.

library(gmodels)
a <-  CrossTable( test_data[  , 6 ],  result )

a$t​

정리하면 2가지 ?
1. 사전확률 : 각 장르가 데이터셋에 나타나는 비율
2. 조건부 확률 : 각 입력변수(나이,성별,직업, 결혼여부, 이성친구여부) 에 따라 각 장르가 나타날 확률
문제1. 나이가 40대이고 성별이 남자이며 직업이 언론이고 결혼을 했으며 이성친구가 없는 남자가 공포영화를 좋아할 확률을 출력하시오 !
library(naivebayes)

test_data3 <- data.frame(나이='40대', 성별='남', 직업='언론', 결혼여부='YES', 이성친구='NO')

result3 <-  predict( new_model, test_data3, type='prob')
result3​
0.004% 의 확률로 공포 영화를 좋아합니다.
문제2. 나이가 20대 성별이 여자 결혼여부 no, 이성친구 yes, 직업이 학생인 사람이 좋아하는 영화 장르를 예측하시오. 
library(naivebayes)

test_data4 <- data.frame(나이='20대', 성별='여', 직업='학생', 결혼여부='NO', 이성친구='YES')

result4 <-  predict( new_model, test_data4, type='prob')
result4​

로맨틱 영화를 가장좋아함 
문제 3. 위의 코드를 활용한 R shinny 코드를 수행하시오. (영화 장르 예측 나이브 베이즈 Rshiny 전체 코드)

1) UI 정의: Shiny 애플리케이션의 사용자 인터페이스를 정의합니다.
-  titlePanel: 애플리케이션의 제목을 정의합니다.
-  sidebarLayout: 사이드바와 메인 패널로 구성된 레이아웃을 정의합니다.
-  sidebarPanel: 사용자가 입력할 수 있는 선택 입력 필드와 예측 버튼을 포함합니다.
-  selectInput: 사용자가 나이, 성별, 직업, 결혼 여부, 이성 친구 여부를 선택할 수 있는 드롭다운 메뉴를 생성합니다.
-  actionButton: 예측을 수행하는 버튼을 생성합니다.
-  mainPanel: 예측 결과를 출력할 영역을 정의합니다.
-  verbatimTextOutput: 예측 결과를 텍스트 형식으로 출력합니다.
 
2) 서버 로직 정의: 서버 측 로직을 정의합니다.
observeEvent: 사용자가 예측 버튼을 클릭할 때 실행됩니다.
-  입력된 값을 기반으로 테스트 데이터를 생성합니다.
-  predict: 생성된 모델을 사용하여 입력된 값을 기반으로 예측을 수행합니다.
-  output$prediction: 예측 결과를 출력합니다.

if (!require("shiny")) install.packages("shiny")
if (!require("naivebayes")) install.packages("naivebayes")
if (!require("e1071")) install.packages("e1071")
if (!require("caret")) install.packages("caret")

library(shiny)
library(naivebayes)
library(e1071)
library(caret)

# 데이터 불러오기
movie <- read.csv("c:\\data\\movie2.csv", stringsAsFactors=TRUE, fileEncoding = "euc-kr")

# 결측치 확인
colSums(is.na(movie))

# 훈련 데이터와 테스트 데이터로 분리
set.seed(1)
k <- createDataPartition(movie$장르, p=0.8, list=F)
train_data <- movie[k, ]
test_data <- movie[-k, ]

# 나이브 베이즈 모델 생성
new_model <- naive_bayes(장르 ~ ., data=train_data)

# UI 정의
ui <- fluidPage(
  titlePanel("영화 장르 예측기"),
  sidebarLayout(
    sidebarPanel(
      selectInput("age", "나이", choices = unique(movie$나이)),
      selectInput("gender", "성별", choices = unique(movie$성별)),
      selectInput("job", "직업", choices = unique(movie$직업)),
      selectInput("married", "결혼여부", choices = unique(movie$결혼여부)),
      selectInput("relationship", "이성친구 여부", choices = unique(movie$이성친구)),
      actionButton("predict", "예측하기")
    ),
    mainPanel(
      verbatimTextOutput("prediction")
    )
  )
)

# 서버 로직 정의
server <- function(input, output) {
  
  observeEvent(input$predict, {
    test_data <- data.frame(
      나이 = input$age,
      성별 = input$gender,
      직업 = input$job,
      결혼여부 = input$married,
      이성친구 = input$relationship
    )
    
    result <- predict(new_model, test_data, type = "prob")
    
    output$prediction <- renderPrint({
      result
    })
  })
  
}

# Shiny 앱 실행
shinyApp(ui = ui, server = server)​


 

★ 오늘의 마지막 문제. 지금 만든 나이브 베이즈 알 샤이니 화면을 쳇GPT 에게 요청해서 화면을 여러분들이 원하는 스타일로 변경하시오. 색깔, 버튼의 위치, 글씨크기등......
if (!require("shiny")) install.packages("shiny")
if (!require("naivebayes")) install.packages("naivebayes")
if (!require("e1071")) install.packages("e1071")
if (!require("caret")) install.packages("caret")
if (!require("ggplot2")) install.packages("ggplot2")

library(shiny)
library(naivebayes)
library(e1071)
library(caret)
library(ggplot2)

# 데이터 불러오기
movie <- read.csv("c:\\data\\movie2.csv", stringsAsFactors=TRUE, fileEncoding = "euc-kr")

# 결측치 확인
colSums(is.na(movie))

# 훈련 데이터와 테스트 데이터로 분리
set.seed(1)
k <- createDataPartition(movie$장르, p=0.8, list=F)
train_data <- movie[k, ]
test_data <- movie[-k, ]

# 나이브 베이즈 모델 생성
new_model <- naive_bayes(장르 ~ ., data=train_data)

# UI 정의
ui <- fluidPage(
  tags$head(
    tags$style(HTML("
      body {
        background-color: #F0F8FF; /* 완전 연한 하늘색 배경색 */
      }
      .btn-predict {
        background-color: #87CEEB; /* 하늘색 배경색 */
        border-color: #87CEEB; /* 하늘색 테두리 색 */
        color: white; /* 글자 색상 */
      }
      .title {
        font-size: 24px; /* 제목 글씨 크기 조정 */
        color: #0072B2; /* 남색 글자 색상 */
      }
    "))
  ),
  div(class = "title", "영화 장르 예측기"),  # 직접 HTML 태그를 사용하여 제목 정의
  sidebarLayout(
    sidebarPanel(
      radioButtons("age", "연령대", choices = unique(movie$나이), selected = NULL),
      radioButtons("gender", "성별", choices = unique(movie$성별), selected = NULL),
      radioButtons("job", "직업", choices = unique(movie$직업), selected = NULL),
      radioButtons("married", "결혼여부", choices = unique(movie$결혼여부), selected = NULL),
      radioButtons("relationship", "이성친구 여부", choices = unique(movie$이성친구), selected = NULL),
      actionButton("predict", "예측하기", class = "btn-predict")
    ),
    mainPanel(
      plotOutput("predictionPlot"),
      textOutput("predictionText")
    )
  )
)

# 서버 로직 정의
server <- function(input, output) {
  values <- reactiveValues(result_df = NULL)
  
  observeEvent(input$predict, {
    test_data <- data.frame(
      나이 = input$age,
      성별 = input$gender,
      직업 = input$job,
      결혼여부 = input$married,
      이성친구 = input$relationship
    )
    
    result <- predict(new_model, test_data, type = "prob")
    
    values$result_df <- as.data.frame(t(result))
    values$result_df$장르 <- rownames(values$result_df)
    colnames(values$result_df) <- c("확률", "장르")
  })
  
  output$predictionPlot <- renderPlot({
    req(values$result_df)
    ggplot(values$result_df, aes(x = 장르, y = 확률)) +
      geom_bar(stat = "identity", fill = "skyblue") +
      theme_minimal() +
      labs(title = "예측된 영화 장르 확률", x = "장르", y = "확률") +
      ylim(0, 1)
  })
  
  output$predictionText <- renderText({
    req(values$result_df)
    max_genre <- values$result_df$장르[which.max(values$result_df$확률)]
    paste("예측된 영화 장르 확률은", max_genre, "입니다.")
  })
}

# Shiny 앱 실행
shinyApp(ui = ui, server = server)