👨🏻‍🏫IT 활동/인공지능교육 - NLP

[NLP] Day 24 - Naive bayes

728x90
반응형

Naive Bayes

MLE : 데이터만 가지고 ( 반드시 데이터가 있어야 추정 가능, 없으면 동작 X )

MAP : 데이터와 사전 정보를 가지고 ( 데이터가 없어도 사전 정보를 가지고 알아낼 수 있음 ) 조금 더 Optimal하다.

Naive assumption : 입력데이터끼리 conditional independence 하다고 가정한다. ( 실생활에서느 그렇지 않지만 계산을 위해 )

Ex) 대출, 광고 모두 스팸이라면 둘 사이는 원래 강한 상관관계가 존재한다.

Combination을 아래와 같이 구할 수 있는 것이다.

( 특정 정보가 주어졌을 때, (사전 정보= 스팸이라고 알려줬을 때, 대출과 광고는 독립이다.) )


 로 볼 수 있는 것이다.

따라서 이 성립하는 것이다.


Naive bayes 문제점 :

확률 값을 정확히 예측 못함 

MLE에서는 데이터가 불충분할 때, MAP에서는 사전 정보가 좋지 못할 때.


다 곱하는 것에서 log를 취해서 다 더하는 형태로 바꿔줌 ( 곱으로 진행하면 확률이 0에 수렴함, log를 통해 합으로 바꿔서 해결 )

그리고 하나가 0이어도 사라지지 않는다. ( unknown data에 대해, prior knowledge가 영향을 미치게 되는 것이다 )

In [22]:
# 코드로 구현하기 

trainingSet = [
    (1,"Chinese Beijing Chinese","yes"),
    (2,"Chinese Chinese Shanghai","yes"),
    (3,"Chinese Macao","yes"),
    (4,"Tokyo Japan Chinese","no"),
]

testSet = [
    (5,"Chinese Chinese Chinese Tokyo Japan")   
]
In [23]:
# 
trainingSetYes = [d for d in trainingSet if d[2] == "yes"]
trainingSetNo = [d for d in trainingSet if d[2] == "no"]
In [24]:
trainingSetYes, trainingSetNo
Out[24]:
([(1, 'Chinese Beijing Chinese', 'yes'),
  (2, 'Chinese Chinese Shanghai', 'yes'),
  (3, 'Chinese Macao', 'yes')],
 [(4, 'Tokyo Japan Chinese', 'no')])
In [25]:
# doc의 전체 갯수 구하기
N = len(trainingSet)
N
Out[25]:
4
In [26]:
# 사전 정보 구하기 prior[c]
# MLE : 주어진 데이터를 이용해 확률값 추정 
priorYes = len(trainingSetYes) / N
priorNo = 1 - priorYes
In [27]:
# 확률이라 1이 되어야 한다. 
priorYes, priorNo, priorYes+priorNo
Out[27]:
(0.75, 0.25, 1.0)
In [28]:
# 확률을 누적시킬 것 
from collections import defaultdict

# 빈도를 이용할 것이므로 int
tokensYes = defaultdict(int)
tokensNo = defaultdict(int)

for d in trainingSetYes:
    for t in d[1].lower().split():  # 소문자로 / 
        tokensYes[t] += 1    # 나오는 것 하나씩 누적시킴
    
for d in trainingSetNo:
    for t in d[1].lower().split():  # 소문자로 / 
        tokensNo[t] += 1 
        
# Unique한 word를 뽑는 과정 

vocabulary = list(set(list(tokensYes.keys()) + list(tokensNo.keys())))
In [29]:
tokensYes, tokensNo
Out[29]:
(defaultdict(int, {'chinese': 5, 'beijing': 1, 'shanghai': 1, 'macao': 1}),
 defaultdict(int, {'tokyo': 1, 'japan': 1, 'chinese': 1}))
In [30]:
# 전체의 unique한 단어 set 
vocabulary
Out[30]:
['tokyo', 'japan', 'chinese', 'macao', 'beijing', 'shanghai']
In [31]:
# 이제 조건부 확률을 구해야 함.
# Conditional Probabilities

sumYes = sum(tokensYes.values())
sumNo = sum(tokensNo.values())
In [32]:
# 각 클래스에 따른 단어의 갯수 
sumYes, sumNo
Out[32]:
(8, 3)
In [34]:
from math import log
cpYes = defaultdict(float)
cpNo = defaultdict(float)

B = len(vocabulary)

# token ( log를 미리 씌움 )
for t in vocabulary:
    cpYes[t] = log((tokensYes[t]+1) / (sumYes + B))  # 1 더해서 smoothing / 분모에 1씩더하는 것은 B를 더하면 됨 
    cpNo[t] = log((tokensNo[t]+1) / (sumNo + B))
    print(t)
    print("Yes, {0} = {1}+1 / {2}+{3}".format(cpYes[t],tokensYes[t],sumYes,B))
    print("No, {0} = {1}+1 / {2}+{3}".format(cpNo[t],tokensNo[t],sumNo,B))


# for t,f in tokensNo.items():
#     cpNo[t] = log((f+1) / (sumNo + B))
#     print(t)
#     print("{0} = {1} / {2}+{3}".format(cpNo[t],f,sumNo,B))
tokyo
Yes, -2.639057329615259 = 0+1 / 8+6
No, -1.5040773967762742 = 1+1 / 3+6
japan
Yes, -2.639057329615259 = 0+1 / 8+6
No, -1.5040773967762742 = 1+1 / 3+6
chinese
Yes, -0.8472978603872037 = 5+1 / 8+6
No, -1.5040773967762742 = 1+1 / 3+6
macao
Yes, -1.9459101490553135 = 1+1 / 8+6
No, -2.1972245773362196 = 0+1 / 3+6
beijing
Yes, -1.9459101490553135 = 1+1 / 8+6
No, -2.1972245773362196 = 0+1 / 3+6
shanghai
Yes, -1.9459101490553135 = 1+1 / 8+6
No, -2.1972245773362196 = 0+1 / 3+6
In [35]:
# + Smoothing 기법 ( 라플라스 )

cpYes = defaultdict(float)
cpNo = defaultdict(float)

K = 0.5

# token ( log를 미리 씌움 )
for t in vocabulary:
    cpYes[t] = log((tokensYes[t]+ K) / (sumYes + K*2))  # 1 더해서 smoothing / 분모에 1씩더하는 것은 B를 더하면 됨 
    cpNo[t] = log((tokensNo[t]+ K) / (sumNo + K*2))
    print(t)
    print("Yes, {0} = {1}+1 / {2}+{3}".format(cpYes[t],tokensYes[t],sumYes,B))
    print("No, {0} = {1}+1 / {2}+{3}".format(cpNo[t],tokensNo[t],sumNo,B))


# for t,f in tokensNo.items():
#     cpNo[t] = log((f+1) / (sumNo + B))
#     print(t)
#     print("{0} = {1} / {2}+{3}".format(cpNo[t],f,sumNo,B))
tokyo
Yes, -2.890371757896165 = 0+1 / 8+6
No, -0.9808292530117262 = 1+1 / 3+6
japan
Yes, -2.890371757896165 = 0+1 / 8+6
No, -0.9808292530117262 = 1+1 / 3+6
chinese
Yes, -0.49247648509779407 = 5+1 / 8+6
No, -0.9808292530117262 = 1+1 / 3+6
macao
Yes, -1.791759469228055 = 1+1 / 8+6
No, -2.0794415416798357 = 0+1 / 3+6
beijing
Yes, -1.791759469228055 = 1+1 / 8+6
No, -2.0794415416798357 = 0+1 / 3+6
shanghai
Yes, -1.791759469228055 = 1+1 / 8+6
No, -2.0794415416798357 = 0+1 / 3+6
In [36]:
cpYes, cpNo
Out[36]:
(defaultdict(float,
             {'tokyo': -2.890371757896165,
              'japan': -2.890371757896165,
              'chinese': -0.49247648509779407,
              'macao': -1.791759469228055,
              'beijing': -1.791759469228055,
              'shanghai': -1.791759469228055}),
 defaultdict(float,
             {'tokyo': -0.9808292530117262,
              'japan': -0.9808292530117262,
              'chinese': -0.9808292530117262,
              'macao': -2.0794415416798357,
              'beijing': -2.0794415416798357,
              'shanghai': -2.0794415416798357}))
In [37]:
from math import log, exp

for d in testSet:
    scoreYes = log(priorYes)
    scoreNo = log(priorNo)
    
    for t in d[1].lower().split():
        # 원래는 곱셈인데 로그 취해서 + 가능 
        scoreYes += cpYes[t]   
        scoreNo += cpNo[t]
        
    print(exp(scoreYes), exp(scoreNo))  # 로그 상태로 지수 취해서 원래대로 나타냄
    if scoreYes > scoreNo:
        print("Yes")
    else:
        print("No")
        
# 빈도 수를 따라 training보고 판단했을 것. 
# testSet의 chinese를 하나로 줄이면 No를 반환함 
0.0005282953563989228 0.0018539428710937502
No

스팸 수집 꿀팀

selenium은 로그인 때문에 쓰는 것!

데이터만 가로챌 것

In [38]:
from selenium import webdriver
driver = webdriver.Chrome(executable_path='/Users/charming/Python/3. Koipa AI Learning/NLP/chromedriver')
In [39]:
driver.get('https://nid.naver.com/nidlogin.login?url=http%3A%2F%2Fmail.naver.com%2F')
In [49]:
# 쿠키값이 필요한 것 
import requests

cookie = driver.get_cookies()
session = requests.Session()

# cookie 는 dict 형태

# for c in cookie:
#     print(c['name'], c['value'])
#     session.cookies.set(c['name'], c['value'])

    # set으로 다 밀어넣으면됨
In [41]:
# 이제 selenium 필요없음 
# session.cookies
In [42]:
# requests로 접근해야함 
url = "https://mail.naver.com/json/list/"
data={  "page":1,
        "sortField":1,
        "sortType":0,
        "folderSN":0,
        "isUnread":"false",
        "u":"trueman9512"}

# 로그인 안됨 
# resp = requests.post(url,data)
# resp.text

# 쿠키만 있으면 로그인 가능 
resp = session.post(url,data)
# resp.text
In [43]:
type(resp.text)
Out[43]:
str
In [45]:
from bs4 import BeautifulSoup
dom = BeautifulSoup(resp.content,"lxml")
In [46]:
for tag in dom.select('subject'):
    print(tag.text)
In [47]:
for tag in dom.select("subject"):
    print(tag.text)


728x90
반응형