Sigmoid Function

Logistic Regression 분석은 (예측)결과가 Yes(1) 이냐 No(0)이냐를 예측하기 위한 방법이다.
다시 말하면 결과 y 가 1이 될 확율을 계산하는 것이라고 할 수 있다.
따라서 h_\theta(x) 의 값은 0과 1사이 ( 0 \leq h_\theta(x) \leq 1 )에 있어야 한다.
Linear Regression 에서 사용했던 공식을 사용하면 결과값이 0보다 작을수도, 1보다 커실수도 있으므로, Sigmoid Function(Logistic Function)을 사용해서 결과값의 범위를 제한할 필요가 있다.

Sigmoid Function 을 아래와 같이 정의한다.

h_\theta(x) = \frac{1}{1 + e^{\theta^TX}}

Normal Equation ( 정규 방정식)

선형회귀분석에서 cost function J(\theta) 의 값이 최소가 되는 \theta 를 찾기 위한 방법으로 경사 하강법(Gradient Decent)와 정규 방정식(Normal Equation)이 있다.

정규방정식은 \theta = (X^TX)^{-1}X^Ty 로 표현이 되는데,
Feature 갯수(n)이 많게 되면 (X^TX)^{-1} 를 구하는데 시간이 오래 걸리기 때문에 경사 하강법을 사용하는게 좋다.
하지만 feature 갯수 nn \leq 10^4 정도라면 한번에 계산해 낼 수 있는 정규 방정식이 유리하다.

Feature Scaling

여러개의 변수(Multiple Variables)를 가지고 회귀분석(Linear Regression)을 할 때 변수의 스캐일이 너무 차이가 나면 Cost Function J(\theta) 를 이용한 Gradient Decent과정이 너무 오래걸릴 수 있다.

예를 들면 집의 가격을 예측하는 모델에서 가격을 결정하는 변수들로 크기(1000 ~ 2000), 방의 갯수(1~5), 사용년수(1~20)등을 생각해 볼 수 있는데 각각의 변수들의 스케일의 볌위가 많이 달라서 등고선을 그려보면 매우 좁고 길쭉한 모양이 나타나게 된다.

이럴때는 Mean Normalization 을 사용해서 변수의 범위를 -1 \leq x_i \leq 1 로 조정하는 방법을 사용할 수 있다.

Nomalized된 변수 Z는 아래와 같이 구할 수 있다.
z = \frac{x - \mu_{avg}}{max(x) - min(x)}

집가격을 예측하는 모델을 h_\theta(x) = \theta_0 + \theta_1x_{size} + \theta_2x_{rooms}라고 할 때,
집크기 x_{size}x_{rooms}를 Normalization을 아래와 같이 할 수 있다.

 

  • 수집된 데이터에서 집크기(size) 의 평균은 1000이고 최소값은 200, 최대값은 2000이라고 할 때 집크기가 1200인 집의 Nomalized 된 값은 Z_{size} = \frac{x - \mu_{avg}}{max(x) - min(x)} = \frac{1200 - 1000}{2000 - 200} = 0.1111 이다.
  • 수집된 데이터에서 방의 갯수(rooms)의 평균은 5이고, 최소값은 2, 최대값은 8이라고 할때 방의갯수가 3인 관측값의 Normalized된 값은 Z_{rooms} = \frac{x - \mu_{avg}}{max(x) - min(x)} = \frac{3 - 5}{8 - 2} = -0.3333 이다.

Spam Mail Classifying

우리가 메일 서비스를 이용할 때 스팸 메일들이 자동으로 스팸함으로 이동되는 것을 볼 수 있다. 메일 서비스들은 도착한 메일이 스팸인지 아닌지 여부를 어떻게 판단해서 스팸으로 분류할 수 있는 것일까?

기본적으로는 “베이지안 추론“이라는 통계적 추론 방법을 통해 메일을 분류하게 되는데, 베이지안 추론이란, 사전확률을 통해 사후확률을 추론하는 것이다.

사용자들이 메일을 수신하고 스팸메일함으로 이동시킨 메일을 대상으로 “스팸으로 분류된 메일에 특정 단어들이 나타날 확률“을 미리 계산해 놓으면(사전확율), 어떤 특정 단어들이 나타났을 때 이 메일이 스팸일 확율(사후 확률)을 구할 수 있게 된다. 즉, 기존의 데이터를 이용해서 스팸메일로 분류할 방법을 학습(learning)시키는 것이라고 볼 수 있다.

1. Data 구하기

Model Training & Test  용 데이터는 UCI – Machine Learning Repository (https://archive.ics.uci.edu/ml/datasets/Spambase) 에서 가져와서 사용한다.

사용할 데이터는 https://archive.ics.uci.edu/ml/machine-learning-databases/spambase/ 에서 확인할 수 있으며, spambase.zip 파일을 다운로드 받도록 한다.

spambase.zip 파일을 다운로드 받아서 압출을 풀면 3개의 파일을 확인해 볼 수 있다.

  • spambase.DOCUMENTATION
    • 데이터파일(spambase.data)에 대한 description 이다. 데이터의 구조와 각 컬럼에 대한 설명을 가지고 있다.
  • spambase.data
    • 우리가 사용할 데이터 파일이다.
    • 총 4,601건의 데이터(row)가 있으며, 1,813개가 스팸으로 분류되어 있다.
    • 총 58개의 컬럼을 가지고 있으며, 1개의 컬럼은 spam/non-spam 분류를 나타내고 나머지 57개 컬럼은 각 컬럽의 타입 속성이 나타난 percentager값(0~100)이다.
  • spambase.names
    • Spambase.data 의 헤더 정보가 들어있다.

2. Tidy Dataset 만들기

Spambase dataset 에 헤더정보가 없으므로 헤더를 구성한다.


load data file
spam.base.df<- read.csv("./data/spambase.data",header=FALSE)

# load header file
# MakeHeader.py 로 spambase.names 에 있는 헤더 정보를 추출하여 headers 파일로 기록해 두었음.
spam.base.header <- read.csv("./data/headers",header=FALSE,stringsAsFactors = F)
# column 명에 특수문자가 포함되어 있으므로 make.names를 하지 않으면 as.formula에서 오류가 난다.
headers <- make.names(spam.base.header[,1],unique=T)
headers <- c(headers,"spam")
names(spam.base.df) <- headers
spam.base.df$spam <- as.factor(ifelse(spam.base.df$spam > 0.5, "spam","non-spam"))

spambase.names 파일에서 헤더정보를 추출하는 파이썬 코드

__author__ = 'yhlee'
 
import re
 
regex = re.compile('^(.+):\s+continuous\.')
 
f = open("data/spambase.names")
out = open("data/headers", "w")
 
for line in f.readlines():
    # print(line)
    m = regex.match(line)
    if m:
        # print line
        header =  m.group(1) + "\n"
        out.writelines(header)

3. Training Data

Machine Learning 모델을 선택해야 한다. 우리가 원하는 것은 특정 관측값(Observation)-수신한 메일-이 스팸 메일인지 아닌지에 대한 “분류”를 추정하는 것이다.

즉, 정량적 (Quantitive) 예측이 아니고 정성적(Qualitative) 예측을 해야 한다. 예측하고자 하는 값(spam/non-spam) 이 데이터에 이미 포함되어 있고, 그 값을 바탕으로 training을 할 것이므로 우리가 하고자 하는 분석은 Supervised Classification이라고 할 수 있다. Classfication Method에는 Naive Bayes, Decision Tree, Logistic Regression, LDA,  KNN 등 여러가지 방법이 있으며,지금은 특정 관측값이 특정 분류에 속하게 될 확률을 추정해야 하고, 분류(Class)결과는 스팸/Non-Spam 두 가지의 (binomial) 결과가 있으므로 “Logistic Regression”을 선택해서 모델을 만들어 보겠다.


#fitting model
## Data Split to Train/Test
require(caret)
set.seed(1234)
trainIdx <- createDataPartition(y=spam.base.df$spam, p=0.75,list=F)
trainData <- spam.base.df[trainIdx,]
testData<- spam.base.df[-trainIdx,]

spamCols <- setdiff(colnames(trainData),list("spam"))
spam.fomula <- as.formula(paste('spam=="spam"',paste(spamCols,collapse=' + '),sep=' ~ '))

#모델 만들기
fit <- glm(spam.fomula,family = binomial(link='logit'),data=trainData)

4. Calculate Accuracy On TrainData

스크린샷 2015-01-14 16.19.31

 Training Data 에 대한 Confusion Matrix 를 확인해 보면 accuracy가 92% 임을 확인 할 수 있다. Training Data로는 모델이 잘 만들어 진 것 같은데, testData로 내용을 검증해 보도록 하자.

5. Calculate Accuracy On TestData

스크린샷 2015-01-14 16.22.50

TestData 에 대해서도 ConfusionMatrix를 확인해 본 결과 92%를 보여주고 있다. ROC Curve를 체크하면서 Threshold값을 조정한다면 더 정교한 모델을 만들수도 있다.

* GitHub Location

https://github.com/Yonghee/spam-mail-classfication.git