본문 바로가기
1-1. 지도학습 (이산자료)/4) 로지스틱 회귀

R 로지스틱 회귀분석 예시 (대장암 예시)

by makhimh 2022. 11. 23.

먼저 아래 패키지를 설치합시다. 

install.packages("survival")


survival 패키지에는 대장암 데이터인 colon 데이터가 들어 있습니다. 

패키지를 불러옵니다. 

library(survival)


데이터를 변수에 저장해줍니다. 

data=colon


이후 과정은 번호를 붙여 진행하겠습니다. 

 

1. 데이터 살펴보기

str함수를 이용하여 변수들을 살펴봅시다. 

 

> str(colon)
'data.frame':	1858 obs. of  16 variables:
 $ id      : num  1 1 2 2 3 3 4 4 5 5 ...
 $ study   : num  1 1 1 1 1 1 1 1 1 1 ...
 $ rx      : Factor w/ 3 levels "Obs","Lev","Lev+5FU": 3 3 3 3 1 1 3 3 1 1 ...
 $ sex     : num  1 1 1 1 0 0 0 0 1 1 ...
 $ age     : num  43 43 63 63 71 71 66 66 69 69 ...
 $ obstruct: num  0 0 0 0 0 0 1 1 0 0 ...
 $ perfor  : num  0 0 0 0 0 0 0 0 0 0 ...
 $ adhere  : num  0 0 0 0 1 1 0 0 0 0 ...
 $ nodes   : num  5 5 1 1 7 7 6 6 22 22 ...
 $ status  : num  1 1 0 0 1 1 1 1 1 1 ...
 $ differ  : num  2 2 2 2 2 2 2 2 2 2 ...
 $ extent  : num  3 3 3 3 2 2 3 3 3 3 ...
 $ surg    : num  0 0 0 0 0 0 1 1 1 1 ...
 $ node4   : num  1 1 0 0 1 1 1 1 1 1 ...
 $ time    : num  1521 968 3087 3087 963 ...
 $ etype   : num  2 1 2 1 2 1 2 1 2 1 ...

 

종속변수는 status 입니다. 1이면 대장암 재발 또는 사망입니다. 독리변수는 rx, sex, age, obstruct, perfor, adhere, nodes, differ, extent, surg 로 놓겠습니다. 대장암 여부를 예측하는 모델을 만드는 것이 목적입니다. 

 

2. 결측치 확인 및 제거

결측치를 확인하고 제거해줍니다 .

 

#결측치 위치 확인 함수
where.na.df=function(df){ 
  
  res=data.frame(row=NA,col=NA)
  
  
  for (i in 1:dim(df)[1]){
    for (j in 1:dim(df)[2]){
      
      if (is.na(df[i,j])){
        res=rbind(res,c(i,j))
      }
      
    }
  }
  
  res=res[-1,]
  rownames(res)=NULL
  
  return(res)
  
}

where.na.df(data) #결측치 위치확인
data = na.omit(data) #결측치 제거

 

인스턴스의 개수가 1858에서 1776으로 줄었습니다. 

 

> dim(data)
[1] 1776   16

 

3. 훈련데이터셋, 테스트데이터셋 나누기

데이터를 훈련데이터셋과 테스트데이터셋으로 나누겠습니다. 전체의 25%를 테스트 데이터셋으로 만들겠습니다. 코드는 아래와 같습니다. 

set.seed(999)
id_test=sample(1:nrow(data),nrow(data)*0.25)

data_test=data[id_test,]
data_train=data[setdiff(1:nrow(data),y=id_test),]

 

4. 모델 만들기

대장암을 예측하는 모델을 만들 것입니다. 로지스틱회귀 알고리즘을 사용합니다. glm 함수를 이용하고, family 를 binomial 로 설정합니다. 아래와 같이 입력합니다. 

model=glm(status ~ rx+sex+age+obstruct+perfor+adhere+nodes+differ+extent+surg, family=binomial, data=data_train)


모델 생성 결과는 아래와 같습니다. 

> model

Call:  glm(formula = status ~ rx + sex + age + obstruct + perfor + adhere + 
    nodes + differ + extent + surg, family = binomial, data = data_train)

Coefficients:
(Intercept)        rxLev    rxLev+5FU          sex          age     obstruct       perfor       adhere        nodes       differ       extent         surg  
  -2.430926    -0.069553    -0.585606    -0.086161     0.001896     0.219995     0.085831     0.373527     0.185245     0.031839     0.563617     0.388068  

Degrees of Freedom: 1775 Total (i.e. Null);  1764 Residual
Null Deviance:	    2462 
Residual Deviance: 2240 	AIC: 2264

 

 

5. 중요도 출력

독립변수의 중요도를 출력할 때는 varImp 함수를 사용합니다. 패키지는 caret입니다. 

library(caret)
varImp(model, scale = FALSE)

> varImp(model, scale = FALSE)
            Overall
rxLev     0.5678213
rxLev+5FU 4.7006774
sex       0.8479236
age       0.4386259
obstruct  1.7155740
perfor    0.2876978
adhere    2.5381611
nodes     9.8151412
differ    0.3159995
extent    4.8239592
surg      3.4089047

 

6. 모델 평가

predict 함수를 이용하여 테스트셋의 결과변수를 구해줍니다. type 을 response 로 설정하면 확률이 반환됩니다. 해당 확률이 0.5보다 높은 경우를 1로, 낮은 경우를 0으로 반환한 뒤, test 데이터의 status 와 비교합니다. 이때 TRUE 의 비율이 정확도입니다. mean 으로 구한 평균이 TRUE 비율입니다. 잘 생각해보시면 이해가 되실겁니다. 

 

pred=predict(model, data_test,type='response')
mean(ifelse(pred>0.5,1,0)==data_test$status)

 

정확도는 64.8% 입니다. 

 

test 데이터에 대해 ROC 곡선도 그려봅시다. 

 

library(Epi)
ROC(test=pred,stat=data_test$status,plot="ROC")

 

 

코드 모아보기

library(survival)


#1.데이터
data = colon

#2.결측치확인 및 제거

#결측치 위치 확인 함수
where.na.df = function(df) {
  res = data.frame(row = NA, col = NA)
  
  
  for (i in 1:dim(df)[1]) {
    for (j in 1:dim(df)[2]) {
      if (is.na(df[i, j])) {
        res = rbind(res, c(i, j))
      }
    }
  }
  res = res[-1, ]
  rownames(res) = NULL
  
  return(res)
}

where.na.df(data) #결측치 위치확인
data = na.omit(data) #결측치 제거



#2.훈련데이터셋, 테스트데이터셋 나누기
set.seed(999)
id_test = sample(1:nrow(data), nrow(data) * 0.25)

data_test = data[id_test, ]
data_train = data[setdiff(1:nrow(data), y = id_test), ]

#3.모델 만들기
model = glm(
  status ~ rx + sex + age + obstruct + perfor + adhere + nodes + differ + extent + surg,
  family = binomial,
  data = data_train
)


#4.중요도 출력
library(caret)
varImp(model, scale = FALSE)

#6.모델 평가하기
pred = predict(model, data_test, type = 'response')
mean(ifelse(pred > 0.5, 1, 0) == data_test$status)

#roc curve
library(Epi)
ROC(test = pred,
    stat = data_test$status,
    plot = "ROC")

댓글