강은 가정을 거의 안 하는 쪽 끝을 봤습니다. 이번에는 반대쪽 끝으로 갑니다.
이 가정이 참인 경우는 거의 없습니다. 낱말 "기계"와 "학습"은 같은 문서에 함께 나오고, 키와 몸무게는 같은 사람에게 함께 붙습니다. 그런데도 이 방법은 수십 년째 쓰입니다.
이 강의는 그 이유를 정확히 밝힙니다. 갈래를 고르는 것과 확률을 재는 것은 다른 일이고, 나이브 가정은 앞의 것만 지킵니다.
문제. 최적 분류기를 세웁니다.
() 베이즈 규칙의 각 조각을 정리하세요.
() 최적 오류율을 확인하세요.
() 우도를 통째로 추정하면 무엇이 어려운지 세세요.
생각의 실마리. 강의 베이즈 규칙은 원인과 결과의 방향을 뒤집는 공식입니다. 분류는 결과()를 보고 원인()을 맞히는 일이므로 정확히 이 공식이 필요합니다.
풀이. () 정리합니다.
| 무엇 | 기호 | 무엇을 뜻하나 |
|---|---|---|
| 사후확률 | 주어진 | 답을 정하는 것 |
| 우도 | 주어진 | 갈래마다의 분포 |
| 사전확률 | 갈래의 비율 | |
| 증거 | 갈래와 무관한 몫 |
분모는 갈래에 안 딸리므로 견줄 때는 빼도 됩니다. 그러면 우도 곱하기 사전확률이 가장 큰 갈래를 고르면 됩니다.
() 최적 오류율을 확인합니다. 참 확률을 다 안다고 하고 잽니다.
| 판정 방법 | 오류율 | 최적과의 차 |
|---|---|---|
| 참 확률이 넘으면 양성 | ||
| 참 확률이 넘으면 양성 | ||
| 언제나 양성 | ||
| 동전 던지기 |
참 확률로 문턱을 쓰는 것이 베이즈 분류기이고, 그 오류율보다 낮게 갈 수 있는 방법은 없습니다. 이 이 자료의 바닥입니다.
강 문제 의 잡음처럼 줄일 수 없는 양입니다. 모형을 아무리 좋게 만들어도 아래로 못 갑니다.
문턱을 으로 옮기면 을 손해 봅니다. 그래도 손해가 크지 않은데, 이것이 강에서 문턱을 옮겨 재현율을 사는 근거가 됩니다.
() 우도를 통째로 추정하면 무엇이 어려운지 셉니다.
| 변수 개수 | 이진 변수면 세야 할 칸 수 | 칸마다 개면 필요한 표본 |
|---|---|---|
변수 개면 억 칸이 넘습니다. 강 문제 의 칸 세기와 같은 계산이고, 우도를 통째로 추정하는 것은 사실상 불가능합니다.
그래서 우도에 강한 가정을 넣습니다. 다음 문제가 그 가정입니다.
이 문제에서 배우는 것. 분류의 정답은 이미 강에 있었습니다. 문제는 를 모른다는 것이고, 그것을 어떻게 추정하느냐가 방법들을 갈라놓습니다.
확인 1-1. 베이즈 분류기가 무엇을 최대로 하는지 쓰세요.
답. 우도 곱하기 사전확률입니다.
확인 1-2. 검산에서 베이즈 분류기의 오류율을 쓰세요.
답. 입니다.
확인 1-3. 검산에서 이진 변수 개면 몇 칸을 세야 하는지 쓰세요.
답. 칸입니다.
문제. 독립 가정을 넣습니다.
() 무엇이 줄어드는지 세세요.
() 상관이 있어도 왜 잘 되는지 재세요.
() 같은 변수를 복사해 넣어 보세요.
생각의 실마리. 곱으로 쪼개면 칸이 아니라 축을 세게 됩니다. 가 가 됩니다.
풀이. () 셉니다.
| 무엇 | 추정해야 할 수 | 변수 개면 |
|---|---|---|
| 통째로 | 의 제곱 빼기 | 억 개 넘음 |
| 순진한 가정 | 곱하기 갈래 수 | 개 |
| 줄어드는 비율 | 지수에서 선형으로 | 천만 분의 |
이 가정이 참인 경우는 거의 없습니다. 그래서 순진하다고 부릅니다.
() 상관이 있어도 잘 되는지 잽니다. 갈래 안에서 두 변수의 상관을 바꿔 가며 잽니다.
| 갈래 안 상관 | 나이브 정확도 | 로지스틱 정확도 | 나이브 확률오차 | 로지스틱 확률오차 |
|---|---|---|---|---|
두 방법의 정확도가 소수점 둘째 자리까지 거의 같습니다. 상관 에서도 과 입니다.
상관이 커지면 둘 다 떨어지는데 이는 문제 자체가 어려워진 것입니다. 나이브 가정이 깨져서가 아닙니다. 가정을 안 하는 로지스틱도 똑같이 떨어집니다.
확률 오차는 다릅니다. 상관 에서 나이브가 이고 로지스틱이 입니다. 갈래를 고르는 데는 순서만 맞으면 되고, 확률은 순서보다 많은 것을 요구합니다.
() 같은 변수를 복사해 넣어 봅니다. 완전히 같은 변수를 여러 개 두면 나이브 가정이 최악으로 깨집니다.
| 같은 변수 복사 수 | 정확도 | 평균 사후확률 | 확률 제곱오차 |
|---|---|---|---|
복사해도 정확도는 에서 으로 사실상 그대로입니다. 점수가 몇 배가 되어도 부호가 안 바뀌기 때문입니다.
그런데 확신은 에서 까지 계속 커집니다. 같은 증거를 다섯 번 세었으니 다섯 배 확신하는 것입니다.
이것이 나이브 베이즈가 확률을 과신하는 이유입니다. 확률 제곱오차가 에서 로 나빠집니다.
이 문제에서 배우는 것. 나이브 가정은 점수의 부호를 지키고 크기를 망칩니다. 갈래만 고를 것이면 문제가 없고, 확률을 쓸 것이면 보정해야 합니다. 명백히 틀린 가정이 잘 작동하는 이유가 이것입니다.
확인 2-1. 나이브 가정이 추정해야 할 수를 얼마나 줄이는지 쓰세요.
답. 지수에서 선형으로 줄입니다.
확인 2-2. 검산에서 상관 일 때 두 방법의 정확도를 쓰세요.
답. 과 입니다.
확인 2-3. 검산에서 같은 변수를 개와 개 넣었을 때의 평균 사후확률을 쓰세요.
답. 과 입니다.
문제. 세는 자료에 적용합니다.
() 평활이 없으면 무슨 일이 나는지 보세요.
() 평활 상수가 무엇을 하는지 재세요.
() 표본이 적을 때 유리한지 확인하세요.
생각의 실마리. 낱말 세기에서 학습 자료에 안 나온 낱말이 반드시 생깁니다. 그 낱말의 확률을 으로 두면 **곱이 통째로 **이 됩니다.
풀이. () 낱말 가지 문서를 갈래 둘로 만듭니다. 문서마다 낱말 개이고, 두 갈래의 낱말 분포를 조금만 다르게 두어 쉽게 안 갈리게 합니다.
| 평활 상수 | 정확도 | 인 확률이 몇 개 | 로그우도가 무한인 문서 |
|---|---|---|---|
평활이 없으면 확률 이 개 생기고 문서 개가 전부 탈락합니다. 첫 줄의 정확도 은 성능이 나쁜 것이 아니라 판정을 아예 못 한 것입니다.
아주 작은 만 더해도 정확도가 이 됩니다. 을 더하는 것을 라플라스 평활이라 합니다.
강의 사전분포에서 나옵니다. 디리클레 사전분포의 모수가 이고, 사후 평균이 정확히 이 꼴입니다.
() 평활 상수가 무엇을 하는지 봅니다.
| 평활 상수 | 가장 흔한 낱말 확률 | 안 나온 낱말 확률 | 둘의 비 |
|---|---|---|---|
평활을 키우면 모든 확률이 고르게 다가갑니다. 가장 흔한 낱말과 안 나온 낱말의 비가 에서 로 줄어듭니다.
강의 사전분포 세기와 정확히 같은 손잡이입니다. 가 크면 자료보다 사전분포를 믿는 것이고, 그것이 곧 강의 와 같은 역할입니다.
() 표본이 적을 때 유리한지 확인합니다.
| 학습 문서 수 | 나이브 베이즈 | 로지스틱 회귀 | 어느 쪽이 나은가 |
|---|---|---|---|
| 나이브 | |||
| 나이브 | |||
| 나이브 | |||
| 나이브 |
표본 에서 나이브가 입니다. 계수 개짜리 문제인데 문서 개로 그만큼 나옵니다.
표본 에서도 나이브가 앞서고 차가 에서 로 오히려 벌어집니다. 로지스틱은 낱말 개의 계수를 벌점 없이 맞추므로 표본 이 모자랍니다.
변수가 많고 표본이 적은 자리가 생성 모형이 강한 자리입니다. 나이브 베이즈는 계수를 푸는 것이 아니라 세기만 하므로 표본이 적어도 무너지지 않습니다.
이 문제에서 배우는 것. 평활은 선택이 아니라 필수입니다. 그리고 그것은 임시방편이 아니라 사전분포를 넣는 정식 절차입니다. 강과 강과 이 강의가 같은 손잡이를 말하고 있습니다.
확인 3-1. 평활이 없으면 무슨 일이 나는지 쓰세요.
답. 안 본 낱말의 확률이 이 되어 곱이 통째로 이 됩니다.
확인 3-2. 검산에서 평활 과 일 때 흔한 낱말과 안 나온 낱말의 비를 쓰세요.
답. 과 입니다.
확인 3-3. 검산에서 문서 개일 때 두 방법의 정확도를 쓰세요.
답. 과 입니다.
문제. 두 갈래의 접근을 정리합니다.
() 차이를 정리하세요.
() 같은 꼴의 판정식을 쓴다는 것을 확인하세요.
() 가정이 맞을 때와 틀릴 때를 견주세요.
생각의 실마리. 나이브 베이즈는 전체를 모형화합니다. 로지스틱 회귀는 만 모형화합니다. 알고 싶은 것은 후자뿐인데 전자를 다 세우는 것이 낭비인지 아닌지가 문제입니다.
풀이. () 정리합니다.
| 무엇 | 생성 모형 | 판별 모형 |
|---|---|---|
| 무엇을 모형화 | 와 | 주어진 |
| 대표 | 나이브 베이즈 | 로지스틱 회귀 |
| 표본이 적을 때 | 유리 | 불리 |
| 가정이 틀리면 | 편향이 남음 | 덜 다침 |
| 새 자료 생성 | 가능 | 불가능 |
() 같은 꼴의 판정식을 쓴다는 것을 확인합니다. 가우스 나이브 베이즈에서 분산이 갈래마다 같으면 경계가 직선입니다.
| 무엇 | 나이브 베이즈 | 로지스틱 | 비 |
|---|---|---|---|
| 첫 계수 | |||
| 둘째 계수 | |||
| 절편 |
두 계수의 비가 와 로 거의 같습니다. 같은 방향의 직선을 긋습니다.
길이는 다릅니다. 나이브 베이즈는 분포 가정에서 크기를 정하고 로지스틱은 손실을 최소화해 크기를 정합니다. 강 문제 에서 손실과 사전분포의 대응을 본 것과 같은 자리입니다.
() 가정이 맞을 때와 틀릴 때를 견줍니다. 각 자료의 베이즈 최적 정확도를 함께 재서 공정하게 봅니다.
| 자료가 가정에 맞나 | 표본 | 표본 | 표본 | 베이즈 최적 |
|---|---|---|---|---|
| 맞음 (독립) | ||||
| 틀림 (거의 같은 변수) |
둘 다 표본 이면 자기 자료의 베이즈 최적에 거의 닿습니다. 대 이고 대 입니다.
가정이 틀린 쪽의 최적 자체가 낮습니다. 인데 이는 변수 둘이 거의 같은 말을 해서 실질 정보가 하나뿐이기 때문입니다. 나이브 베이즈의 잘못이 아닙니다.
정확도만 보면 나이브 가정이 깨져도 손해가 거의 없습니다. 손해는 문제 에서 본 대로 확률 추정에서 납니다.
이 문제에서 배우는 것. 생성 모형과 판별 모형은 같은 직선을 다른 방법으로 긋습니다. 표본이 적으면 가정이 도움이 되고 많으면 부담이 됩니다. 어느 쪽이 나은지는 표본 크기가 정합니다.
확인 4-1. 생성 모형과 판별 모형이 각각 무엇을 모형화하는지 쓰세요.
답. 와 와 주어진 입니다.
확인 4-2. 검산에서 두 방법의 첫 계수와 그 비를 쓰세요.
답. 과 이며 비가 입니다.
확인 4-3. 검산에서 가정이 틀린 자료의 베이즈 최적 정확도를 쓰세요.
답. 입니다.
문제. 실무의 요령을 정리합니다.
() 요령을 정리하세요.
() 로그로 안 바꾸면 무슨 일이 나는지 보세요.
() 확률 보정이 얼마나 필요한지 재세요.
생각의 실마리. 나이브 베이즈는 확률을 수백 개 곱합니다. 각각이 근처면 곱은 금방 부동소수점 바닥으로 내려갑니다.
풀이. () 정리합니다.
| 무엇 | 왜 | 어떻게 |
|---|---|---|
| 로그로 계산 | 곱이 으로 내려감 | 로그합으로 바꿈 |
| 평활 넣기 | 안 본 값이 | 라플라스 평활 |
| 확률을 못 믿음 | 독립 가정 탓 | 보정하거나 순위만 |
| 변수 중복 제거 | 같은 증거 중복 | 상관 큰 것 정리 |
| 연속 변수 | 분포를 정해야 함 | 구간화 또는 가우스 |
() 로그로 안 바꾸면 무슨 일이 나는지 봅니다. 낱말 하나의 확률을 로 두고 곱해 봅니다.
| 낱말 수 | 확률의 곱 | 이 되었나 | 로그합 |
|---|---|---|---|
| 아니오 | |||
| 아니오 | |||
| 예 | |||
| 예 |
낱말 개만 되어도 배정밀도 부동소수점에서 정확히 이 됩니다. 그러면 어느 갈래를 골라도 점수가 이라 판정이 불가능합니다.
로그합은 로 멀쩡합니다. 강의 수치 안정성이 여기서 실제 손해로 나타납니다.
() 확률 보정이 얼마나 필요한지 잽니다. 예측 확률을 구간으로 나눠 실제 비율과 견줍니다.
| 예측 확률 구간 | 문서 수 | 평균 예측 확률 | 실제 양성 비율 |
|---|---|---|---|
| 에서 | |||
| 에서 | |||
| 에서 | |||
| 에서 |
아래 두 구간에서는 실제 비율이 예측보다 높습니다. 이라 했는데 실제로는 입니다.
위 두 구간에서는 실제 비율이 예측보다 낮습니다. 이라 했는데 실제로는 입니다.
예측 확률이 양쪽 다 확신 쪽으로 밀려 있습니다. 문제 에서 본 과신이 그대로 나타나고, 강의 보정 곡선이 이것을 그림으로 보여 줍니다.
마지막으로 언제 쓰고 언제 안 쓰는지 정리합니다.
| 상황 | 나이브 베이즈를 쓰나 |
|---|---|
| 변수가 아주 많고 표본이 적음 | 예. 셀 것이 적음 |
| 글이나 세는 자료 | 예. 오래된 기본 후보 |
| 확률 값을 그대로 써야 함 | 아니오. 과신함 |
| 변수끼리 강하게 얽힘 | 아니오. 편향이 남음 |
| 빠른 기준선이 필요함 | 예. 학습이 한 번 훑기 |
이 문제에서 배우는 것. 나이브 베이즈의 실무 문제는 대부분 수치와 보정입니다. 로그로 바꾸고 평활을 넣으면 계산은 안전해지고, 확률은 순위로만 쓰거나 따로 보정해야 합니다.
확인 5-1. 로그로 계산하는 이유를 쓰세요.
답. 확률의 곱이 부동소수점 바닥으로 내려가 이 되기 때문입니다.
확인 5-2. 검산에서 낱말 개일 때 곱과 로그합을 쓰세요.
답. 이 되고 로그합은 입니다.
확인 5-3. 검산에서 예측 확률 에서 구간의 평균 예측과 실제 비율을 쓰세요.
답. 와 입니다.
| 유형 | 무엇을 묻나 | 어디를 보나 |
|---|---|---|
| 베이즈 분류기 | 우도 곱하기 사전확률 | 문제 |
| 최적 오류율 | 못 내려가는 바닥 | 문제 |
| 나이브 가정 | 지수에서 선형으로 | 문제 |
| 정확도 대 확률 | 부호만 지킴 | 문제 |
| 과신 | 같은 증거 중복 | 문제 |
| 라플라스 평활 | 사전분포에서 나옴 | 문제 |
| 표본이 적을 때 | 생성 모형이 유리 | 문제 |
| 같은 꼴의 직선 | 크기 정하는 법만 다름 | 문제 |
| 로그 계산 | 곱이 으로 내려감 | 문제 |
| 보정 | 확신 쪽으로 밀림 | 문제 |
핵심 식을 한자리에 모읍니다.
| 자료 종류 | 무엇을 가정하나 | 이름 |
|---|---|---|
| 세는 자료 | 다항분포 | 다항 나이브 베이즈 |
| 있고 없고 | 베르누이 | 베르누이 나이브 베이즈 |
| 연속 자료 | 정규분포 | 가우스 나이브 베이즈 |
| 섞임 | 변수마다 따로 | 혼합형 |
문제 6. 베이즈 분류기가 무엇을 최대로 하는지 쓰세요.
답. 우도 곱하기 사전확률입니다.
문제 7. 검산에서 베이즈 분류기의 오류율을 쓰세요.
답. 입니다.
문제 8. 검산에서 이진 변수 개면 몇 칸을 세야 하는지 쓰세요.
답. 칸입니다.
문제 9. 나이브 가정이 추정해야 할 수를 얼마나 줄이는지 쓰세요.
답. 지수에서 선형으로 줄입니다.
문제 10. 검산에서 상관 일 때 두 방법의 정확도를 쓰세요.
답. 과 입니다.
문제 11. 검산에서 같은 변수를 개와 개 넣었을 때의 평균 사후확률을 쓰세요.
답. 과 입니다.
문제 12. 검산에서 평활이 일 때 로그우도가 무한인 문서 수를 쓰세요.
답. 개 전부입니다.
문제 13. 검산에서 평활 과 일 때 흔한 낱말과 안 나온 낱말의 비를 쓰세요.
답. 과 입니다.
문제 14. 검산에서 문서 개일 때 두 방법의 정확도를 쓰세요.
답. 과 입니다.
문제 15. 검산에서 두 방법의 첫 계수와 그 비를 쓰세요.
답. 과 이며 비가 입니다.
문제 16. 검산에서 가정이 틀린 자료의 베이즈 최적 정확도를 쓰세요.
답. 입니다.
문제 17. 검산에서 낱말 개일 때 곱과 로그합을 쓰세요.
답. 이 되고 로그합은 입니다.
문제 18. 검산에서 예측 확률 에서 구간의 평균 예측과 실제 비율을 쓰세요.
답. 와 입니다.
심화 1. 가우스 나이브 베이즈가 언제 이차 경계를 갖는지 정리하세요.
로그 비를 전개하면 이렇습니다.
| 조건 | 경계 |
|---|---|
| \sigma_{1j}=\sigma_ | 직선 |
| \sigma_{1j}\neq\sigma_ | 이차곡선 |
| 공분산까지 같음 | 선형판별분석 |
| 공분산이 다름 | 이차판별분석 |
항의 계수가 입니다. 분산이 같으면 이 항이 사라져 직선이 되고, 그때가 문제 의 표입니다. 가정을 하나 더 풀면 경계가 한 차수 올라갑니다.
심화 2. 나이브 베이즈가 로지스틱보다 빨리 수렴하는 이유를 정리하세요.
| 무엇 | 나이브 베이즈 | 로지스틱 |
|---|---|---|
| 수렴 속도 | ||
| 점근 오차 | 편향이 남을 수 있음 | 편향 없음 |
| 교차점 | 표본 근처 |
나이브 베이즈는 변수마다 따로 세므로 표본이 변수 수의 로그만큼만 필요합니다. 로지스틱은 계수를 함께 풀므로 변수 수에 비례해 필요합니다. 문제 에서 낱말 개에 문서 개로도 이 나온 것이 이 성질입니다.
다만 점근에서는 로지스틱이 이깁니다. 편향이 없기 때문이고, 어느 쪽이 나은지는 자료 크기가 정합니다.
심화 3. 다항 나이브 베이즈와 베르누이 나이브 베이즈의 차이를 정리하세요.
| 무엇 | 다항 | 베르누이 |
|---|---|---|
| 무엇을 봄 | 낱말이 몇 번 나왔나 | 나왔나 안 나왔나 |
| 안 나온 낱말 | 무시 | 명시적으로 벌함 |
| 문서가 길 때 | 유리 | 불리 |
| 문서가 짧을 때 | 불리 | 유리 |
둘째 줄이 결정적입니다. 베르누이는 이므로 안 나온 낱말도 점수에 들어갑니다. 짧은 문서에서는 "무엇이 없는가"가 정보이므로 베르누이가 낫고, 긴 문서에서는 빈도가 정보이므로 다항이 낫습니다.
심화 4. 나이브 베이즈의 확률을 보정하는 방법을 정리하세요.
| 방법 | 무엇을 하나 | 필요한 것 |
|---|---|---|
| 플랫 보정 | 점수에 로지스틱을 다시 맞춤 | 검증 자료 |
| 등위 회귀 | 단조 함수를 맞춤 | 검증 자료 |
| 온도 조정 | 점수를 상수로 나눔 | 검증 자료 하나의 값 |
| 순위만 쓰기 | 확률을 안 씀 | 없음 |
셋째 줄이 가장 싸고 문제 의 원인에 직접 맞습니다. 같은 증거를 번 세었으면 점수가 배 부풀었으므로 로 나누면 됩니다. 실제로는 를 검증 자료로 고릅니다. 강에서 보정 곡선으로 이 값을 읽는 법을 봅니다.
심화 5. 나이브 베이즈가 최적이 되는 조건을 쓰세요.
그런데 이보다 훨씬 약한 조건으로도 충분합니다.
| 조건 | 결과 |
|---|---|
| 완전 독립 | 확률까지 정확 |
| 부호만 보존 | 갈래는 정확 |
| 상관이 갈래마다 같음 | 갈래는 정확 |
둘째 줄이 문제 의 표를 설명합니다. 상관 에서도 정확도가 안 떨어진 것은 상관이 두 갈래에서 같았기 때문입니다. 갈래마다 상관 구조가 다르면 그때는 정확도도 떨어집니다.
심화 6. 나이브 베이즈가 여전히 쓰이는 자리를 정리하세요.
| 자리 | 왜 |
|---|---|
| 스팸 걸러내기 | 낱말이 많고 빨라야 함 |
| 실시간 분류 | 학습이 한 번 훑기 |
| 기준선 | 다른 방법의 비교 대상 |
| 자료가 계속 들어옴 | 세기만 갱신하면 됨 |
넷째 줄이 온라인 학습입니다. 새 자료가 오면 횟수만 더하면 되므로 모형을 다시 안 맞춰도 됩니다. 로지스틱이나 신경망은 다시 학습해야 합니다. 셀 것만 세는 구조가 갱신을 공짜로 만듭니다.
정답.
| 기호 | 읽는 법 | 뜻 |
|---|---|---|
| 나이브 베이즈 | naive Bayes | 변수들이 조건부 독립이라 가정합니다 |
| 조건부 독립 | conditional independence | 갈래를 알면 서로 무관합니다 |
| 베이즈 분류기 | Bayes classifier | 참 확률을 아는 최적 분류기입니다 |
| 베이즈 오류율 | Bayes error rate | 어떤 방법도 못 내려가는 자리입니다 |
| 라플라스 평활 | Laplace smoothing | 모든 칸에 상수를 더합니다 |
| 생성 모형 | generative model | 자료 전체의 분포를 세웁니다 |
| 판별 모형 | discriminative model | 조건부 분포만 세웁니다 |
| 과신 | overconfidence | 확률을 실제보다 극단으로 냅니다 |
| 확률 보정 | calibration | 예측 확률을 실제 비율에 맞춥니다 |
| 로그합 | log-sum | 곱을 로그로 바꿔 더합니다 |
다음은 217강 의사결정나무입니다. 이 강의가 가정을 아주 세게 하는 쪽 끝을 봤습니다. 강의 이웃 방법과 이 강의를 양 끝으로 두면, 다음 세 강의는 그 사이에서 규칙을 쪼개며 답을 찾습니다.
import numpy as np
rng = np.random.default_rng(20261122)
def pw(s, n):
k = n - sum(2 if ord(c) > 0x2FFF else 1 for c in str(s))
return str(s) + " " * max(k, 0)
def rw(s, n):
k = n - sum(2 if ord(c) > 0x2FFF else 1 for c in str(s))
return " " * max(k, 0) + str(s)
# --- 문제 1: 베이즈 규칙에서 분류기를 꺼냅니다 --------------------------
print(" 215강은 가정을 거의 안 했습니다. 이번에는 세게 합니다")
print(" 121강의 베이즈 규칙에서 시작합니다")
print(" %s %s %s"
% (pw("무엇", 22), rw("기호", 26), rw("무엇을 뜻하나", 24)))
for a, b, c in [("사후확률", "p(y 주어진 x)", "답을 정하는 것"),
("우도", "p(x 주어진 y)", "갈래마다의 분포"),
("사전확률", "p(y)", "갈래의 비율"),
("증거", "p(x)", "갈래와 무관한 몫")]:
print(" %s %s %s" % (pw(a, 22), rw(b, 26), rw(c, 24)))
print(" 분모는 갈래에 안 딸리므로 견줄 때는 빼도 됩니다")
print(" 그러면 우도 곱하기 사전확률이 가장 큰 갈래를 고르면 됩니다")
print(" 최적 분류기가 무엇인지 확인합니다")
print(" 참 확률을 다 안다고 하고 오류율을 잽니다")
n1 = 20000
X1 = rng.normal(0, 1, (n1, 2))
sc1 = 1.5 * X1[:, 0] - X1[:, 1] + 0.5
p1 = 1.0 / (1.0 + np.exp(-sc1))
y1 = (rng.uniform(0, 1, n1) < p1).astype(float)
print(" %s %s %s"
% (pw("판정 방법", 26), rw("오류율", 14), rw("최적과의 차", 18)))
bayes = float(np.mean((p1 > 0.5) != y1))
for nm, pred in [("참 확률이 0.5 넘으면 양성", (p1 > 0.5).astype(float)),
("참 확률이 0.3 넘으면 양성", (p1 > 0.3).astype(float)),
("언제나 양성", np.ones(n1)),
("동전 던지기", (rng.uniform(0, 1, n1) < 0.5).astype(float))]:
e = float(np.mean(pred != y1))
print(" %s %14.6f %18.6f" % (pw(nm, 26), e, e - bayes))
print(" 참 확률로 0.5 문턱을 쓰는 것이 베이즈 분류기입니다")
print(" 그 오류율보다 낮게 갈 수 있는 방법은 없습니다")
print(" 210강 문제 1 의 잡음처럼 줄일 수 없는 바닥입니다")
print(" 갈래마다 분포를 세워 보면 무엇이 어려운지 봅니다")
print(" %s %s %s"
% (pw("변수 개수", 14), rw("이진 변수면 세야 할 칸 수", 30),
rw("칸마다 10 개면 필요한 표본", 30)))
for d in [1, 5, 10, 20, 30]:
print(" %s %30.0f %30.0f"
% (pw(str(d), 14), 2.0 ** d, 10 * 2.0 ** d))
print(" 변수 30 개면 10 억 칸이 넘습니다. 213강 문제 2 와 같은 셈입니다")
print(" 우도를 통째로 추정하는 것은 사실상 불가능합니다")
print(" 그래서 우도에 강한 가정을 넣습니다")
# --- 문제 2: 순진한 가정 -----------------------------------------------
print(" 변수들이 갈래를 알면 서로 독립이라고 가정합니다")
print(" %s %s %s"
% (pw("무엇", 24), rw("추정해야 할 수", 22), rw("변수 30 개면", 20)))
for a, b, c in [("통째로", "2 의 d 제곱 빼기 1", "10 억 개 넘음"),
("순진한 가정", "d 곱하기 갈래 수", "60 개"),
("줄어드는 비율", "지수에서 선형으로", "천만 분의 1")]:
print(" %s %s %s" % (pw(a, 24), rw(b, 22), rw(c, 20)))
print(" 이 가정이 참인 경우는 거의 없습니다. 그래서 순진하다고 부릅니다")
print(" 가정이 틀렸는데도 왜 잘 되는지 봅니다")
def nb_gauss_fit(X, y):
ps, ms, vs = [], [], []
for c in [0.0, 1.0]:
Z = X[y == c]
ps.append(len(Z) / len(y))
ms.append(Z.mean(axis=0))
vs.append(Z.var(axis=0) + 1e-9)
return np.array(ps), np.array(ms), np.array(vs)
def nb_gauss_score(X, ps, ms, vs):
out = []
for c in range(2):
lg = (-0.5 * np.log(2 * np.pi * vs[c])
- (X - ms[c]) ** 2 / (2 * vs[c])).sum(axis=1)
out.append(lg + np.log(ps[c]))
return np.stack(out, axis=1)
def logit_fit(X, y, steps=4000, lr=0.3):
A = np.hstack([X, np.ones((len(X), 1))])
w = np.zeros(A.shape[1])
for _ in range(steps):
p = 1.0 / (1.0 + np.exp(-A @ w))
w -= lr * (A.T @ (p - y)) / len(y)
return w
def logit_pred(w, X):
return ((np.hstack([X, np.ones((len(X), 1))]) @ w) > 0).astype(float)
print(" 변수끼리 얼마나 상관되었는지 바꿔 가며 잽니다")
print(" %s %s %s %s %s"
% (pw("갈래 안 상관", 14), rw("나이브 정확도", 18),
rw("로지스틱 정확도", 20), rw("나이브 확률오차", 20),
rw("로지스틱 확률오차", 22)))
for r in [0.0, 0.5, 0.9, 0.99]:
C = np.array([[1.0, r], [r, 1.0]])
L = np.linalg.cholesky(C)
m = 3000
yy = (rng.uniform(0, 1, m) < 0.5).astype(float)
mu = np.stack([np.where(yy > 0.5, 1.0, -1.0),
np.where(yy > 0.5, 1.0, -1.0)], axis=1)
Xa = mu + rng.normal(0, 1, (m, 2)) @ L.T
yt = (rng.uniform(0, 1, 3000) < 0.5).astype(float)
mut = np.stack([np.where(yt > 0.5, 1.0, -1.0),
np.where(yt > 0.5, 1.0, -1.0)], axis=1)
Xb = mut + rng.normal(0, 1, (3000, 2)) @ L.T
ps, ms, vs = nb_gauss_fit(Xa, yy)
sc = nb_gauss_score(Xb, ps, ms, vs)
an = float(np.mean(np.argmax(sc, axis=1) == yt))
ph = 1.0 / (1.0 + np.exp(-(sc[:, 1] - sc[:, 0])))
br = float(np.mean((ph - yt) ** 2))
wl = logit_fit(Xa, yy)
Ab = np.hstack([Xb, np.ones((len(Xb), 1))])
pl = 1.0 / (1.0 + np.exp(-(Ab @ wl)))
al = float(np.mean((pl > 0.5).astype(float) == yt))
bl = float(np.mean((pl - yt) ** 2))
print(" %s %18.6f %20.6f %20.6f %22.6f"
% (pw("%.2f" % r, 14), an, al, br, bl))
print(" 두 방법의 정확도가 소수점 둘째 자리까지 거의 같습니다")
print(" 상관이 커지면 둘 다 떨어지는데 이는 문제 자체가 어려워진 것입니다")
print(" 나이브 가정이 깨져도 갈래를 고르는 데는 손해가 거의 없습니다")
print(" 확률 오차는 다릅니다. 상관 0.99 에서 나이브가 로지스틱보다 나쁩니다")
print(" 갈래를 고르는 데는 순서만 맞으면 되고 확률은 순서보다 많은 것을 요구합니다")
print(" 왜 순서만 맞으면 되는지 수치로 봅니다")
print(" 같은 변수를 세 번 복사해 넣어 봅니다")
m2 = 2000
yy2 = (rng.uniform(0, 1, m2) < 0.5).astype(float)
base = np.where(yy2 > 0.5, 1.0, -1.0) + rng.normal(0, 1, m2)
yt2 = (rng.uniform(0, 1, 3000) < 0.5).astype(float)
baset = np.where(yt2 > 0.5, 1.0, -1.0) + rng.normal(0, 1, 3000)
print(" %s %s %s %s"
% (pw("같은 변수 복사 수", 20), rw("정확도", 14), rw("평균 사후확률", 20),
rw("확률 제곱오차", 18)))
for c in [1, 2, 3, 5]:
Xa = np.stack([base] * c, axis=1)
Xb = np.stack([baset] * c, axis=1)
ps, ms, vs = nb_gauss_fit(Xa, yy2)
sc = nb_gauss_score(Xb, ps, ms, vs)
ph = 1.0 / (1.0 + np.exp(-(sc[:, 1] - sc[:, 0])))
print(" %s %14.6f %20.6f %18.6f"
% (pw(str(c), 20), float(np.mean(np.argmax(sc, axis=1) == yt2)),
float(np.mean(np.maximum(ph, 1 - ph))),
float(np.mean((ph - yt2) ** 2))))
print(" 복사해도 정확도는 그대로입니다. 부호가 안 바뀌기 때문입니다")
print(" 그런데 확신은 계속 커집니다. 같은 증거를 여러 번 센 탓입니다")
print(" 이것이 나이브 베이즈가 확률을 과신하는 이유입니다")
# --- 문제 3: 이산 자료와 평활 ------------------------------------------
print(" 글처럼 세는 자료에서 나이브 베이즈를 세웁니다")
V = 300
n3, n3t = 400, 2000
w0 = rng.dirichlet(np.ones(V) * 1.0)
w1 = w0 * np.exp(rng.normal(0, 0.5, V))
w1 = w1 / w1.sum()
def gen_docs(m, L=25):
y = (rng.uniform(0, 1, m) < 0.5).astype(int)
D = np.zeros((m, V))
for i in range(m):
w = w1 if y[i] == 1 else w0
idx = rng.choice(V, L, p=w)
for j in idx:
D[i, j] += 1
return D, y.astype(float)
D3, y3 = gen_docs(n3)
D3t, y3t = gen_docs(n3t)
print(" 낱말 300 가지 문서를 갈래 둘로 만듭니다. 문서마다 낱말 25 개입니다")
print(" 두 갈래의 낱말 분포를 조금만 다르게 두어 쉽게 안 갈리게 합니다")
print(" %s %s %s %s"
% (pw("평활 상수", 12), rw("정확도", 14), rw("0 인 확률이 몇 개", 22),
rw("로그우도가 무한인 문서", 24)))
for al in [0.0, 0.01, 0.1, 1.0, 10.0]:
cnt = np.stack([D3[y3 == c].sum(axis=0) for c in [0, 1]])
prob = (cnt + al) / (cnt.sum(axis=1, keepdims=True) + al * V)
zero = int(np.sum(prob == 0))
with np.errstate(divide='ignore', invalid='ignore'):
lp = np.log(prob)
sc = D3t @ lp.T
bad = int(np.sum(~np.isfinite(sc).all(axis=1)))
ok = np.isfinite(sc).all(axis=1)
ac = float(np.mean(np.argmax(sc[ok], axis=1) == y3t[ok])) if ok.any() else 0.0
print(" %s %14.6f %22d %24d"
% (pw("%.2f" % al, 12), ac, zero, bad))
print(" 평활이 없으면 학습에서 안 나온 낱말이 확률 0 이 됩니다")
print(" 로그를 취하면 마이너스 무한이 되어 문서 전체가 탈락합니다")
print(" 첫 줄의 정확도 0 은 문서 2000 개가 전부 탈락해 판정을 못 한 것입니다")
print(" 1 을 더하는 것을 라플라스 평활이라 하고 148강의 사전분포에서 나옵니다")
print(" 평활 상수가 무엇을 하는지 봅니다")
print(" %s %s %s %s"
% (pw("평활 상수", 12), rw("가장 흔한 낱말 확률", 24),
rw("안 나온 낱말 확률", 22), rw("둘의 비", 16)))
cnt0 = np.stack([D3[y3 == c].sum(axis=0) for c in [0, 1]])
for al in [0.01, 0.1, 1.0, 10.0, 100.0]:
prob = (cnt0 + al) / (cnt0.sum(axis=1, keepdims=True) + al * V)
top = float(prob[0].max())
unseen = float(prob[0][cnt0[0] == 0].max()) if (cnt0[0] == 0).any() else 0.0
print(" %s %24.8f %22.8f %16.6f"
% (pw("%.2f" % al, 12), top, unseen, top / unseen))
print(" 평활을 키우면 모든 확률이 고르게 다가갑니다")
print(" 가장 흔한 낱말과 안 나온 낱말의 비가 줄어듭니다")
print(" 148강의 사전분포 세기와 정확히 같은 손잡이입니다")
print(" 표본이 적을 때 나이브 베이즈가 유리한지 봅니다")
print(" %s %s %s %s"
% (pw("학습 문서 수", 14), rw("나이브 베이즈", 18),
rw("로지스틱 회귀", 18), rw("어느 쪽이 나은가", 22)))
for m in [20, 50, 200, 1000]:
Da, ya = gen_docs(m)
cnt = np.stack([Da[ya == c].sum(axis=0) for c in [0, 1]])
prob = (cnt + 1.0) / (cnt.sum(axis=1, keepdims=True) + V)
pri = np.array([np.mean(ya == 0), np.mean(ya == 1)])
sc = D3t @ np.log(prob).T + np.log(pri + 1e-12)
an = float(np.mean(np.argmax(sc, axis=1) == y3t))
al = float(np.mean(logit_pred(logit_fit(Da, ya, steps=8000, lr=0.1),
D3t) == y3t))
print(" %s %18.6f %18.6f %s"
% (pw(str(m), 14), an, al,
rw("나이브" if an > al + 1e-9 else
("로지스틱" if al > an + 1e-9 else "같음"), 22)))
print(" 표본이 적을 때 나이브 베이즈가 앞섭니다. 셀 것이 적기 때문입니다")
print(" 표본 1000 에서도 나이브가 앞섭니다. 차가 0.024 에서 0.042 로 오히려 벌어집니다")
print(" 로지스틱은 낱말 300 개의 계수를 벌점 없이 맞추므로 표본 1000 이 모자랍니다")
print(" 변수가 많고 표본이 적은 자리가 생성 모형이 강한 자리입니다")
print(" 214강의 복잡도가 낮으면 편향은 크고 분산은 작다는 것입니다")
# --- 문제 4: 생성 모형과 판별 모형 -------------------------------------
print(" 나이브 베이즈와 로지스틱 회귀의 관계를 정리합니다")
print(" %s %s %s"
% (pw("무엇", 22), rw("생성 모형", 24), rw("판별 모형", 24)))
for a, b, c in [("무엇을 모형화", "p(x 와 y)", "p(y 주어진 x)"),
("대표", "나이브 베이즈", "로지스틱 회귀"),
("표본이 적을 때", "유리", "불리"),
("가정이 틀리면", "편향이 남음", "덜 다침"),
("새 자료 생성", "가능", "불가능")]:
print(" %s %s %s" % (pw(a, 22), rw(b, 24), rw(c, 24)))
print(" 둘이 같은 꼴의 판정식을 씁니다. 계수를 정하는 방식만 다릅니다")
print(" 같은 꼴이라는 것을 수치로 확인합니다")
print(" 가우스 나이브 베이즈에서 분산이 갈래마다 같으면 경계가 직선입니다")
m4 = 4000
y4 = (rng.uniform(0, 1, m4) < 0.5).astype(float)
X4 = np.stack([np.where(y4 > 0.5, 1.2, -1.2) + rng.normal(0, 1, m4),
np.where(y4 > 0.5, 0.6, -0.6) + rng.normal(0, 1, m4)], axis=1)
ps4, ms4, vs4 = nb_gauss_fit(X4, y4)
vsh = np.stack([X4.var(axis=0) * 0 + ((X4[y4 == 0] - ms4[0]) ** 2).sum(axis=0)
+ ((X4[y4 == 1] - ms4[1]) ** 2).sum(axis=0)] * 2) / m4
wnb = (ms4[1] - ms4[0]) / vsh[0]
bnb = (-0.5 * ((ms4[1] ** 2 - ms4[0] ** 2) / vsh[0]).sum()
+ np.log(ps4[1] / ps4[0]))
wlr = logit_fit(X4, y4)
print(" %s %s %s %s"
% (pw("무엇", 22), rw("나이브 베이즈", 18), rw("로지스틱", 18),
rw("비", 12)))
for i, nm in enumerate(["첫 계수", "둘째 계수"]):
print(" %s %18.6f %18.6f %12.6f"
% (pw(nm, 22), wnb[i], wlr[i], wnb[i] / wlr[i]))
print(" %s %18.6f %18.6f %12.6f"
% (pw("절편", 22), bnb, wlr[2], bnb / (wlr[2] if abs(wlr[2]) > 1e-9 else 1)))
print(" 두 계수의 비가 거의 같습니다. 같은 방향의 직선을 긋습니다")
print(" 길이는 다릅니다. 나이브 베이즈는 분포 가정에서 크기를 정합니다")
print(" 206강 문제 4 에서 손실과 사전분포의 대응을 본 것과 같은 자리입니다")
print(" 가정이 맞을 때와 틀릴 때를 견줍니다")
print(" 각 자료의 베이즈 최적 정확도를 함께 재서 공정하게 견줍니다")
print(" %s %s %s %s %s"
% (pw("자료가 가정에 맞나", 22), rw("표본 30", 12), rw("표본 300", 12),
rw("표본 3000", 12), rw("베이즈 최적", 14)))
def bayes_opt(kind):
mt = 40000
yb = (rng.uniform(0, 1, mt) < 0.5).astype(float)
if kind == "fit":
Xb = np.stack([np.where(yb > 0.5, 0.6, -0.6)
+ rng.normal(0, 1, mt) for _ in range(2)], axis=1)
g = Xb.sum(axis=1)
else:
ub = rng.normal(0, 1, mt)
Xb = np.stack([np.where(yb > 0.5, 0.6, -0.6) + ub,
np.where(yb > 0.5, 0.6, -0.6) + ub
+ rng.normal(0, 0.2, mt)], axis=1)
g = Xb.sum(axis=1)
return float(np.mean((g > 0).astype(float) == yb))
def bench(kind):
out = []
for m in [30, 300, 3000]:
ya = (rng.uniform(0, 1, m) < 0.5).astype(float)
if kind == "fit":
Xa = np.stack([np.where(ya > 0.5, 0.6, -0.6)
+ rng.normal(0, 1, m) for _ in range(2)], axis=1)
else:
u = rng.normal(0, 1, m)
Xa = np.stack([np.where(ya > 0.5, 0.6, -0.6) + u,
np.where(ya > 0.5, 0.6, -0.6) + u
+ rng.normal(0, 0.2, m)], axis=1)
mt = 3000
yb = (rng.uniform(0, 1, mt) < 0.5).astype(float)
if kind == "fit":
Xb = np.stack([np.where(yb > 0.5, 0.6, -0.6)
+ rng.normal(0, 1, mt) for _ in range(2)], axis=1)
else:
ub = rng.normal(0, 1, mt)
Xb = np.stack([np.where(yb > 0.5, 0.6, -0.6) + ub,
np.where(yb > 0.5, 0.6, -0.6) + ub
+ rng.normal(0, 0.2, mt)], axis=1)
ps, ms, vs = nb_gauss_fit(Xa, ya)
an = float(np.mean(np.argmax(nb_gauss_score(Xb, ps, ms, vs),
axis=1) == yb))
out.append(an)
return out
for nm, kind in [("맞음 (독립)", "fit"), ("틀림 (거의 같은 변수)", "bad")]:
v = bench(kind)
print(" %s %12.6f %12.6f %12.6f %14.6f"
% (pw(nm, 22), v[0], v[1], v[2], bayes_opt(kind)))
print(" 둘 다 표본 300 이면 자기 자료의 베이즈 최적에 거의 닿습니다")
print(" 가정이 틀린 쪽의 최적 자체가 낮습니다. 변수 둘이 같은 말을 하기 때문입니다")
print(" 정확도만 보면 나이브 가정이 깨져도 손해가 거의 없습니다")
print(" 손해는 문제 2 에서 본 대로 확률 추정에서 납니다")
# --- 문제 5: 실무에서 쓰기 ---------------------------------------------
print(" 실무에서 나이브 베이즈를 쓸 때의 요령을 정리합니다")
print(" %s %s %s"
% (pw("무엇", 24), rw("왜", 24), rw("어떻게", 24)))
for a, b, c in [("로그로 계산", "곱이 0 으로 내려감", "로그합으로 바꿈"),
("평활 넣기", "안 본 값이 0", "라플라스 평활"),
("확률을 못 믿음", "독립 가정 탓", "보정하거나 순위만"),
("변수 중복 제거", "같은 증거 중복", "상관 큰 것 정리"),
("연속 변수", "분포를 정해야 함", "구간화 또는 가우스")]:
print(" %s %s %s" % (pw(a, 24), rw(b, 24), rw(c, 24)))
print(" 로그로 안 바꾸면 무슨 일이 나는지 봅니다")
print(" %s %s %s %s"
% (pw("낱말 수", 12), rw("확률의 곱", 20), rw("0 이 되었나", 16),
rw("로그합", 18)))
pv = 0.005
for L in [10, 50, 150, 400]:
prod = pv ** L
print(" %s %20.6e %s %18.6f"
% (pw(str(L), 12), prod,
rw("예" if prod == 0.0 else "아니오", 16), L * np.log(pv)))
print(" 낱말 150 개만 되어도 배정밀도 부동소수점에서 0 이 됩니다")
print(" 로그합은 마이너스 795 로 멀쩡합니다. 92강의 수치 안정성입니다")
print(" 확률 보정이 얼마나 필요한지 잽니다")
print(" %s %s %s %s"
% (pw("예측 확률 구간", 20), rw("문서 수", 12), rw("평균 예측 확률", 20),
rw("실제 양성 비율", 20)))
cntf = np.stack([D3[y3 == c].sum(axis=0) for c in [0, 1]])
probf = (cntf + 1.0) / (cntf.sum(axis=1, keepdims=True) + V)
scf = D3t @ np.log(probf).T
phf = 1.0 / (1.0 + np.exp(-(scf[:, 1] - scf[:, 0])))
for lo, hi in [(0.0, 0.01), (0.01, 0.5), (0.5, 0.99), (0.99, 1.01)]:
sel = (phf >= lo) & (phf < hi)
if sel.sum() == 0:
continue
print(" %s %12d %20.6f %20.6f"
% (pw("%.2f 에서 %.2f" % (lo, hi), 20), int(sel.sum()),
float(phf[sel].mean()), float(y3t[sel].mean())))
print(" 아래 두 구간에서는 실제 비율이 예측보다 높습니다")
print(" 위 두 구간에서는 실제 비율이 예측보다 낮습니다")
print(" 예측 확률이 양쪽 다 확신 쪽으로 밀려 있습니다. 문제 2 의 과신입니다")
print(" 226강의 보정 곡선이 이것을 그림으로 보여 줍니다")
print(" 마지막으로 언제 쓰고 언제 안 쓰는지 정리합니다")
print(" %s %s"
% (pw("상황", 28), rw("나이브 베이즈를 쓰나", 30)))
for a, b in [("변수가 아주 많고 표본이 적음", "예. 셀 것이 적음"),
("글이나 세는 자료", "예. 오래된 기본 후보"),
("확률 값을 그대로 써야 함", "아니오. 과신함"),
("변수끼리 강하게 얽힘", "아니오. 편향이 남음"),
("빠른 기준선이 필요함", "예. 학습이 한 번 훑기")]:
print(" %s %s" % (pw(a, 28), rw(b, 30)))
print(" 216강은 가정을 세게 하는 쪽을 봤습니다. 217강은 가정 없이 규칙을 나눕니다")
# 215강은 가정을 거의 안 했습니다. 이번에는 세게 합니다
# 121강의 베이즈 규칙에서 시작합니다
# 무엇 기호 무엇을 뜻하나
# 사후확률 p(y 주어진 x) 답을 정하는 것
# 우도 p(x 주어진 y) 갈래마다의 분포
# 사전확률 p(y) 갈래의 비율
# 증거 p(x) 갈래와 무관한 몫
# 분모는 갈래에 안 딸리므로 견줄 때는 빼도 됩니다
# 그러면 우도 곱하기 사전확률이 가장 큰 갈래를 고르면 됩니다
# 최적 분류기가 무엇인지 확인합니다
# 참 확률을 다 안다고 하고 오류율을 잽니다
# 판정 방법 오류율 최적과의 차
# 참 확률이 0.5 넘으면 양성 0.230650 0.000000
# 참 확률이 0.3 넘으면 양성 0.261450 0.030800
# 언제나 양성 0.420250 0.189600
# 동전 던지기 0.502150 0.271500
# 참 확률로 0.5 문턱을 쓰는 것이 베이즈 분류기입니다
# 그 오류율보다 낮게 갈 수 있는 방법은 없습니다
# 210강 문제 1 의 잡음처럼 줄일 수 없는 바닥입니다
# 갈래마다 분포를 세워 보면 무엇이 어려운지 봅니다
# 변수 개수 이진 변수면 세야 할 칸 수 칸마다 10 개면 필요한 표본
# 1 2 20
# 5 32 320
# 10 1024 10240
# 20 1048576 10485760
# 30 1073741824 10737418240
# 변수 30 개면 10 억 칸이 넘습니다. 213강 문제 2 와 같은 셈입니다
# 우도를 통째로 추정하는 것은 사실상 불가능합니다
# 그래서 우도에 강한 가정을 넣습니다
# 변수들이 갈래를 알면 서로 독립이라고 가정합니다
# 무엇 추정해야 할 수 변수 30 개면
# 통째로 2 의 d 제곱 빼기 1 10 억 개 넘음
# 순진한 가정 d 곱하기 갈래 수 60 개
# 줄어드는 비율 지수에서 선형으로 천만 분의 1
# 이 가정이 참인 경우는 거의 없습니다. 그래서 순진하다고 부릅니다
# 가정이 틀렸는데도 왜 잘 되는지 봅니다
# 변수끼리 얼마나 상관되었는지 바꿔 가며 잽니다
# 갈래 안 상관 나이브 정확도 로지스틱 정확도 나이브 확률오차 로지스틱 확률오차
# 0.00 0.921333 0.923667 0.057438 0.057509
# 0.50 0.876333 0.876333 0.092318 0.089694
# 0.90 0.852667 0.851000 0.115519 0.108194
# 0.99 0.830667 0.831333 0.123139 0.114632
# 두 방법의 정확도가 소수점 둘째 자리까지 거의 같습니다
# 상관이 커지면 둘 다 떨어지는데 이는 문제 자체가 어려워진 것입니다
# 나이브 가정이 깨져도 갈래를 고르는 데는 손해가 거의 없습니다
# 확률 오차는 다릅니다. 상관 0.99 에서 나이브가 로지스틱보다 나쁩니다
# 갈래를 고르는 데는 순서만 맞으면 되고 확률은 순서보다 많은 것을 요구합니다
# 왜 순서만 맞으면 되는지 수치로 봅니다
# 같은 변수를 세 번 복사해 넣어 봅니다
# 같은 변수 복사 수 정확도 평균 사후확률 확률 제곱오차
# 1 0.832667 0.835603 0.115828
# 2 0.832667 0.912751 0.124906
# 3 0.832333 0.941621 0.133771
# 5 0.832333 0.965208 0.144159
# 복사해도 정확도는 그대로입니다. 부호가 안 바뀌기 때문입니다
# 그런데 확신은 계속 커집니다. 같은 증거를 여러 번 센 탓입니다
# 이것이 나이브 베이즈가 확률을 과신하는 이유입니다
# 글처럼 세는 자료에서 나이브 베이즈를 세웁니다
# 낱말 300 가지 문서를 갈래 둘로 만듭니다. 문서마다 낱말 25 개입니다
# 두 갈래의 낱말 분포를 조금만 다르게 두어 쉽게 안 갈리게 합니다
# 평활 상수 정확도 0 인 확률이 몇 개 로그우도가 무한인 문서
# 0.00 0.000000 44 2000
# 0.01 0.833500 0 0
# 0.10 0.844500 0 0
# 1.00 0.857000 0 0
# 10.00 0.851000 0 0
# 평활이 없으면 학습에서 안 나온 낱말이 확률 0 이 됩니다
# 로그를 취하면 마이너스 무한이 되어 문서 전체가 탈락합니다
# 첫 줄의 정확도 0 은 문서 2000 개가 전부 탈락해 판정을 못 한 것입니다
# 1 을 더하는 것을 라플라스 평활이라 하고 148강의 사전분포에서 나옵니다
# 평활 상수가 무엇을 하는지 봅니다
# 평활 상수 가장 흔한 낱말 확률 안 나온 낱말 확률 둘의 비
# 0.01 0.02348341 0.00000194 12101.000000
# 0.10 0.02337838 0.00001931 1211.000000
# 1.00 0.02238532 0.00018349 122.000000
# 10.00 0.01607362 0.00122699 13.100000
# 100.00 0.00628734 0.00284495 2.210000
# 평활을 키우면 모든 확률이 고르게 다가갑니다
# 가장 흔한 낱말과 안 나온 낱말의 비가 줄어듭니다
# 148강의 사전분포 세기와 정확히 같은 손잡이입니다
# 표본이 적을 때 나이브 베이즈가 유리한지 봅니다
# 학습 문서 수 나이브 베이즈 로지스틱 회귀 어느 쪽이 나은가
# 20 0.657000 0.633500 나이브
# 50 0.666500 0.634500 나이브
# 200 0.790500 0.766500 나이브
# 1000 0.863000 0.821000 나이브
# 표본이 적을 때 나이브 베이즈가 앞섭니다. 셀 것이 적기 때문입니다
# 표본 1000 에서도 나이브가 앞섭니다. 차가 0.024 에서 0.042 로 오히려 벌어집니다
# 로지스틱은 낱말 300 개의 계수를 벌점 없이 맞추므로 표본 1000 이 모자랍니다
# 변수가 많고 표본이 적은 자리가 생성 모형이 강한 자리입니다
# 214강의 복잡도가 낮으면 편향은 크고 분산은 작다는 것입니다
# 나이브 베이즈와 로지스틱 회귀의 관계를 정리합니다
# 무엇 생성 모형 판별 모형
# 무엇을 모형화 p(x 와 y) p(y 주어진 x)
# 대표 나이브 베이즈 로지스틱 회귀
# 표본이 적을 때 유리 불리
# 가정이 틀리면 편향이 남음 덜 다침
# 새 자료 생성 가능 불가능
# 둘이 같은 꼴의 판정식을 씁니다. 계수를 정하는 방식만 다릅니다
# 같은 꼴이라는 것을 수치로 확인합니다
# 가우스 나이브 베이즈에서 분산이 갈래마다 같으면 경계가 직선입니다
# 무엇 나이브 베이즈 로지스틱 비
# 첫 계수 2.428033 2.378268 1.020925
# 둘째 계수 1.193607 1.132334 1.054113
# 절편 0.108100 0.155887 0.693449
# 두 계수의 비가 거의 같습니다. 같은 방향의 직선을 긋습니다
# 길이는 다릅니다. 나이브 베이즈는 분포 가정에서 크기를 정합니다
# 206강 문제 4 에서 손실과 사전분포의 대응을 본 것과 같은 자리입니다
# 가정이 맞을 때와 틀릴 때를 견줍니다
# 각 자료의 베이즈 최적 정확도를 함께 재서 공정하게 견줍니다
# 자료가 가정에 맞나 표본 30 표본 300 표본 3000 베이즈 최적
# 맞음 (독립) 0.699667 0.805000 0.797333 0.799925
# 틀림 (거의 같은 변수) 0.700667 0.729667 0.727667 0.722250
# 둘 다 표본 300 이면 자기 자료의 베이즈 최적에 거의 닿습니다
# 가정이 틀린 쪽의 최적 자체가 낮습니다. 변수 둘이 같은 말을 하기 때문입니다
# 정확도만 보면 나이브 가정이 깨져도 손해가 거의 없습니다
# 손해는 문제 2 에서 본 대로 확률 추정에서 납니다
# 실무에서 나이브 베이즈를 쓸 때의 요령을 정리합니다
# 무엇 왜 어떻게
# 로그로 계산 곱이 0 으로 내려감 로그합으로 바꿈
# 평활 넣기 안 본 값이 0 라플라스 평활
# 확률을 못 믿음 독립 가정 탓 보정하거나 순위만
# 변수 중복 제거 같은 증거 중복 상관 큰 것 정리
# 연속 변수 분포를 정해야 함 구간화 또는 가우스
# 로그로 안 바꾸면 무슨 일이 나는지 봅니다
# 낱말 수 확률의 곱 0 이 되었나 로그합
# 10 9.765625e-24 아니오 -52.983174
# 50 8.881784e-116 아니오 -264.915868
# 150 0.000000e+00 예 -794.747605
# 400 0.000000e+00 예 -2119.326947
# 낱말 150 개만 되어도 배정밀도 부동소수점에서 0 이 됩니다
# 로그합은 마이너스 795 로 멀쩡합니다. 92강의 수치 안정성입니다
# 확률 보정이 얼마나 필요한지 잽니다
# 예측 확률 구간 문서 수 평균 예측 확률 실제 양성 비율
# 0.00 에서 0.01 292 0.003343 0.017123
# 0.01 에서 0.50 693 0.151909 0.215007
# 0.50 에서 0.99 744 0.855788 0.827957
# 0.99 에서 1.01 271 0.996351 0.985240
# 아래 두 구간에서는 실제 비율이 예측보다 높습니다
# 위 두 구간에서는 실제 비율이 예측보다 낮습니다
# 예측 확률이 양쪽 다 확신 쪽으로 밀려 있습니다. 문제 2 의 과신입니다
# 226강의 보정 곡선이 이것을 그림으로 보여 줍니다
# 마지막으로 언제 쓰고 언제 안 쓰는지 정리합니다
# 상황 나이브 베이즈를 쓰나
# 변수가 아주 많고 표본이 적음 예. 셀 것이 적음
# 글이나 세는 자료 예. 오래된 기본 후보
# 확률 값을 그대로 써야 함 아니오. 과신함
# 변수끼리 강하게 얽힘 아니오. 편향이 남음
# 빠른 기준선이 필요함 예. 학습이 한 번 훑기
# 216강은 가정을 세게 하는 쪽을 봤습니다. 217강은 가정 없이 규칙을 나눕니다