Group Study (2020-2021)/Machine Learning

[Machine Learning] 4주차 스터디 - 나이브 베이즈 분류기

@shpark0308 2020. 11. 8. 13:38

 

▶실습

  •  실습 내용 : train.csv의 데이터를 가지고 와서 ['text', 'target'] 컬럼만 가져오기

1 ).  데이터 불러오기 및 필요한 데이터만 선별하여 train data에 저장

import pandas as pd
import re
from collections import Counter
from math import log, exp

df = pd.read_csv('./train.csv')
# "text", "target" column만 갖고오기
df = df[['text','target']]
df.head()

필요한 컬럼만 데이터에서 가져온다

# target == 0
df_zero = []
# target == 1
df_one = []

for i in range(len(df)):
    # 아래 pass 지우고 코드 작성
    if df.iloc[i,1]==0:
        df_zero.append(df.iloc[i,0])
    else:
        df_one.append(df.iloc[i,0])

print(df_zero)
print(df_one)

train_datas = [" ".join(df_zero), " ".join(df_one)]

위에 있는 데이터 df를 for문으로 돌면서 target이 0일 경우 df_zero에 담고 target이 1일 경우 df_one에 담는다. 그 이후 보다 쉽게 토큰화를 하기 위해 train_datas를 target이 0인 문장과 target이 1인 문장을 한문장으로 합치는 과정을 거친다 

# train_datas = [target==0인 문장, target==1인 문장]
train_datas = [" ".join(df_zero), " ".join(df_one)]

 

2 ). 데이터 전처리

def preprocessing(data):
    data_sw = re.sub('[^a-z0-9]',' ',data.lower())
    tokenized = data_sw.split(' ')
    word_vector = {}
    for a in tokenized:
        if a not in word_vector:
            word_vector[a]=1
        else:
            word_vector[a]+=1
    return word_vector, len(tokenized)
    
train_zero, zero_total_wc = preprocessing(train_datas[0])
train_one, one_total_wc = preprocessing(train_datas[1])

 

 

이전에 각각의 target에 따라 토큰화 한 train_datas를 먼저 (( 소문자로 바꾸고 )) (( 문자가 아닌 것들을 띄어쓰기로 변경 ))하는 작업을 걸친다. 다음 띄어쓰기를 기준으로 토큰화 한 다음 이를 { 단어 : 빈도수 } 의 형태로 바꾸어주는 Bow 화를 하여 각 각의 단어들이 얼마나 많이 나와 있는지를 알 수 있게 한다.

 

3 ). 문장이 나올 확률 구하기 ( log를 이용 )

nowords_w = 0.1
def getLogProb(train_vector, test_vector, total_wc):
    log_prob = 0
    for word in test_vector:
        # word가 train_vector에 있는 경우 --> 단어 등장 확률 // 없는 경우 --> 사전에 임의로 정한 확률
        if word in train_vector:
            log_prob += log ( train_vector[word] / total_wc)
        else:
            # 없는 단어는 가정
            log_prob += log(nowords_w/total_wc)
    return log_prob
    
    
test_data = "Traffic accident"        # 예측 대상 문장 #input()으로 대체 가능
test_vector, _ = preprocessing(test_data)

해당 문장이 나올 확률을 문장의 각 각의 단어가 등장할 확률을 전부 곱한 것으로 정의하여 log를 취할 수 있도록 하였다. 

4 ). 베이즈 정리 이용과 로그를 지수화

zero_prob = zero_total_wc / (zero_total_wc + one_total_wc ) # P(target == 0)
one_prob = one_total_wc / (zero_total_wc + one_total_wc) # P(target == 1)

(( target == 0 ))일 확률 = 0인 경우 / 0인 경우 + 1인 경우  |  (( target == 1 ))일 확률 = 1인 경우 / 0인 경우 + 1인 경우

# P(부정|test_data) = P(test_data|부정) * P(부정) / P(test_data)
test_zero_prob = getLogProb(train_zero, test_vector, zero_total_wc) + log(zero_prob) 
# P(긍정|test_data) = P(test_data|긍정) * P(긍정) / P(test_data)
test_one_prob = getLogProb(train_one, test_vector, one_total_wc) + log(one_prob)

로그 연산을 이용한 베이즈 정리를 사용하여 부정일 확률과 긍정일 확률을 계산할 수 있도록 한다

maxprob = max(test_zero_prob, test_one_prob)
test_one_prob -= maxprob
test_zero_prob -= maxprob

# log 없애주기 위해 지수화 --> 힌트) exp 함수 사용
test_one = exp(test_one_prob)
test_zero = exp(test_zero_prob)

# 두 확률 값의 상대적인 비율 구하기(normalization)
a = test_zero / (test_one + test_zero)
b = test_one / (test_one + test_zero)
normalized_prob = [a, b]
# 둘 중 큰 것의 index 출력
print(normalized_prob.index(max(normalized_prob)))

normalized_prob

그 결과 [ target == 0, target ==1 ]일 때의 확률을 각각 ex). [ 0.09, 0.9 ]로 출력할 수 있도록 한다