<jupyter_start><jupyter_text>in Gaussian normal distribution<jupyter_code>np.random.seed(0)
rv0 = sp.stats.multivariate_normal([-2, -2], [[1, 0.9],[0.9, 2]])
rv1 = sp.stats.multivariate_normal([2, 2], [[1.2, -0.8],[-0.8, 2]])

x0 = rv0.rvs(40)
x1 = rv1.rvs(60)
x = np.vstack([x0, x1])
y = np.hstack([np.zeros(40), np.ones(60)])<jupyter_output><empty_output><jupyter_text>컬럼 별로 확률변수로 보는게 아니라 클래스별로 확률변수로 보는건가?..<jupyter_code>xx1 = np.linspace(-5, 5, 100)
xx2 = np.linspace(-5, 5, 100)

XX1, XX2 = np.meshgrid(xx1,xx2)
plt.grid(False)
plt.contour(XX1, XX2, rv0.pdf(np.dstack([XX1, XX2])), cmap=mpl.cm.cool)
plt.contour(XX1, XX2, rv1.pdf(np.dstack([XX1, XX2])), cmap=mpl.cm.hot)

plt.scatter(x0[:,0], x0[:,1] , marker= 'o', s=50, c='b')
plt.scatter(x1[:,0], x1[:,1], marker= 'o', s=50, c='r')

plt.axis('equal')
plt.show()
from sklearn.naive_bayes import GaussianNB
model1 = GaussianNB().fit(x,y)
print("클래스 종류 : {} ,\n 클래스별 샘플 수 : {}, \n 클래스별 사전확률 : {}".format(model1.classes_, model1.class_count_, model1.class_prior_))
model1.theta_<jupyter_output><empty_output><jupyter_text>가우시안이기때문에 theta는 모수(mean)으로 볼 수 있다.- 클래스0의 ,x1, x2 각각의 theta는 -1.96197643, -2.00597903- 클래스1의 ,x1, x2 각각의 theta는 2.19130701,  2.12626716<jupyter_code>model1.sigma_<jupyter_output><empty_output><jupyter_text>x1, x2의 분산만 나올뿐 공분산은 빠져있는것을 알 수 있다. (조건부 독립이라서 공분산은 0으로 처리)- 클래스0의 ,x1, x2 각각의 sigma는 1.02398854,  2.31390497- 클래스1의 ,x1, x2 각각의 sigma는 1.25429371,  1.93742544<jupyter_code>rv0 = sp.stats.multivariate_normal(mean=model1.theta_[0], cov=model1.sigma_[0])
rv1 = sp.stats.multivariate_normal(mean=model1.theta_[1], cov=model1.sigma_[1])

xx1 = np.linspace(-5, 5, 100)
xx2 = np.linspace(-5, 5, 100)
XX1, XX2 = np.meshgrid(xx1, xx2)

plt.grid(False)
plt.contour(XX1, XX2, rv0.pdf(np.dstack([XX1, XX2])), cmap=mpl.cm.cool)
plt.contour(XX1, XX2, rv1.pdf(np.dstack([XX1, XX2])), cmap=mpl.cm.hot)

plt.scatter(x0[:,0], x0[:,1], marker='o', s=50, c='b')
plt.scatter(x1[:,0], x1[:,1], marker='o', s=50, c='r')

plt.axis('equal')
plt.show()<jupyter_output><empty_output><jupyter_text>공분산이 0이기 때문에, 그래프의 기울어짐이 사라졌다...  새로운 test 데이터 샘플을 넣어보자<jupyter_code>x_new = np.array([[-0.7, -0.8]])
model1.predict_proba(x_new)<jupyter_output><empty_output><jupyter_text>클래스0일 확률이 0.983, 클래스1일 확률이 0.017  위 결과가 나온 중간과정을 보자<jupyter_code>likelihood = [
    sp.stats.norm(model1.theta_[0], np.sqrt(model1.sigma_[0])).pdf(x_new).prod(),
    sp.stats.norm(model1.theta_[1], np.sqrt(model1.sigma_[1])).pdf(x_new).prod()
]
sp.stats.norm(model1.theta_[0], np.sqrt(model1.sigma_[0])).pdf(x_new).prod()
sp.stats.norm(model1.theta_[0], np.sqrt(model1.sigma_[0])).pdf(x_new)<jupyter_output><empty_output><jupyter_text>바로 위 출력값의 의미- `x_new[0]`값을 class0의 x1의 pdf에 넣었을 때 나온 함수값 = 0.18115014- `x_new[1]`값을 class0의 x2의 pdf에 넣었을 때 나온 함수값 = 0.19153637<jupyter_code>0.18115014 * 0.19153637<jupyter_output><empty_output><jupyter_text>- prod()은 값 두 개를 곱해준다는 의미- class0에서 각각의 P(x1|y=class0), P(x2|y=class0)은 서로 독립이다.(조건부 독립) 중간과정 결과해석(정리)- 독립이기 때문에 class0의 likelihood P(x|y=class0)는 P(x1|y=class0) * P(x2|y=class0)로 구할 수 있다.- (x의 차원이 2개이므로 P(x1,x2|y=class0) : 결합확률을 P(x|y=class0)로 표현).- 그래서 prod()로 0.18115014 * 0.19153637 해준 것이다.<jupyter_code>post = likelihood * model1.class_prior_
post<jupyter_output><empty_output><jupyter_text>이 출력값은 P(x_new|y=class0) X P(y=class0)와 P(x_new|y=class1) X P(y=class1)을 구한 것이다.<jupyter_code>post/post.sum()<jupyter_output><empty_output><jupyter_text>P(x)로 나눠주면 P(y=class0|x_new)와P(y=class1|x_new)일 확률을 각각 구한 것이다  in Bernoulli distribution<jupyter_code>x = np.array([
    [0, 1, 1, 0],
    [1, 1, 1, 1],
    [1, 1, 1, 0],
    [0, 1, 0, 0],
    [0, 0, 0, 1],
    [0, 1, 1, 0],
    [0, 1, 1, 1],
    [1, 0, 1, 0],
    [1, 0, 1, 1],
    [0, 1, 1, 0]])
y = np.array([0,0,0,0,1,1,1,1,1,1])<jupyter_output><empty_output><jupyter_text>4개의 키워드(4개의 열)를 사용하여 정상메일(y=0) 4개와 스팸메일 6개를 BOW 인코딩한 행렬이다.<jupyter_code>from sklearn.naive_bayes import BernoulliNB
model2 = BernoulliNB().fit(x,y)
print("클래스 종류 : {} ,\n 클래스별 샘플 수 : {}, \n 클래스별 사전확률 : {}".format(model2.classes_, model2.class_count_, np.exp(model2.class_log_prior_)))<jupyter_output>클래스 종류 : [0 1] ,
 클래스별 샘플 수 : [ 4.  6.], 
 클래스별 사전확률 : [ 0.4  0.6]<jupyter_text>`class_prior_`가 있는데 None이 뜸...왜 있는건지...<jupyter_code>model2.feature_count_<jupyter_output><empty_output><jupyter_text>클래스0는 키워드가 각각 2,4,3,1번 나옴클래스1는 키워드가 각각 2,3,5,3번 나옴<jupyter_code>model2.feature_count_/model2.class_count_[:,np.newaxis]
model2.feature_count_/np.repeat(model2.class_count_[:,np.newaxis],repeats=4, axis=1)
model2.alpha<jupyter_output><empty_output><jupyter_text>스무딩 가중치 값이 1.0으로 디폴트 설정되어있다.(model2생성시)<jupyter_code>np.exp(model2.feature_log_prob_)<jupyter_output><empty_output><jupyter_text>bernoulli 분포에서 스무딩은 각 feature의 확률을 0.5에 가까워지도록 만든다.- feature_log_prob_은 스무딩이 된 상태다.- 스무딩 전 확률보다 각 확률이 좀 더 0.5에 가까워졌다.<jupyter_code>x_new = np.array([[1,1,0,0]])
model2.predict_proba(x_new)<jupyter_output><empty_output><jupyter_text>위 확률의 도출과정을 살펴보자<jupyter_code>theta = np.exp(model2.feature_log_prob_)
p = ((theta ** x_new)*((1-theta)**(1-x_new))).prod(axis=1) * np.exp(model2.class_log_prior_)
p / p.sum()<jupyter_output><empty_output><jupyter_text>- 출력값에 대한 설명은 가우시안과 같다.- x_new(document)는 정상메일이라 볼 수 있다.  in multi-nomial distribution<jupyter_code>x = np.array([    
    [3, 4, 1, 2],
    [3, 5, 1, 1],
    [3, 3, 0, 4],
    [3, 4, 1, 2],
    [1, 2, 1, 4],
    [0, 0, 5, 3],
    [1, 2, 4, 1],
    [1, 1, 4, 2],
    [0, 1, 2, 5],
    [2, 1, 2, 3]])
y = np.array([0, 0, 0, 0, 1, 1, 1, 1, 1, 1])<jupyter_output><empty_output><jupyter_text>클래스별로 4면체 주사위를 던진 횟수가 다르다- class0는 10번, class1은 8번<jupyter_code>from sklearn.naive_bayes import MultinomialNB
model3 = MultinomialNB().fit(x,y)
print("클래스 종류 : {} ,\n 클래스별 샘플 수 : {}, \n 클래스별 사전확률 : {}".format(\
                                                                 model3.classes_, model3.class_count_, np.exp(model3.class_log_prior_)))<jupyter_output>클래스 종류 : [0 1] ,
 클래스별 샘플 수 : [ 4.  6.], 
 클래스별 사전확률 : [ 0.4  0.6]<jupyter_text>얘도 class_prior가 None...<jupyter_code>fc = model3.feature_count_
fc<jupyter_output><empty_output><jupyter_text>class0에서 4면체 주사위를 던져 각 눈이 나온 횟수가 12,16,3,9회<jupyter_code>fc / fc.sum(axis=1)[:,np.newaxis]
fc / np.repeat(fc.sum(axis=1)[:,np.newaxis], 4, axis=1)
model3.alpha
fc.sum(axis=1)<jupyter_output><empty_output><jupyter_text>스무딩이 디폴드로 1.0으로 설정되어있다.(model3생성시)  스무딩 과정 좀 더 자세히<jupyter_code>(fc + model3.alpha) / (np.repeat(fc.sum(axis=1)[:,np.newaxis], 4, axis=1) + model3.alpha * x.shape[1])<jupyter_output><empty_output><jupyter_text>위 결과는 스무딩한 결과다. (각 feature의 확률에 분자에 1, 분모에 4를 더함)<jupyter_code>np.exp(model3.feature_log_prob_)<jupyter_output><empty_output><jupyter_text>- 같은 결과임.- multi-nomial분포에서는 bernoulli분포와 스무딩방법이 좀 다름  P(y|x_new)의 도출과정 in multi-nomial<jupyter_code>x_new = np.array([[1,1,0,0]])
model3.predict_proba(x_new)
theta = np.exp(model3.feature_log_prob_)
p = (theta ** x_new).prod(axis=1) * np.exp(model3.class_log_prior_)
p / p.sum()<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.1860164005179111, 'fraction_numerical': 0.07682347863616745, 'mean_word_length': 5.179555555555556, 'pattern_counts': {'":': 0, '<': 91, '<?xml version=': 0, '>': 91, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '23', 'dir': 'jupyter-structured-clean-dedup', 'id': '346104', 'license': 'MIT', 'n_tokens_mistral': 4142, 'n_tokens_neox': 4445, 'n_words': 589, 'path': 'machinelearning/classification/naive bayes/naive_bayes_review.ipynb', 'repo_name': 'Junhojuno/TIL', 'size': '6951'}