저자 책 웹페이지: https://dataninja.me/ipds-kr/

R 환경 준비

일단은 필수패키지인 tidyverse, 그리고 머신러닝을 위한 몇가지 패키지를 로드하자. (로딩 메시지를 감추기 위해 suppressMessages() 명령을 사용.)

# install.packages("tidyverse")
suppressMessages(library(tidyverse))

# install.packages(c("ROCR", "MASS", "glmnet", "randomForest", "gbm", "rpart", "boot"))
suppressMessages(library(gridExtra))
suppressMessages(library(ROCR))
suppressMessages(library(MASS))
suppressMessages(library(glmnet))
## Warning: package 'glmnet' was built under R version 3.4.2
suppressMessages(library(randomForest))
suppressMessages(library(gbm))
suppressMessages(library(rpart))
suppressMessages(library(boot))

책에서 기술한대로 이항 오차 함수, 그리고 panel.cor 함수를 정의하자:

binomial_deviance <- function(y_obs, yhat){
  epsilon = 0.0001
  yhat = ifelse(yhat < epsilon, epsilon, yhat)
  yhat = ifelse(yhat > 1-epsilon, 1-epsilon, yhat)
  a = ifelse(y_obs==0, 0, y_obs * log(y_obs/yhat))
  b = ifelse(y_obs==1, 0, (1-y_obs) * log((1-y_obs)/(1-yhat)))
  return(2*sum(a + b))
}

# exmaple(pairs) 에서 따옴
panel.cor <- function(x, y, digits = 2, prefix = "", cex.cor, ...){
  usr <- par("usr"); on.exit(par(usr))
  par(usr = c(0, 1, 0, 1))
  r <- abs(cor(x, y))
  txt <- format(c(r, 0.123456789), digits = digits)[1]
  txt <- paste0(prefix, txt)
  if(missing(cex.cor)) cex.cor <- 0.8/strwidth(txt)
  text(0.5, 0.5, txt, cex = cex.cor * r)
}

1. (위스콘신 유방암 데이터 II)

위스콘신 유방암 데이터 중 약간 다른 데이터인 https://goo.gl/gY8Iri 혹은 http://archive.ics.uci.edu/ml/machine-learning-databases/breast-cancer-wisconsin/breast-cancer-wisconsin.data 를 분석하라. 변수에 대한 설명은 https://goo.gl/CqLTuk 혹은 http://archive.ics.uci.edu/ml/machine-learning-databases/breast-cancer-wisconsin/breast-cancer-wisconsin.names 에서 볼 수 있다. 분석의 목적은 다른 10개의 변수를 사용하여 class = 2(양성; benign), 4(악성; malign) 값을 예측하는 것이다.

우선 다음 명령으로 자료를 다운받자:

wget http://archive.ics.uci.edu/ml/machine-learning-databases/breast-cancer-wisconsin/breast-cancer-wisconsin.data 
wget http://archive.ics.uci.edu/ml/machine-learning-databases/breast-cancer-wisconsin/breast-cancer-wisconsin.names 

R 로 자료를 읽어들인 후, 적절한 변수명을 부여하고, ID 변수 (“Sample code number”)를 제거하고, 반응변수인 class를 0(Benign, 원래값 = 2)과 1(Malignant, 원래값 = 4)로 변환하자. 원 데이터 파일에서, 결측치를 ?로 나타내고 있으므로 read_csv()문의 na= 옵션을 사용하여 결측치를 올바로 읽어들여야 한다.

df <- read_csv("breast-cancer-wisconsin.data", col_names = FALSE, na="?")
## Parsed with column specification:
## cols(
##   X1 = col_integer(),
##   X2 = col_integer(),
##   X3 = col_integer(),
##   X4 = col_integer(),
##   X5 = col_integer(),
##   X6 = col_integer(),
##   X7 = col_integer(),
##   X8 = col_integer(),
##   X9 = col_integer(),
##   X10 = col_integer(),
##   X11 = col_integer()
## )
names(df) <- tolower(gsub(" ", "_",
             c("Sample code number",
               "Clump Thickness", 
               "Uniformity of Cell Size", 
               "Uniformity of Cell Shape", 
               "Marginal Adhesion", 
               "Single Epithelial Cell Size", 
               "Bare Nuclei", 
               "Bland Chromatin", 
               "Normal Nucleoli", 
               "Mitoses", 
               "Class")))
df <- df %>%
  mutate(is_malig=ifelse(class==4, 1, 0)) %>%
  dplyr::select(-sample_code_number, -class)
glimpse(df)
## Observations: 699
## Variables: 10
## $ clump_thickness             <int> 5, 5, 3, 6, 4, 8, 1, 2, 2, 4, 1, 2...
## $ uniformity_of_cell_size     <int> 1, 4, 1, 8, 1, 10, 1, 1, 1, 2, 1, ...
## $ uniformity_of_cell_shape    <int> 1, 4, 1, 8, 1, 10, 1, 2, 1, 1, 1, ...
## $ marginal_adhesion           <int> 1, 5, 1, 1, 3, 8, 1, 1, 1, 1, 1, 1...
## $ single_epithelial_cell_size <int> 2, 7, 2, 3, 2, 7, 2, 2, 2, 2, 1, 2...
## $ bare_nuclei                 <int> 1, 10, 2, 4, 1, 10, 10, 1, 1, 1, 1...
## $ bland_chromatin             <int> 3, 3, 3, 3, 3, 9, 3, 3, 1, 2, 3, 2...
## $ normal_nucleoli             <int> 1, 2, 1, 7, 1, 7, 1, 1, 1, 1, 1, 1...
## $ mitoses                     <int> 1, 1, 1, 1, 1, 1, 1, 1, 5, 1, 1, 1...
## $ is_malig                    <dbl> 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0...

a. (결측치 처리)

설명변수중에결측치가있는가? 어느변수에몇개의결측치가있는가? 어떻게해결하는것이좋 을까? (관심 있는 독자는 Saar-Tsechansky & Provost (2007) 등을 참고하라.)

결측치를 찾아내는 간단한 방법은 summary() 함수를 사용하는 것이다:

summary(df)
##  clump_thickness  uniformity_of_cell_size uniformity_of_cell_shape
##  Min.   : 1.000   Min.   : 1.000          Min.   : 1.000          
##  1st Qu.: 2.000   1st Qu.: 1.000          1st Qu.: 1.000          
##  Median : 4.000   Median : 1.000          Median : 1.000          
##  Mean   : 4.418   Mean   : 3.134          Mean   : 3.207          
##  3rd Qu.: 6.000   3rd Qu.: 5.000          3rd Qu.: 5.000          
##  Max.   :10.000   Max.   :10.000          Max.   :10.000          
##                                                                   
##  marginal_adhesion single_epithelial_cell_size  bare_nuclei    
##  Min.   : 1.000    Min.   : 1.000              Min.   : 1.000  
##  1st Qu.: 1.000    1st Qu.: 2.000              1st Qu.: 1.000  
##  Median : 1.000    Median : 2.000              Median : 1.000  
##  Mean   : 2.807    Mean   : 3.216              Mean   : 3.545  
##  3rd Qu.: 4.000    3rd Qu.: 4.000              3rd Qu.: 6.000  
##  Max.   :10.000    Max.   :10.000              Max.   :10.000  
##                                                NA's   :16      
##  bland_chromatin  normal_nucleoli     mitoses          is_malig     
##  Min.   : 1.000   Min.   : 1.000   Min.   : 1.000   Min.   :0.0000  
##  1st Qu.: 2.000   1st Qu.: 1.000   1st Qu.: 1.000   1st Qu.:0.0000  
##  Median : 3.000   Median : 1.000   Median : 1.000   Median :0.0000  
##  Mean   : 3.438   Mean   : 2.867   Mean   : 1.589   Mean   :0.3448  
##  3rd Qu.: 5.000   3rd Qu.: 4.000   3rd Qu.: 1.000   3rd Qu.:1.0000  
##  Max.   :10.000   Max.   :10.000   Max.   :10.000   Max.   :1.0000  
## 

bare_nuclei 변수에 16개의 결측치가 있음을 알 수 있다.

결측치를 해결하는 다양한 방법이 있지만 여기서는 간단히 중앙값으로 대치하도록 하자.

df <- df %>%
  mutate(bare_nuclei=ifelse(is.na(bare_nuclei), 
                            median(df$bare_nuclei, na.rm=TRUE),
                            bare_nuclei))
summary(df)
##  clump_thickness  uniformity_of_cell_size uniformity_of_cell_shape
##  Min.   : 1.000   Min.   : 1.000          Min.   : 1.000          
##  1st Qu.: 2.000   1st Qu.: 1.000          1st Qu.: 1.000          
##  Median : 4.000   Median : 1.000          Median : 1.000          
##  Mean   : 4.418   Mean   : 3.134          Mean   : 3.207          
##  3rd Qu.: 6.000   3rd Qu.: 5.000          3rd Qu.: 5.000          
##  Max.   :10.000   Max.   :10.000          Max.   :10.000          
##  marginal_adhesion single_epithelial_cell_size  bare_nuclei    
##  Min.   : 1.000    Min.   : 1.000              Min.   : 1.000  
##  1st Qu.: 1.000    1st Qu.: 2.000              1st Qu.: 1.000  
##  Median : 1.000    Median : 2.000              Median : 1.000  
##  Mean   : 2.807    Mean   : 3.216              Mean   : 3.486  
##  3rd Qu.: 4.000    3rd Qu.: 4.000              3rd Qu.: 5.000  
##  Max.   :10.000    Max.   :10.000              Max.   :10.000  
##  bland_chromatin  normal_nucleoli     mitoses          is_malig     
##  Min.   : 1.000   Min.   : 1.000   Min.   : 1.000   Min.   :0.0000  
##  1st Qu.: 2.000   1st Qu.: 1.000   1st Qu.: 1.000   1st Qu.:0.0000  
##  Median : 3.000   Median : 1.000   Median : 1.000   Median :0.0000  
##  Mean   : 3.438   Mean   : 2.867   Mean   : 1.589   Mean   :0.3448  
##  3rd Qu.: 5.000   3rd Qu.: 4.000   3rd Qu.: 1.000   3rd Qu.:1.0000  
##  Max.   :10.000   Max.   :10.000   Max.   :10.000   Max.   :1.0000

b. (분류분석)

결측치를 표본의 중앙값으로 대치하고 분류 예측분석을 시행하라. 어떤 모형이 가장 성능이 좋은 가? 결과를 슬라이드 10여 장 내외로 요약하라.

수량형 변수들간의 관계는 산점도 행렬로 살펴볼 수 있다:

set.seed(2017)
df %>% 
  sample_n(500) %>% 
  pairs(lower.panel=function(x,y){ points(x,y); abline(0, 1, col='red')},
    upper.panel = panel.cor)