이번에는 로지스틱 회귀분석을 해보려 한다. 간단히 말하자면 데이터를 분류할 때 선형분류기를 사용하여 이진분류를 하는 것이 로지스틱 분석의 핵심이다.
선형분류기란 로지스틱 함수 즉, odds 함수를 사용하여 분류를 하는 것이다. 이는 후에 신경망 이론에도 매우 중요한 근간을 이루기 때문에 로지스틱 함수에 대한 자세한 이야기는 나중에 다루기로 하겠다.
자 이제 iris 데이터로 로지스틱 회기를 통한 이진분류를 해보자.
# 필요한 패키지
library(tidyverse)
df <- iris
# 데이터 설정
df <- df %>%
filter(Species != "versicolor") %>%
as.data.frame()
unique(df$Species)
## [1] setosa virginica
## Levels: setosa versicolor virginica
df$Species <- factor(df$Species)
이번에는 데이터를 파악해보자 각각 데이터의 자료형이 어떤지, 어떻게 분포되어 있는지 등을 볼 것이다.
str(df)
## 'data.frame': 100 obs. of 5 variables:
## $ Sepal.Length: num 5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ...
## $ Sepal.Width : num 3.5 3 3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1 ...
## $ Petal.Length: num 1.4 1.4 1.3 1.5 1.4 1.7 1.4 1.5 1.4 1.5 ...
## $ Petal.Width : num 0.2 0.2 0.2 0.2 0.2 0.4 0.3 0.2 0.2 0.1 ...
## $ Species : Factor w/ 2 levels "setosa","virginica": 1 1 1 1 1 1 1 1 1 1 ...
summary(df)
## Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## Min. :4.300 Min. :2.200 Min. :1.000 Min. :0.100 setosa :50
## 1st Qu.:5.000 1st Qu.:3.000 1st Qu.:1.500 1st Qu.:0.200 virginica:50
## Median :5.700 Median :3.200 Median :3.200 Median :1.000
## Mean :5.797 Mean :3.201 Mean :3.507 Mean :1.136
## 3rd Qu.:6.500 3rd Qu.:3.425 3rd Qu.:5.525 3rd Qu.:2.000
## Max. :7.900 Max. :4.400 Max. :6.900 Max. :2.500
sum(is.na(df))
## [1] 0
plot(df)
간단히 자료의 데이터형과 통계수치, 결측치가 없는 것을 확인했고,그래프로 데이터를 파악해본 결과, Species를 분류하는데 있어서 유효한 데이터는 Peltal.Width, Petal.Length, Sepal.Width 로 확인 되었다.
자 이제 versicolor 를 제외한 iris 데이터를 트레이닝 테스트 셋으로 나누자. 이 때 70:30으로 나눌 것이다.
# test set
# 모델을 평가 하는데 필요
# train/test sampling
training_sampling <- sort(sample(1:nrow(df),nrow(df)*0.7))
test_sampling <- setdiff(1:nrow(df), training_sampling)
# nrow, ncol
# nrow = number of row
# ncol = number of column
## traing_set, test_set
training_set <- df[training_sampling,]
test_set <- df[test_sampling,]
이제 로지스틱 회귀를 하여 이진분류를 해보도록 하겠다. 로지스틱의 기본 함수는 glm()이고 기본 형식은 다음과 같다.
glm(종속변수 ~ 독립변수, data = df, family = “binomial”)
# 모델생성
logit_m <- glm(Species ~ Petal.Length + Petal.Width + Sepal.Width, data = training_set, family = "binomial")
## Warning: glm.fit: algorithm did not converge
## Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred
# 모델확인
logit_f <- fitted(logit_m)
logit_f < 0.5
## 1 2 4 5 6 7 8 9 10 11 12 13 14
## TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
## 15 16 17 18 19 22 23 24 25 26 27 33 34
## TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
## 35 36 37 41 42 44 45 46 49 52 53 55 57
## TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE FALSE FALSE FALSE FALSE
## 58 59 60 62 64 66 67 68 69 70 71 72 73
## FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
## 75 77 78 79 81 83 84 85 86 88 89 90 91
## FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
## 93 94 96 97 100
## FALSE FALSE FALSE FALSE FALSE
df$Species %>% as.numeric()
## [1] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
## [38] 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
## [75] 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
ifelse(logit_f < 0.5, 1, 2)
## 1 2 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 22 23
## 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
## 24 25 26 27 33 34 35 36 37 41 42 44 45 46 49 52 53 55 57 58
## 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2
## 59 60 62 64 66 67 68 69 70 71 72 73 75 77 78 79 81 83 84 85
## 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
## 86 88 89 90 91 93 94 96 97 100
## 2 2 2 2 2 2 2 2 2 2
# 정확도를 위한 데이터 생성
is_correct <- training_set$Species %>% as.numeric() == ifelse(logit_f < 0.5, 1, 2)
# 정확도
sum(is_correct) / length(is_correct)
## [1] 1
정확도가 1이 나왔다. 이는 100% 잘 분류되었음을 나타낸다. 이제는 test set 에다가 모델을 적용시켜보자. predict() 함수를 쓰고 기본형은 다음과 같다.
predict(model, newdata, type=“response”)
## test set의 모델적용
logit_p <- predict(logit_m, test_set, type = "response")
is_correct_p <- test_set$Species %>% as.numeric() == ifelse(logit_p < 0.5, 1, 2)
sum(is_correct_p) / length(is_correct_p)
## [1] 1
그러나 iris 데이터 자체가 매우 교과서적으로 나와있어서 역시 차후에 복잡한 데이터를 통해 다시 한 번 적용해볼 예정이다.