강은 치우친 자료를 어떻게 재는지 봤습니다. 이 강의는 어떻게 다룰지를 봅니다.
흔히 "불균형 문제"라 부르고 재표집부터 합니다. 그런데 비율 자체는 정보입니다. 양성이 퍼센트라는 사실은 버릴 것이 아니라 알아야 할 것입니다.
이 강의는 재표집과 가중과 문턱 셋이 사실상 같은 일을 한다는 것을 수치로 보이고, 정말 도움이 되는 것이 무엇인지를 가립니다.
문제. 문제를 정확히 짚습니다.
() 무엇이 정말 문제인지 정리하세요.
() 잘 갈리는 경우와 겹친 경우를 견주세요.
() 치우침이 무엇을 망가뜨리는지 재세요.
생각의 실마리. "양성이 퍼센트"라는 말에는 두 가지가 섞여 있습니다. 비율이 낮다는 것과 개수가 적다는 것입니다. 표본이 백만 개면 양성도 만 개입니다.
풀이. () 정리합니다.
| 무엇이 문제라 하나 | 정말 문제인가 | 실제로는 |
|---|---|---|
| 갈래 비율 자체 | 아니오 | 비율은 정보임 |
| 드문 쪽 표본이 적음 | 예 | 분산이 큼 |
| 겹쳐 있음 | 예 | 베이즈 오류가 큼 |
| 문턱이 로 고정 | 예 | 옮기면 됨 |
| 손실이 비용을 안 봄 | 예 | 가중을 넣음 |
첫 줄이 흔한 오해입니다. 비율이 치우쳤다고 자동으로 문제는 아닙니다.
() 잘 갈리는 경우와 겹친 경우를 견줍니다.
| 떨어짐 정도 | 양성 비율 | ROC 넓이 | PR 넓이 | 문턱 재현율 |
|---|---|---|---|---|
떨어짐이 이면 양성이 퍼센트여도 ROC 넓이가 입니다. 비율이 균형일 때의 보다도 높습니다.
그런데 문턱 재현율은 에서 으로 반토막입니다. 순위는 좋은데 문턱이 나쁜 것입니다.
떨어짐이 이면 비율과 무관하게 어렵습니다. PR 넓이가 이고, 이것은 자료의 한계이지 비율의 문제가 아닙니다.
() 치우침이 무엇을 망가뜨리는지 잽니다. 비율은 로 고정하고 양성 개수만 바꿉니다.
| 양성 개수 | 계수 추정의 표준편차 | ROC 넓이 평균 | ROC 넓이 표준편차 |
|---|---|---|---|
양성이 개면 계수의 표준편차가 입니다. 개면 로 여섯 배 줄어듭니다.
그런데 ROC 넓이는 에서 로 거의 안 변합니다. 계수의 크기가 흔들려도 방향이 비슷해 순위가 지켜지기 때문입니다.
비율이 아니라 드문 쪽의 절대 개수가 계수의 믿음직함을 정합니다.
이 문제에서 배우는 것. "불균형"이라는 한 단어에 서로 다른 세 문제가 섞여 있습니다. 개수가 적은 것, 겹쳐 있는 것, 문턱이 안 맞는 것입니다. 어느 것인지 먼저 가려야 무엇을 할지 정해집니다.
확인 1-1. 갈래 비율 자체가 문제가 아닌 이유를 쓰세요.
답. 비율은 버릴 것이 아니라 알아야 할 정보이기 때문입니다.
확인 1-2. 검산에서 떨어짐 이고 양성 퍼센트일 때 ROC 넓이와 문턱 재현율을 쓰세요.
답. 와 입니다.
확인 1-3. 검산에서 양성 개와 개의 계수 표준편차를 쓰세요.
답. 과 입니다.
문제. 자료를 다시 뽑아 봅니다.
() 방법들을 정리하세요.
() 네 가지를 견주세요.
() 문턱을 옮긴 것과 견주고 SMOTE가 무엇을 만드는지 보세요.
생각의 실마리. 재표집은 자료를 바꾸는 일입니다. 자료를 바꾸면 모형이 바뀌는데, 무엇이 바뀌고 무엇이 안 바뀌는지를 봐야 합니다.
풀이. () 정리합니다.
| 방법 | 무엇을 하나 | 무엇이 문제인가 |
|---|---|---|
| 적은 쪽 늘리기 | 드문 쪽을 복사 | 같은 점이 여러 번 |
| 많은 쪽 줄이기 | 흔한 쪽을 버림 | 정보를 버림 |
| SMOTE | 이웃 사이를 보간 | 가짜 점이 경계에 |
| 둘을 섞음 | 늘리고 줄이고 | 손잡이가 둘 |
| 아무것도 안 함 | 문턱만 옮김 | 대개 이것으로 충분 |
() 네 가지를 견줍니다. 학습 양성 개 검증 양성 개입니다.
| 무엇을 했나 | 학습 양성 비율 | ROC 넓이 | PR 넓이 | 평균 예측 확률 |
|---|---|---|---|---|
| 그대로 | ||||
| 적은 쪽 늘리기 | ||||
| 많은 쪽 줄이기 | ||||
| SMOTE |
ROC 넓이가 에서 사이입니다. PR 넓이도 에서 사이입니다. 순위는 그대로입니다.
바뀌는 것은 평균 예측 확률입니다. 에서 근처로 여섯 배 넘게 오릅니다.
재표집이 하는 일은 문턱을 옮기는 것과 사실상 같습니다.
() 문턱을 옮긴 것과 견줍니다.
| 무엇을 했나 | 문턱 | 재현율 | 정밀도 |
|---|---|---|---|
| 그대로 문턱 | |||
| 그대로 비율 문턱 | |||
| 늘리고 문턱 |
아래 두 줄이 거의 같습니다. 재현율 대 , 정밀도 대 입니다.
재표집은 자료를 바꾸고 문턱 옮기기는 판정을 바꿉니다. 결과가 같다면 자료를 안 바꾸는 쪽이 낫습니다. 확률이 안 망가지기 때문입니다.
SMOTE가 만드는 점이 어디에 놓이는지 봅니다.
| 무엇 | 값 | 무엇을 뜻하나 |
|---|---|---|
| 원래 양성의 평균 판별값 | 참 양성 영역 | |
| 만든 점의 평균 판별값 | 평균은 거의 같음 | |
| 만든 점의 판별값 표준편차 | 원래보다 좁음 | |
| 원래 양성의 판별값 표준편차 | 기준 |
평균은 거의 같고 표준편차만 에서 으로 좁아집니다.
보간한 점은 원래 점들 사이에 놓이므로 바깥으로 안 나갑니다. 새 정보를 만든 것이 아니라 있던 것을 채운 것이고, 그래서 순위가 거의 안 바뀝니다.
이 문제에서 배우는 것. 재표집은 정보를 만들지 못합니다. 순위는 그대로 두고 확률만 옮기므로, 문턱을 옮기는 것과 같은 일을 더 비싸게 하는 셈입니다.
확인 2-1. 재표집이 무엇을 바꾸고 무엇을 안 바꾸는지 쓰세요.
답. 평균 예측 확률을 바꾸고 순위는 안 바꿉니다.
확인 2-2. 검산에서 그대로와 적은 쪽 늘리기의 평균 예측 확률을 쓰세요.
답. 와 입니다.
확인 2-3. 검산에서 SMOTE가 만든 점과 원래 양성의 판별값 표준편차를 쓰세요.
답. 과 입니다.
문제. 자료 대신 손실을 바꿉니다.
() 방법들을 정리하세요.
() 가중을 바꿔 가며 재고 계수를 견주세요.
() 부풀린 확률을 되돌리세요.
생각의 실마리. 재표집은 같은 점을 여러 번 세는 것입니다. 그러면 손실에 무게를 곱하는 것과 같아야 합니다. 정말 그런지 봅니다.
풀이. () 정리합니다.
| 무엇 | 어떻게 | 무엇과 같은가 |
|---|---|---|
| 갈래 가중 | 드문 쪽 손실에 곱 | 적은 쪽 늘리기 |
| 표본 가중 | 관측마다 다른 무게 | 가중 재표집 |
| 초점 손실 | 쉬운 것의 무게를 낮춤 | 어려운 것에 집중 |
| 비용 민감 문턱 | 판정만 바꿈 | 강 문제 |
() 가중을 바꿔 가며 잽니다.
| 양성 무게 | ROC 넓이 | PR 넓이 | 평균 예측 확률 | 문턱 재현율 |
|---|---|---|---|---|
ROC 넓이가 에서 사이로 거의 안 바뀝니다. 재현율만 에서 으로 오릅니다.
재표집과 같은 그림입니다. 셋 다 순위를 안 바꿉니다.
세 방법의 계수를 직접 견줍니다.
| 무엇 | 첫 계수 | 둘째 계수 | 절편 | 첫 계수의 비 |
|---|---|---|---|---|
| 그대로 | ||||
| 가중 | ||||
| 적은 쪽 늘리기 |
기울기 계수는 배 안쪽이고 절편은 에서 으로 나 옮겨집니다. 로짓 척도에서 는 오즈 배이므로 절편 쪽이 압도적으로 크게 움직인 것입니다.
절편이 곧 문턱입니다. 강에서 절편이 전체 수준이라 했고, 그래서 셋이 같은 직선을 다른 자리에 놓는 것입니다.
() 부풀린 확률을 되돌립니다.
| 무엇 | 브라이어 점수 | 평균 예측 확률 | 실제 비율과의 차 |
|---|---|---|---|
| 그대로 | |||
| 가중 | |||
| 적은 쪽 늘리기 |
가중은 평균 예측 확률을 에서 로 일곱 배 부풀립니다. 강 문제 의 비용 문턱을 쓰려면 이 확률로는 안 됩니다.
학습 비율과 실제 비율의 차이를 절편에서 빼면 됩니다.
| 무엇 | 평균 예측 확률 | 브라이어 점수 |
|---|---|---|
| 가중 그대로 | ||
| 절편을 되돌린 뒤 | ||
| 처음부터 가중 없이 |
되돌리면 브라이어 점수가 에서 가 되어 가중 없이 학습한 과 거의 같아집니다.
강 문제 의 사전확률을 바꿔 끼우는 것과 같은 계산입니다.
이 문제에서 배우는 것. 재표집과 가중과 문턱은 모두 절편을 옮기는 세 가지 방법입니다. 기울기는 거의 안 건드리고, 그래서 순위도 안 바뀝니다. 그리고 옮긴 절편은 공식으로 되돌릴 수 있습니다.
확인 3-1. 가중과 재표집이 계수의 무엇을 바꾸는지 쓰세요.
답. 기울기는 배 안쪽으로 두고 절편을 훨씬 크게 바꿉니다.
확인 3-2. 검산에서 그대로와 가중 의 절편을 쓰세요.
답. 와 입니다.
확인 3-3. 검산에서 절편을 되돌린 뒤의 평균 예측 확률과 브라이어 점수를 쓰세요.
답. 과 입니다.
문제. 정말 듣는 것을 찾습니다.
() 네 방법의 가장 좋은 F1을 견주세요.
() 다른 것들을 바꿔 보세요.
() 드문 쪽이 흩어져 있으면 어떤지 보세요.
생각의 실마리. 앞의 두 문제에서 재표집도 가중도 순위를 안 바꿨습니다. 그러면 문턱을 제대로 고르면 무엇을 했든 같은 자리에 가야 합니다.
풀이. () 네 방법의 가장 좋은 F1을 견줍니다.
| 무엇 | PR 넓이 | 가장 좋은 F1 | 그때 문턱 |
|---|---|---|---|
| 그대로 | |||
| 가중 | |||
| 적은 쪽 늘리기 | |||
| SMOTE |
가장 좋은 F1이 에서 사이로 넷 다 비슷합니다. 문턱만 와 로 크게 다릅니다.
문턱을 제대로 고르면 무엇을 했든 같은 자리에 갑니다.
() 그러면 무엇이 실제로 도움이 되는지 봅니다.
| 무엇을 바꿨나 | PR 넓이 | 그대로 대비 |
|---|---|---|
| 그대로 | ||
| 자료를 네 배로 | ||
| 변수를 늘림 | ||
| 벌점을 넣음 | ||
| 갈래가 더 잘 갈림 |
갈래가 잘 갈리는 것만 크게 듭니다. 오릅니다.
자료를 네 배로 늘려도 나빠집니다. 이미 양성이 개로 충분했기 때문입니다.
변수를 늘리거나 벌점을 넣는 것도 안쪽입니다. 참 경계가 직선이라 더할 것도 뺄 것도 없기 때문입니다.
결국 자료와 변수가 좋아야 합니다. 손잡이 조정으로는 안 됩니다.
() 드문 쪽이 여러 덩어리로 흩어져 있으면 어떤지 봅니다.
| 무엇 | PR 넓이 | ROC 넓이 |
|---|---|---|
| 로지스틱 | ||
| 제곱 항을 넣음 | ||
| 양성 대 음성 이웃 거리 차 |
직선 모형은 PR 넓이 로 흩어진 양성을 못 잡습니다.
제곱 항을 넣으면 으로 뜁니다. 세 덩어리가 원점에서 떨어져 있기 때문입니다.
이웃 거리 차이도 으로 직선보다 훨씬 낫습니다. 모양을 안 가정하기 때문입니다.
치우침이 문제가 아니라 모형이 모양을 못 담은 것입니다.
이 문제에서 배우는 것. "불균형이라 성능이 나쁘다"고 진단하기 전에 모형이 참 모양을 담고 있는지 봐야 합니다. 재표집을 아무리 해도 직선은 세 덩어리를 못 잡고, 제곱 항 하나가 PR 넓이를 두 배로 만듭니다.
확인 4-1. 문턱을 제대로 고르면 네 방법이 어떻게 되는지 쓰세요.
답. 가장 좋은 F1이 거의 같아지고 문턱만 다릅니다.
확인 4-2. 검산에서 갈래가 더 잘 갈릴 때 PR 넓이가 얼마나 오르는지 쓰세요.
답. 오릅니다.
확인 4-3. 검산에서 흩어진 양성에 로지스틱과 제곱 항의 PR 넓이를 쓰세요.
답. 와 입니다.
문제. 실제로 씁니다.
() 교차검증의 함정을 정리하세요.
() 재표집을 겹 밖에서 하면 얼마나 낙관되는지 재세요.
() 층화가 왜 필요한지 보고 절차를 정리하세요.
생각의 실마리. 재표집은 같은 점을 복사합니다. 복사한 뒤에 겹을 나누면 원본이 학습에, 복사본이 검증에 들어갑니다.
풀이. () 정리합니다.
| 무엇 | 무엇이 문제인가 | 어떻게 |
|---|---|---|
| 겹마다 양성이 개 | 지표를 못 잼 | 층화 겹 |
| 재표집을 먼저 하면 | 같은 점이 양쪽에 | 겹 안에서만 |
| SMOTE를 먼저 하면 | 만든 점이 검증에 | 겹 안에서만 |
| 문턱을 검증에서 고르면 | 낙관 | 따로 뗀 자료로 |
강 문제 의 누출이 여기서는 재표집을 통해 들어옵니다.
() 얼마나 낙관되는지 잽니다. 이웃 방법으로 봅니다. 복사된 점이 검증에 들어가면 자기를 찾습니다.
| 언제 재표집했나 | 교차검증 ROC 넓이 | 따로 뗀 자료 대비 |
|---|---|---|
| 겹을 나누기 전에 | ||
| 겹 안에서 |
먼저 늘리면 이 나옵니다. 따로 뗀 자료에서의 참값은 인데 이나 부풀었습니다.
겹 안에서 하면 로 참값보다 오히려 조금 낮습니다. 학습 자료가 겹만큼 적어서이고, 이쪽이 정직한 값입니다.
로지스틱처럼 매끄러운 모형은 이 누출이 작습니다. 같은 점을 여러 번 봐도 외울 수가 없기 때문입니다. 나무나 이웃 방법에서 특히 위험합니다.
() 층화가 왜 필요한지 봅니다. 양성이 개뿐인 자료입니다.
| 겹 수 | 무작위 겹의 최소 양성 수 | 층화 겹의 최소 양성 수 | 양성 인 겹 비율 |
|---|---|---|---|
겹을 개로만 해도 무작위로는 퍼센트의 경우에 양성이 인 겹이 생깁니다.
층화하면 겹마다 최소 개수가 보장됩니다. 겹에서도 겹당 개입니다.
강 심화 의 층화 겹이 여기서 필수가 됩니다.
실무 절차를 정리합니다.
| 순서 | 무엇을 하나 |
|---|---|
| 먼저 물어보기 | 정말 치우침이 문제인가 |
| 드문 쪽 개수 세기 | 비율이 아니라 개수 |
| 문턱부터 옮겨 보기 | 가장 싸고 대개 충분 |
| 그래도 모자라면 | 자료를 늘리거나 변수를 고침 |
| 재표집은 마지막에 | 확률이 망가짐 |
셋째 줄이 이 강의의 결론입니다.
이 문제에서 배우는 것. 재표집은 가장 먼저 손대는 것이 아니라 마지막에 남는 것입니다. 그리고 쓰더라도 반드시 겹 안에서 해야 하고, 안 그러면 성능을 크게 부풀려 봅니다.
확인 5-1. 재표집을 겹 안에서 해야 하는 이유를 쓰세요.
답. 먼저 하면 복사된 점이 학습과 검증에 함께 들어가기 때문입니다.
확인 5-2. 검산에서 겹 밖과 겹 안에서 재표집했을 때의 교차검증 ROC 넓이를 쓰세요.
답. 과 입니다.
확인 5-3. 검산에서 겹일 때 무작위 겹의 양성 인 비율을 쓰세요.
답. 입니다.
| 유형 | 무엇을 묻나 | 어디를 보나 |
|---|---|---|
| 비율 대 개수 | 무엇이 진짜 문제 | 문제 |
| 겹침 | 자료의 한계 | 문제 |
| 재표집의 효과 | 순위는 그대로 | 문제 |
| SMOTE | 흩어짐만 좁아짐 | 문제 |
| 가중과 절편 | 기울기는 그대로 | 문제 |
| 확률 되돌리기 | 사전확률 보정 | 문제 |
| 최선 F1 | 문턱만 다름 | 문제 |
| 모형의 모양 | 제곱 항 하나가 두 배 | 문제 |
| 겹 밖 재표집 | 크게 낙관 | 문제 |
| 층화 | 양성 인 겹 | 문제 |
핵심 식을 한자리에 모읍니다.
| 무엇을 하나 | 기울기 | 절편 | 순위 | 확률 |
|---|---|---|---|---|
| 문턱 옮기기 | 그대로 | 그대로 | 그대로 | 그대로 |
| 갈래 가중 | 거의 그대로 | 옮김 | 그대로 | 부풀림 |
| 재표집 | 조금 커짐 | 크게 옮김 | 그대로 | 부풀림 |
| 변수 고치기 | 바뀜 | 바뀜 | 바뀜 | 바뀜 |
문제 6. 갈래 비율 자체가 문제가 아닌 이유를 쓰세요.
답. 비율은 버릴 것이 아니라 알아야 할 정보이기 때문입니다.
문제 7. 검산에서 떨어짐 이고 양성 퍼센트일 때 ROC 넓이와 문턱 재현율을 쓰세요.
답. 와 입니다.
문제 8. 검산에서 양성 개와 개의 계수 표준편차를 쓰세요.
답. 과 입니다.
문제 9. 재표집이 무엇을 바꾸고 무엇을 안 바꾸는지 쓰세요.
답. 평균 예측 확률을 바꾸고 순위는 안 바꿉니다.
문제 10. 검산에서 그대로와 적은 쪽 늘리기의 평균 예측 확률을 쓰세요.
답. 와 입니다.
문제 11. 검산에서 SMOTE가 만든 점과 원래 양성의 판별값 표준편차를 쓰세요.
답. 과 입니다.
문제 12. 검산에서 그대로와 가중 의 절편을 쓰세요.
답. 와 입니다.
문제 13. 검산에서 절편을 되돌린 뒤의 평균 예측 확률과 브라이어 점수를 쓰세요.
답. 과 입니다.
문제 14. 검산에서 갈래가 더 잘 갈릴 때 PR 넓이가 얼마나 오르는지 쓰세요.
답. 오릅니다.
문제 15. 검산에서 흩어진 양성에 로지스틱과 제곱 항의 PR 넓이를 쓰세요.
답. 와 입니다.
문제 16. 검산에서 겹 밖과 겹 안에서 재표집했을 때의 교차검증 ROC 넓이를 쓰세요.
답. 과 입니다.
문제 17. 검산에서 겹일 때 무작위 겹의 양성 인 비율을 쓰세요.
답. 입니다.
문제 18. 불균형 문제에서 가장 먼저 해 볼 것을 쓰세요.
답. 문턱을 옮겨 보는 것입니다.
심화 1. 가중과 재표집이 왜 같은지 보이세요.
가중 손실은 이렇습니다.
| 무엇 | 뜻 |
|---|---|
| 인 관측 | 같은 점을 번 센 것 |
| 복원 추출로 번 뽑음 | 기댓값이 |
| 차이 | 재표집은 무작위라 분산이 더 큼 |
기댓값으로는 정확히 같고 재표집 쪽이 분산만 더 큽니다. 그래서 가중을 쓸 수 있으면 가중이 낫습니다. 문제 의 표에서 가중 와 적은 쪽 늘리기의 계수가 과 로 거의 같게 나온 것이 이것입니다.
심화 2. 사전확률 보정 공식을 유도하세요.
베이즈 규칙에서 사전확률만 바꿉니다.
| 단계 | 무엇 |
|---|---|
| 첫째 | 우도는 안 바뀜 |
| 둘째 | 사전확률 비만 바뀜 |
| 셋째 | 로그를 취하면 절편에 더해짐 |
강 문제 에서 분모가 갈래에 안 딸린다고 한 것이 여기서 쓰입니다. 우도가 그대로이므로 사전확률 비만 갈아 끼우면 됩니다.
심화 3. SMOTE의 변형들을 정리하세요.
| 변형 | 무엇을 다르게 |
|---|---|
| Borderline-SMOTE | 경계 근처 양성만 씀 |
| ADASYN | 어려운 양성 주위에 더 많이 |
| SMOTE-NC | 범주형 변수도 다룸 |
| SMOTE-Tomek | 만든 뒤 겹치는 쌍을 지움 |
첫 줄과 둘째 줄이 같은 생각입니다. 안쪽 깊숙한 양성 주위에 점을 만들어 봐야 경계가 안 바뀌므로, 경계 근처에 집중합니다. 다만 경계 근처는 잡음도 많은 자리라 이상점을 증폭할 수 있습니다.
심화 4. 초점 손실을 정리하세요.
| 무엇이 되나 | |
|---|---|
| 보통 교차엔트로피 | |
| 쉬운 것의 무게가 크게 줄음 | |
| 큼 | 어려운 것만 봄 |
이고 면 무게가 배입니다. 이미 잘 맞히는 것을 거의 안 보고 어려운 것에 집중합니다. 갈래 가중이 갈래별로 무게를 주는 것과 달리 관측별로 줍니다.
심화 5. 이상탐지와 언제 갈리는지 정리하세요.
| 무엇 | 불균형 분류 | 강 이상탐지 |
|---|---|---|
| 드문 쪽 라벨 | 있음 | 거의 없음 |
| 드문 쪽 모양 | 일정함 | 미리 모름 |
| 드문 쪽 개수 | 수백 이상 | 수십 이하 |
| 방법 | 분류기 | 정상 모형 |
셋째 줄이 실무의 경계입니다. 양성이 수백 개 있으면 분류기가 낫고, 수십 개 이하이거나 새 종류가 계속 나오면 강으로 갑니다.
심화 6. 언제 무엇을 쓸지 정리하세요.
| 상황 | 무엇을 하나 | 왜 |
|---|---|---|
| 확률이 필요함 | 문턱만 옮김 | 확률이 안 망가짐 |
| 판정만 필요함 | 무엇이든 | 결과가 같음 |
| 양성이 아주 적음 | 자료를 늘림 | 개수가 문제 |
| 나무나 이웃 방법 | 가중 | 재표집은 누출 위험 |
| 경계가 굽음 | 변수를 고침 | 문제 |
첫 줄이 가장 자주 맞는 답입니다. 강 문제 의 비용 문턱을 쓰려면 확률이 맞아야 하고, 재표집하면 그것부터 망가집니다.
정답.
| 기호 | 읽는 법 | 뜻 |
|---|---|---|
| 불균형 자료 | imbalanced data | 갈래 비율이 크게 치우친 자료입니다 |
| 적은 쪽 늘리기 | oversampling | 드문 갈래를 복사해 늘립니다 |
| 많은 쪽 줄이기 | undersampling | 흔한 갈래를 버려 줄입니다 |
| SMOTE | synthetic minority oversampling | 이웃 사이를 보간해 점을 만듭니다 |
| 갈래 가중 | class weight | 갈래마다 손실에 다른 무게를 줍니다 |
| 초점 손실 | focal loss | 쉬운 것의 무게를 낮춥니다 |
| 사전확률 보정 | prior correction | 절편으로 학습 비율을 되돌립니다 |
| 층화 겹 | stratified fold | 겹마다 갈래 비율을 지킵니다 |
| 누출 | leakage | 검증 정보가 학습에 들어갑니다 |
| 비용 민감 학습 | cost-sensitive learning | 오류마다 다른 비용을 씁니다 |
다음은 228강 특성공학입니다. 이 강의의 문제 에서 제곱 항 하나가 PR 넓이를 두 배로 만들었습니다. 다음 강의는 그 변수를 어떻게 만드는지를 봅니다.
import numpy as np
rng = np.random.default_rng(20270207)
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)
def auc_roc(score, y):
o = np.argsort(score)
r = np.empty(len(score))
r[o] = np.arange(1, len(score) + 1)
n1 = float((y == 1).sum())
n0 = float((y == 0).sum())
if n1 == 0 or n0 == 0:
return 0.5
return float((r[y == 1].sum() - n1 * (n1 + 1) / 2) / (n1 * n0))
def auc_pr(score, y):
o = np.argsort(-score)
ys = y[o]
tp = np.cumsum(ys == 1)
pr = tp / np.arange(1, len(ys) + 1)
P = max(int((y == 1).sum()), 1)
return float(np.sum(pr * (ys == 1)) / P)
def prf(y, pred):
tp = float(np.sum((pred == 1) & (y == 1)))
fp = float(np.sum((pred == 1) & (y == 0)))
fn = float(np.sum((pred == 0) & (y == 1)))
p = tp / max(tp + fp, 1)
r = tp / max(tp + fn, 1)
f = 0.0 if p + r == 0 else 2 * p * r / (p + r)
return p, r, f
def logit_fit(X, y, w=None, steps=4000, lr=0.4, lam=0.0):
A = np.hstack([X, np.ones((len(X), 1))])
if w is None:
w = np.ones(len(y))
w = w / w.mean()
b = np.zeros(A.shape[1])
for _ in range(steps):
p = 1.0 / (1.0 + np.exp(-A @ b))
g = A.T @ (w * (p - y)) / len(y) + lam * b
b -= lr * g
return b
def logit_p(b, X):
return 1.0 / (1.0 + np.exp(-(np.hstack([X, np.ones((len(X), 1))]) @ b)))
def make(m, pr, sep=1.4, d=4, r=None):
X = r.normal(0, 1, (m, d))
s = sep * X[:, 0] - 0.8 * X[:, 1] + 0.4 * X[:, 2] + r.normal(0, 1.0, m)
thr = float(np.quantile(s, 1 - pr))
y = (s > thr).astype(float)
return X, y
# --- 문제 1: 무엇이 진짜 문제인가 ---------------------------------------
print(" 226강은 치우친 자료를 어떻게 재는지 봤습니다")
print(" 이번에는 어떻게 다룰지를 봅니다")
print(" %s %s %s"
% (pw("무엇이 문제라 하나", 24), rw("정말 문제인가", 20),
rw("실제로는", 26)))
for a, b, c in [("갈래 비율 자체", "아니오", "비율은 정보임"),
("드문 쪽 표본이 적음", "예", "분산이 큼"),
("겹쳐 있음", "예", "베이즈 오류가 큼"),
("문턱이 0.5 로 고정", "예", "옮기면 됨"),
("손실이 비용을 안 봄", "예", "가중을 넣음")]:
print(" %s %s %s" % (pw(a, 24), rw(b, 20), rw(c, 26)))
print(" 첫 줄이 흔한 오해입니다. 비율이 치우쳤다고 자동으로 문제는 아닙니다")
print(" 드문 쪽이 잘 갈리면 비율이 1 퍼센트여도 잘 잡습니다")
print(" 잘 갈리는 경우와 겹친 경우를 견줍니다")
print(" %s %s %s %s %s"
% (pw("떨어짐 정도", 14), rw("양성 비율", 12), rw("ROC 넓이", 16),
rw("PR 넓이", 16), rw("0.5 문턱 재현율", 20)))
for sep in [3.0, 1.4, 0.6]:
for pr in [0.5, 0.02]:
Xa, ya = make(6000, pr, sep, 4, rng)
Xb, yb = make(6000, pr, sep, 4, rng)
b = logit_fit(Xa, ya)
ph = logit_p(b, Xb)
print(" %s %12.4f %16.6f %16.6f %20.6f"
% (pw("%.1f" % sep, 14), float(yb.mean()),
auc_roc(ph, yb), auc_pr(ph, yb), prf(yb, (ph > 0.5))[1]))
print(" 떨어짐이 3.0 이면 양성이 2 퍼센트여도 ROC 넓이가 0.98 을 넘습니다")
print(" 그런데 0.5 문턱 재현율은 크게 떨어집니다. 순위는 좋은데 문턱이 나쁩니다")
print(" 떨어짐이 0.6 이면 비율과 무관하게 어렵습니다. 자료의 한계입니다")
print(" 치우침이 무엇을 실제로 망가뜨리는지 봅니다")
print(" %s %s %s %s"
% (pw("양성 개수", 14), rw("계수 추정의 표준편차", 26),
rw("ROC 넓이 평균", 20), rw("ROC 넓이 표준편차", 22)))
for npos in [20, 60, 200, 1000]:
aucs, cs = [], []
for _ in range(30):
m = int(npos / 0.02)
Xa, ya = make(m, 0.02, 1.4, 4, rng)
if ya.sum() < 3:
continue
b = logit_fit(Xa, ya, steps=1500)
Xb, yb = make(4000, 0.02, 1.4, 4, rng)
aucs.append(auc_roc(logit_p(b, Xb), yb))
cs.append(b[0])
print(" %s %26.6f %20.6f %22.6f"
% (pw(str(npos), 14), float(np.std(cs)),
float(np.mean(aucs)), float(np.std(aucs))))
print(" 양성이 20 개면 계수의 표준편차가 0.147637 입니다. 1000 개면 0.024102 로 줍니다")
print(" 그런데 ROC 넓이는 거의 안 변합니다")
print(" 계수의 크기가 흔들려도 방향이 비슷해 순위가 지켜지기 때문입니다")
print(" 비율이 아니라 드문 쪽의 절대 개수가 계수의 믿음직함을 정합니다")
# --- 문제 2: 재표집 -----------------------------------------------------
print(" 자료를 다시 뽑아 비율을 맞추는 방법들을 봅니다")
print(" %s %s %s"
% (pw("방법", 22), rw("무엇을 하나", 26), rw("무엇이 문제인가", 24)))
for a, b, c in [("적은 쪽 늘리기", "드문 쪽을 복사", "같은 점이 여러 번"),
("많은 쪽 줄이기", "흔한 쪽을 버림", "정보를 버림"),
("SMOTE", "이웃 사이를 보간", "가짜 점이 경계에"),
("둘을 섞음", "늘리고 줄이고", "손잡이가 둘"),
("아무것도 안 함", "문턱만 옮김", "대개 이것으로 충분")]:
print(" %s %s %s" % (pw(a, 22), rw(b, 26), rw(c, 24)))
print(" 마지막 줄이 이 문제의 결론입니다. 수치로 확인합니다")
X2, y2 = make(8000, 0.02, 1.4, 4, rng)
X2t, y2t = make(6000, 0.02, 1.4, 4, rng)
print(" 학습 양성 %d 개 검증 양성 %d 개입니다"
% (int(y2.sum()), int(y2t.sum())))
def smote(X, y, k=5, ratio=1.0, r=None):
P = X[y == 1]
N = X[y == 0]
need = int(len(N) * ratio) - len(P)
if need <= 0 or len(P) < 2:
return X, y
D = ((P[:, None, :] - P[None, :, :]) ** 2).sum(axis=2)
np.fill_diagonal(D, np.inf)
nb = np.argsort(D, axis=1)[:, :min(k, len(P) - 1)]
idx = r.integers(0, len(P), need)
pick = nb[idx, r.integers(0, nb.shape[1], need)]
lam = r.uniform(0, 1, (need, 1))
new = P[idx] + lam * (P[pick] - P[idx])
return (np.vstack([X, new]),
np.concatenate([y, np.ones(need)]))
print(" %s %s %s %s %s"
% (pw("무엇을 했나", 22), rw("학습 양성 비율", 20), rw("ROC 넓이", 16),
rw("PR 넓이", 16), rw("평균 예측 확률", 20)))
res = {}
b0 = logit_fit(X2, y2)
res["그대로"] = (X2, y2, b0)
idx_up = np.concatenate([np.where(y2 == 0)[0],
rng.choice(np.where(y2 == 1)[0],
int((y2 == 0).sum()), replace=True)])
res["적은 쪽 늘리기"] = (X2[idx_up], y2[idx_up],
logit_fit(X2[idx_up], y2[idx_up]))
idx_dn = np.concatenate([np.where(y2 == 1)[0],
rng.choice(np.where(y2 == 0)[0],
int((y2 == 1).sum()), replace=False)])
res["많은 쪽 줄이기"] = (X2[idx_dn], y2[idx_dn],
logit_fit(X2[idx_dn], y2[idx_dn]))
Xs, ys = smote(X2, y2, 5, 1.0, rng)
res["SMOTE"] = (Xs, ys, logit_fit(Xs, ys))
for nm in ["그대로", "적은 쪽 늘리기", "많은 쪽 줄이기", "SMOTE"]:
Xa, ya, b = res[nm]
ph = logit_p(b, X2t)
print(" %s %20.6f %16.6f %16.6f %20.6f"
% (pw(nm, 22), float(ya.mean()), auc_roc(ph, y2t),
auc_pr(ph, y2t), float(ph.mean())))
print(" ROC 넓이와 PR 넓이가 거의 안 바뀝니다. 순위는 그대로입니다")
print(" 바뀌는 것은 평균 예측 확률입니다. 0.022275 에서 0.14 근처로 여섯 배 넘게 오릅니다")
print(" 재표집이 하는 일은 문턱을 옮기는 것과 사실상 같습니다")
print(" 문턱을 옮긴 것과 견줍니다")
print(" %s %s %s %s"
% (pw("무엇을 했나", 24), rw("문턱", 14), rw("재현율", 16),
rw("정밀도", 16)))
ph0 = logit_p(b0, X2t)
print(" %s %14.6f %16.6f %16.6f"
% (pw("그대로 0.5 문턱", 24), 0.5, prf(y2t, ph0 > 0.5)[1],
prf(y2t, ph0 > 0.5)[0]))
print(" %s %14.6f %16.6f %16.6f"
% (pw("그대로 비율 문턱", 24), 0.02, prf(y2t, ph0 > 0.02)[1],
prf(y2t, ph0 > 0.02)[0]))
phu = logit_p(res["적은 쪽 늘리기"][2], X2t)
print(" %s %14.6f %16.6f %16.6f"
% (pw("늘리고 0.5 문턱", 24), 0.5, prf(y2t, phu > 0.5)[1],
prf(y2t, phu > 0.5)[0]))
print(" 아래 두 줄이 거의 같습니다. 같은 자리를 다른 길로 간 것입니다")
print(" 재표집은 자료를 바꾸고 문턱 옮기기는 판정을 바꿉니다")
print(" 결과가 같다면 자료를 안 바꾸는 쪽이 낫습니다. 확률이 안 망가집니다")
print(" SMOTE 가 만드는 점이 어디에 놓이는지 봅니다")
P2 = X2[y2 == 1]
Sn = Xs[len(X2):]
print(" %s %s %s"
% (pw("무엇", 26), rw("값", 20), rw("무엇을 뜻하나", 26)))
print(" %s %20.6f %s"
% (pw("원래 양성의 평균 판별값", 26),
float((1.4 * P2[:, 0] - 0.8 * P2[:, 1]).mean()), rw("참 양성 영역", 26)))
print(" %s %20.6f %s"
% (pw("만든 점의 평균 판별값", 26),
float((1.4 * Sn[:, 0] - 0.8 * Sn[:, 1]).mean()), rw("안쪽으로 몰림", 26)))
print(" %s %20.6f %s"
% (pw("만든 점의 판별값 표준편차", 26),
float((1.4 * Sn[:, 0] - 0.8 * Sn[:, 1]).std()), rw("원래보다 좁음", 26)))
print(" %s %20.6f %s"
% (pw("원래 양성의 판별값 표준편차", 26),
float((1.4 * P2[:, 0] - 0.8 * P2[:, 1]).std()), rw("기준", 26)))
print(" 평균은 거의 같고 표준편차만 좁아집니다")
print(" 보간한 점은 원래 점들 사이에 놓이므로 바깥으로 안 나갑니다")
print(" 새 정보를 만든 것이 아니라 있던 것을 채운 것입니다")
print(" 그래서 순위가 거의 안 바뀝니다. 앞의 표가 그 결과입니다")
# --- 문제 3: 가중과 손실 ------------------------------------------------
print(" 자료 대신 손실에 무게를 겁니다")
print(" %s %s %s"
% (pw("무엇", 22), rw("어떻게", 24), rw("무엇과 같은가", 26)))
for a, b, c in [("갈래 가중", "드문 쪽 손실에 곱", "적은 쪽 늘리기"),
("표본 가중", "관측마다 다른 무게", "가중 재표집"),
("초점 손실", "쉬운 것의 무게를 낮춤", "어려운 것에 집중"),
("비용 민감 문턱", "판정만 바꿈", "226강 문제 2")]:
print(" %s %s %s" % (pw(a, 22), rw(b, 24), rw(c, 26)))
print(" 첫 줄과 셋째 줄이 정말 같은지 확인합니다")
print(" 갈래 가중을 바꿔 가며 잽니다")
print(" %s %s %s %s %s"
% (pw("양성 무게", 12), rw("ROC 넓이", 16), rw("PR 넓이", 16),
rw("평균 예측 확률", 18), rw("0.5 문턱 재현율", 20)))
for wpos in [1.0, 5.0, 20.0, 49.0]:
ww = np.where(y2 == 1, wpos, 1.0)
b = logit_fit(X2, y2, ww)
ph = logit_p(b, X2t)
print(" %s %16.6f %16.6f %18.6f %20.6f"
% (pw("%.0f" % wpos, 12), auc_roc(ph, y2t), auc_pr(ph, y2t),
float(ph.mean()), prf(y2t, ph > 0.5)[1]))
print(" 무게를 49 로 두면 양성 비율 0.02 가 균형에 가깝게 맞춰집니다")
print(" ROC 넓이는 거의 안 바뀌고 평균 예측 확률만 올라갑니다")
print(" 재표집과 같은 그림입니다. 셋 다 순위를 안 바꿉니다")
print(" 세 방법의 계수를 직접 견줍니다")
bw = logit_fit(X2, y2, np.where(y2 == 1, 49.0, 1.0))
bu = res["적은 쪽 늘리기"][2]
print(" %s %s %s %s %s"
% (pw("무엇", 22), rw("첫 계수", 16), rw("둘째 계수", 16),
rw("절편", 16), rw("첫 계수의 비", 18)))
for nm, b in [("그대로", b0), ("가중 49", bw), ("적은 쪽 늘리기", bu)]:
print(" %s %16.6f %16.6f %16.6f %18.6f"
% (pw(nm, 22), b[0], b[1], b[4], b[0] / b0[0]))
print(" 기울기 계수는 1.3 배 안쪽이고 절편은 2.4 나 옮겨집니다")
print(" 절편이 곧 문턱입니다. 208강에서 절편이 전체 수준이라 했습니다")
print(" 그래서 셋이 같은 직선을 다른 자리에 놓는 것입니다")
print(" 확률이 얼마나 망가지는지 봅니다")
print(" %s %s %s %s"
% (pw("무엇", 22), rw("브라이어 점수", 20), rw("평균 예측 확률", 20),
rw("실제 비율과의 차", 22)))
tr = float(y2t.mean())
for nm, b in [("그대로", b0), ("가중 49", bw), ("적은 쪽 늘리기", bu)]:
ph = logit_p(b, X2t)
print(" %s %20.6f %20.6f %22.6f"
% (pw(nm, 22), float(np.mean((ph - y2t) ** 2)), float(ph.mean()),
float(ph.mean()) - tr))
print(" 실제 양성 비율은 %.6f 입니다" % tr)
print(" 가중은 평균 예측 확률을 0.020000 에서 0.142739 로 일곱 배 부풀립니다")
print(" 226강 문제 2 의 비용 문턱을 쓰려면 이 확률로는 안 됩니다")
print(" 부풀린 확률을 되돌리는 공식을 확인합니다")
print(" 학습 비율과 실제 비율의 차이를 절편에서 빼면 됩니다")
r_tr = 0.5
r_true = float(y2.mean())
adj = np.log(r_true / (1 - r_true)) - np.log(r_tr / (1 - r_tr))
lg = np.log(np.clip(logit_p(bw, X2t), 1e-12, 1 - 1e-12)
/ np.clip(1 - logit_p(bw, X2t), 1e-12, 1 - 1e-12))
pc = 1.0 / (1.0 + np.exp(-(lg + adj)))
print(" %s %s %s"
% (pw("무엇", 26), rw("평균 예측 확률", 20), rw("브라이어 점수", 20)))
for nm, q in [("가중 49 그대로", logit_p(bw, X2t)), ("절편을 되돌린 뒤", pc),
("처음부터 가중 없이", logit_p(b0, X2t))]:
print(" %s %20.6f %20.6f"
% (pw(nm, 26), float(q.mean()), float(np.mean((q - y2t) ** 2))))
print(" 되돌리면 가중 없이 학습한 것과 거의 같아집니다")
print(" 216강 문제 1 의 사전확률을 바꿔 끼우는 것과 같은 계산입니다")
# --- 문제 4: 무엇이 실제로 도움이 되는가 --------------------------------
print(" 네 가지를 같은 자료에서 견줍니다")
print(" %s %s %s %s"
% (pw("무엇", 24), rw("PR 넓이", 16), rw("가장 좋은 F1", 18),
rw("그때 문턱", 16)))
ths = np.linspace(0.005, 0.995, 199)
def bestf1(ph, y):
vs = [prf(y, ph > t)[2] for t in ths]
k = int(np.argmax(vs))
return float(vs[k]), float(ths[k])
cand = [("그대로", b0, X2t), ("가중 49", bw, X2t),
("적은 쪽 늘리기", bu, X2t), ("SMOTE", res["SMOTE"][2], X2t)]
for nm, b, Xq in cand:
ph = logit_p(b, Xq)
f, t = bestf1(ph, y2t)
print(" %s %16.6f %18.6f %16.6f"
% (pw(nm, 24), auc_pr(ph, y2t), f, t))
print(" 가장 좋은 F1 이 넷 다 비슷합니다. 문턱만 다릅니다")
print(" 문턱을 제대로 고르면 무엇을 했든 같은 자리에 갑니다")
print(" 그러면 무엇이 실제로 도움이 되는지 다음에서 봅니다")
print(" 정말 도움이 되는 것을 찾습니다")
print(" %s %s %s"
% (pw("무엇을 바꿨나", 26), rw("PR 넓이", 18), rw("그대로 대비", 18)))
base_pr = auc_pr(logit_p(b0, X2t), y2t)
print(" %s %18.6f %18.6f" % (pw("그대로", 26), base_pr, 0.0))
X3, y3 = make(32000, 0.02, 1.4, 4, rng)
b3 = logit_fit(X3, y3)
v = auc_pr(logit_p(b3, X2t), y2t)
print(" %s %18.6f %18.6f" % (pw("자료를 네 배로", 26), v, v - base_pr))
Xg = np.hstack([X2, X2[:, [0]] * X2[:, [1]], X2[:, [0]] ** 2])
Xgt = np.hstack([X2t, X2t[:, [0]] * X2t[:, [1]], X2t[:, [0]] ** 2])
bg = logit_fit(Xg, y2)
v = auc_pr(logit_p(bg, Xgt), y2t)
print(" %s %18.6f %18.6f" % (pw("변수를 늘림", 26), v, v - base_pr))
bl = logit_fit(X2, y2, lam=0.02)
v = auc_pr(logit_p(bl, X2t), y2t)
print(" %s %18.6f %18.6f" % (pw("벌점을 넣음", 26), v, v - base_pr))
X4, y4 = make(8000, 0.02, 2.2, 4, rng)
X4t, y4t = make(6000, 0.02, 2.2, 4, rng)
b4 = logit_fit(X4, y4)
v = auc_pr(logit_p(b4, X4t), y4t)
print(" %s %18.6f %18.6f" % (pw("갈래가 더 잘 갈림", 26), v, v - base_pr))
print(" 갈래가 잘 갈리는 것만 크게 듭니다. 0.222144 오릅니다")
print(" 자료를 네 배로 늘려도 0.004104 나빠집니다. 이미 양성이 충분했기 때문입니다")
print(" 변수를 늘리거나 벌점을 넣는 것도 0.002 안쪽입니다. 사실상 제자리입니다")
print(" 참 경계가 직선이라 더할 것도 뺄 것도 없기 때문입니다")
print(" 재표집과 가중도 앞 표에서 봤듯 거의 안 듭니다")
print(" 결국 자료와 변수가 좋아야 합니다. 손잡이 조정으로는 안 됩니다")
print(" 드문 쪽이 여러 덩어리로 흩어져 있으면 어떤지 봅니다")
n5 = 8000
z5 = rng.integers(0, 3, n5)
cen5 = np.array([[3.0, 0.0, 0, 0], [-3.0, 0.0, 0, 0], [0.0, 3.0, 0, 0]])
X5 = rng.normal(0, 1, (n5, 4))
mask = rng.uniform(0, 1, n5) < 0.02
X5[mask] = X5[mask] + cen5[z5[mask]]
y5 = mask.astype(float)
X5t = rng.normal(0, 1, (6000, 4))
zt5 = rng.integers(0, 3, 6000)
mt = rng.uniform(0, 1, 6000) < 0.02
X5t[mt] = X5t[mt] + cen5[zt5[mt]]
y5t = mt.astype(float)
print(" 양성이 세 덩어리로 흩어져 있습니다")
print(" %s %s %s"
% (pw("무엇", 26), rw("PR 넓이", 18), rw("ROC 넓이", 18)))
bl5 = logit_fit(X5, y5)
print(" %s %18.6f %18.6f"
% (pw("로지스틱", 26), auc_pr(logit_p(bl5, X5t), y5t),
auc_roc(logit_p(bl5, X5t), y5t)))
Xq5 = np.hstack([X5, X5 ** 2])
Xq5t = np.hstack([X5t, X5t ** 2])
bq5 = logit_fit(Xq5, y5)
print(" %s %18.6f %18.6f"
% (pw("제곱 항을 넣음", 26), auc_pr(logit_p(bq5, Xq5t), y5t),
auc_roc(logit_p(bq5, Xq5t), y5t)))
Dp = ((X5t[:, None, :] - X5[y5 == 1][None, :, :]) ** 2).sum(axis=2)
Dn = ((X5t[:, None, :] - X5[y5 == 0][:2000][None, :, :]) ** 2).sum(axis=2)
sk = np.sort(Dn, axis=1)[:, 4] - np.sort(Dp, axis=1)[:, 4]
print(" %s %18.6f %18.6f"
% (pw("양성 대 음성 이웃 거리 차", 26), auc_pr(sk, y5t), auc_roc(sk, y5t)))
print(" 직선 모형은 PR 넓이 0.287954 로 흩어진 양성을 못 잡습니다")
print(" 제곱 항을 넣으면 0.609106 으로 뜁니다. 세 덩어리가 원점에서 떨어져 있기 때문입니다")
print(" 이웃 거리 차이도 직선보다 낫습니다. 모양을 안 가정하기 때문입니다")
print(" 치우침이 문제가 아니라 모형이 모양을 못 담은 것입니다")
# --- 문제 5: 실무에서 쓰기 ---------------------------------------------
print(" 교차검증에서 무엇을 조심해야 하는지 봅니다")
print(" %s %s %s"
% (pw("무엇", 26), rw("무엇이 문제인가", 26), rw("어떻게", 22)))
for a, b, c in [("겹마다 양성이 0 개", "지표를 못 잼", "층화 겹"),
("재표집을 먼저 하면", "같은 점이 양쪽에", "겹 안에서만"),
("SMOTE 를 먼저 하면", "만든 점이 검증에", "겹 안에서만"),
("문턱을 검증에서 고르면", "낙관", "따로 뗀 자료로")]:
print(" %s %s %s" % (pw(a, 26), rw(b, 26), rw(c, 22)))
print(" 212강 문제 4 의 누출이 여기서는 재표집을 통해 들어옵니다")
print(" 재표집을 겹 밖에서 하면 얼마나 낙관되는지 잽니다")
def knn_score(Xa, ya, Xb, k=5):
D = ((Xb[:, None, :] - Xa[None, :, :]) ** 2).sum(axis=2)
idx = np.argsort(D, axis=1)[:, :k]
return ya[idx].mean(axis=1)
def cv_auc(X, y, k, resample_first, r):
n = len(y)
if resample_first:
idx = np.concatenate([np.where(y == 0)[0],
r.choice(np.where(y == 1)[0],
int((y == 0).sum()), replace=True)])
X, y = X[idx], y[idx]
n = len(y)
fol = np.array_split(r.permutation(n), k)
vs = []
for i in range(k):
te = fol[i]
trn = np.concatenate([fol[j] for j in range(k) if j != i])
Xa, ya = X[trn], y[trn]
if not resample_first:
ii = np.concatenate([np.where(ya == 0)[0],
r.choice(np.where(ya == 1)[0],
int((ya == 0).sum()), replace=True)])
Xa, ya = Xa[ii], ya[ii]
vs.append(auc_roc(knn_score(Xa, ya, X[te], 5), y[te]))
return float(np.mean(vs))
Xh, yh = X2[:2500], y2[:2500]
Xht, yht = X2t[:2500], y2t[:2500]
true_auc = auc_roc(knn_score(Xh, yh, Xht, 5), yht)
print(" 이웃 방법으로 봅니다. 복사된 점이 검증에 들어가면 자기를 찾습니다")
print(" %s %s %s"
% (pw("언제 재표집했나", 26), rw("교차검증 ROC 넓이", 24),
rw("따로 뗀 자료 대비", 22)))
for nm, first in [("겹을 나누기 전에", True), ("겹 안에서", False)]:
v = cv_auc(Xh, yh, 5, first, rng)
print(" %s %24.6f %22.6f" % (pw(nm, 26), v, v - true_auc))
print(" 따로 뗀 자료에서의 값은 %.6f 입니다" % true_auc)
print(" 먼저 늘리면 같은 점이 학습과 검증에 함께 들어가 크게 낙관됩니다")
print(" 겹 안에서 하면 정직한 값이 나옵니다")
print(" 로지스틱처럼 매끄러운 모형은 이 누출이 작습니다. 외울 수가 없기 때문입니다")
print(" 층화가 왜 필요한지 봅니다")
Xr7, yr7 = make(4000, 0.01, 1.4, 4, rng)
print(" 양성이 %d 개뿐인 자료로 봅니다" % int(yr7.sum()))
y2 = yr7
print(" %s %s %s %s"
% (pw("겹 수", 10), rw("무작위 겹의 최소 양성 수", 28),
rw("층화 겹의 최소 양성 수", 26), rw("양성 0 인 겹 비율", 22)))
pos_idx = np.where(y2 == 1)[0]
for k in [5, 10, 20, 40]:
mins_r, mins_s, zero = [], [], 0
for _ in range(40):
fol = np.array_split(rng.permutation(len(y2)), k)
c = [int(y2[f].sum()) for f in fol]
mins_r.append(min(c))
if min(c) == 0:
zero += 1
po = rng.permutation(pos_idx)
ne = rng.permutation(np.where(y2 == 0)[0])
cs = [len(np.array_split(po, k)[i]) for i in range(k)]
mins_s.append(min(cs))
print(" %s %28.6f %26.6f %22.6f"
% (pw(str(k), 10), float(np.mean(mins_r)), float(np.mean(mins_s)),
zero / 40.0))
print(" 겹을 40 개로 하면 무작위로는 양성이 0 인 겹이 자주 생깁니다")
print(" 층화하면 겹마다 최소 개수가 보장됩니다")
print(" 212강 심화 3 의 층화 겹이 여기서 필수가 됩니다")
print(" 실무 절차를 정리합니다")
print(" %s %s"
% (pw("순서", 26), rw("무엇을 하나", 38)))
for a, b in [("먼저 물어보기", "정말 치우침이 문제인가"),
("드문 쪽 개수 세기", "비율이 아니라 개수"),
("문턱부터 옮겨 보기", "가장 싸고 대개 충분"),
("그래도 모자라면", "자료를 늘리거나 변수를 고침"),
("재표집은 마지막에", "확률이 망가짐")]:
print(" %s %s" % (pw(a, 26), rw(b, 38)))
print(" 셋째 줄이 이 강의의 결론입니다")
print(" 227강은 치우친 자료를 봤습니다. 228강은 변수를 만듭니다")
# 226강은 치우친 자료를 어떻게 재는지 봤습니다
# 이번에는 어떻게 다룰지를 봅니다
# 무엇이 문제라 하나 정말 문제인가 실제로는
# 갈래 비율 자체 아니오 비율은 정보임
# 드문 쪽 표본이 적음 예 분산이 큼
# 겹쳐 있음 예 베이즈 오류가 큼
# 문턱이 0.5 로 고정 예 옮기면 됨
# 손실이 비용을 안 봄 예 가중을 넣음
# 첫 줄이 흔한 오해입니다. 비율이 치우쳤다고 자동으로 문제는 아닙니다
# 드문 쪽이 잘 갈리면 비율이 1 퍼센트여도 잘 잡습니다
# 잘 갈리는 경우와 겹친 경우를 견줍니다
# 떨어짐 정도 양성 비율 ROC 넓이 PR 넓이 0.5 문턱 재현율
# 3.0 0.5000 0.971255 0.972793 0.899000
# 3.0 0.0200 0.994379 0.803790 0.458333
# 1.4 0.5000 0.914143 0.916322 0.836000
# 1.4 0.0200 0.969636 0.528267 0.300000
# 0.6 0.5000 0.839159 0.844766 0.750667
# 0.6 0.0200 0.936050 0.360324 0.125000
# 떨어짐이 3.0 이면 양성이 2 퍼센트여도 ROC 넓이가 0.98 을 넘습니다
# 그런데 0.5 문턱 재현율은 크게 떨어집니다. 순위는 좋은데 문턱이 나쁩니다
# 떨어짐이 0.6 이면 비율과 무관하게 어렵습니다. 자료의 한계입니다
# 치우침이 무엇을 실제로 망가뜨리는지 봅니다
# 양성 개수 계수 추정의 표준편차 ROC 넓이 평균 ROC 넓이 표준편차
# 20 0.147637 0.969318 0.005431
# 60 0.115980 0.971569 0.004804
# 200 0.048126 0.972957 0.005458
# 1000 0.024102 0.974494 0.005355
# 양성이 20 개면 계수의 표준편차가 0.147637 입니다. 1000 개면 0.024102 로 줍니다
# 그런데 ROC 넓이는 거의 안 변합니다
# 계수의 크기가 흔들려도 방향이 비슷해 순위가 지켜지기 때문입니다
# 비율이 아니라 드문 쪽의 절대 개수가 계수의 믿음직함을 정합니다
# 자료를 다시 뽑아 비율을 맞추는 방법들을 봅니다
# 방법 무엇을 하나 무엇이 문제인가
# 적은 쪽 늘리기 드문 쪽을 복사 같은 점이 여러 번
# 많은 쪽 줄이기 흔한 쪽을 버림 정보를 버림
# SMOTE 이웃 사이를 보간 가짜 점이 경계에
# 둘을 섞음 늘리고 줄이고 손잡이가 둘
# 아무것도 안 함 문턱만 옮김 대개 이것으로 충분
# 마지막 줄이 이 문제의 결론입니다. 수치로 확인합니다
# 학습 양성 160 개 검증 양성 120 개입니다
# 무엇을 했나 학습 양성 비율 ROC 넓이 PR 넓이 평균 예측 확률
# 그대로 0.020000 0.963367 0.471941 0.022275
# 적은 쪽 늘리기 0.500000 0.964089 0.473122 0.140476
# 많은 쪽 줄이기 0.500000 0.963330 0.472388 0.145388
# SMOTE 0.500000 0.964024 0.472171 0.127567
# ROC 넓이와 PR 넓이가 거의 안 바뀝니다. 순위는 그대로입니다
# 바뀌는 것은 평균 예측 확률입니다. 0.022275 에서 0.14 근처로 여섯 배 넘게 오릅니다
# 재표집이 하는 일은 문턱을 옮기는 것과 사실상 같습니다
# 문턱을 옮긴 것과 견줍니다
# 무엇을 했나 문턱 재현율 정밀도
# 그대로 0.5 문턱 0.500000 0.275000 0.622642
# 그대로 비율 문턱 0.020000 0.941667 0.133570
# 늘리고 0.5 문턱 0.500000 0.908333 0.153090
# 아래 두 줄이 거의 같습니다. 같은 자리를 다른 길로 간 것입니다
# 재표집은 자료를 바꾸고 문턱 옮기기는 판정을 바꿉니다
# 결과가 같다면 자료를 안 바꾸는 쪽이 낫습니다. 확률이 안 망가집니다
# SMOTE 가 만드는 점이 어디에 놓이는지 봅니다
# 무엇 값 무엇을 뜻하나
# 원래 양성의 평균 판별값 3.198888 참 양성 영역
# 만든 점의 평균 판별값 3.184276 안쪽으로 몰림
# 만든 점의 판별값 표준편차 0.887733 원래보다 좁음
# 원래 양성의 판별값 표준편차 1.012029 기준
# 평균은 거의 같고 표준편차만 좁아집니다
# 보간한 점은 원래 점들 사이에 놓이므로 바깥으로 안 나갑니다
# 새 정보를 만든 것이 아니라 있던 것을 채운 것입니다
# 그래서 순위가 거의 안 바뀝니다. 앞의 표가 그 결과입니다
# 자료 대신 손실에 무게를 겁니다
# 무엇 어떻게 무엇과 같은가
# 갈래 가중 드문 쪽 손실에 곱 적은 쪽 늘리기
# 표본 가중 관측마다 다른 무게 가중 재표집
# 초점 손실 쉬운 것의 무게를 낮춤 어려운 것에 집중
# 비용 민감 문턱 판정만 바꿈 226강 문제 2
# 첫 줄과 셋째 줄이 정말 같은지 확인합니다
# 갈래 가중을 바꿔 가며 잽니다
# 양성 무게 ROC 넓이 PR 넓이 평균 예측 확률 0.5 문턱 재현율
# 1 0.963367 0.471941 0.022275 0.275000
# 5 0.963617 0.472369 0.054818 0.591667
# 20 0.963968 0.471994 0.103114 0.841667
# 49 0.964055 0.472408 0.142739 0.925000
# 무게를 49 로 두면 양성 비율 0.02 가 균형에 가깝게 맞춰집니다
# ROC 넓이는 거의 안 바뀌고 평균 예측 확률만 올라갑니다
# 재표집과 같은 그림입니다. 셋 다 순위를 안 바꿉니다
# 세 방법의 계수를 직접 견줍니다
# 무엇 첫 계수 둘째 계수 절편 첫 계수의 비
# 그대로 2.530435 -1.425543 -7.231169 1.000000
# 가중 49 3.290318 -1.974509 -4.804096 1.300298
# 적은 쪽 늘리기 3.344434 -2.000384 -4.910217 1.321683
# 기울기 계수는 1.3 배 안쪽이고 절편은 2.4 나 옮겨집니다
# 절편이 곧 문턱입니다. 208강에서 절편이 전체 수준이라 했습니다
# 그래서 셋이 같은 직선을 다른 자리에 놓는 것입니다
# 확률이 얼마나 망가지는지 봅니다
# 무엇 브라이어 점수 평균 예측 확률 실제 비율과의 차
# 그대로 0.014171 0.022275 0.002275
# 가중 49 0.077232 0.142739 0.122739
# 적은 쪽 늘리기 0.076217 0.140476 0.120476
# 실제 양성 비율은 0.020000 입니다
# 가중은 평균 예측 확률을 0.020000 에서 0.142739 로 일곱 배 부풀립니다
# 226강 문제 2 의 비용 문턱을 쓰려면 이 확률로는 안 됩니다
# 부풀린 확률을 되돌리는 공식을 확인합니다
# 학습 비율과 실제 비율의 차이를 절편에서 빼면 됩니다
# 무엇 평균 예측 확률 브라이어 점수
# 가중 49 그대로 0.142739 0.077232
# 절편을 되돌린 뒤 0.025751 0.015494
# 처음부터 가중 없이 0.022275 0.014171
# 되돌리면 가중 없이 학습한 것과 거의 같아집니다
# 216강 문제 1 의 사전확률을 바꿔 끼우는 것과 같은 계산입니다
# 네 가지를 같은 자료에서 견줍니다
# 무엇 PR 넓이 가장 좋은 F1 그때 문턱
# 그대로 0.471941 0.460937 0.255000
# 가중 49 0.472408 0.475410 0.970000
# 적은 쪽 늘리기 0.473122 0.471545 0.970000
# SMOTE 0.472171 0.471545 0.975000
# 가장 좋은 F1 이 넷 다 비슷합니다. 문턱만 다릅니다
# 문턱을 제대로 고르면 무엇을 했든 같은 자리에 갑니다
# 그러면 무엇이 실제로 도움이 되는지 다음에서 봅니다
# 정말 도움이 되는 것을 찾습니다
# 무엇을 바꿨나 PR 넓이 그대로 대비
# 그대로 0.471941 0.000000
# 자료를 네 배로 0.467837 -0.004104
# 변수를 늘림 0.472661 0.000719
# 벌점을 넣음 0.473605 0.001664
# 갈래가 더 잘 갈림 0.694086 0.222144
# 갈래가 잘 갈리는 것만 크게 듭니다. 0.222144 오릅니다
# 자료를 네 배로 늘려도 0.004104 나빠집니다. 이미 양성이 충분했기 때문입니다
# 변수를 늘리거나 벌점을 넣는 것도 0.002 안쪽입니다. 사실상 제자리입니다
# 참 경계가 직선이라 더할 것도 뺄 것도 없기 때문입니다
# 재표집과 가중도 앞 표에서 봤듯 거의 안 듭니다
# 결국 자료와 변수가 좋아야 합니다. 손잡이 조정으로는 안 됩니다
# 드문 쪽이 여러 덩어리로 흩어져 있으면 어떤지 봅니다
# 양성이 세 덩어리로 흩어져 있습니다
# 무엇 PR 넓이 ROC 넓이
# 로지스틱 0.287954 0.634899
# 제곱 항을 넣음 0.609106 0.955146
# 양성 대 음성 이웃 거리 차 0.597103 0.955818
# 직선 모형은 PR 넓이 0.287954 로 흩어진 양성을 못 잡습니다
# 제곱 항을 넣으면 0.609106 으로 뜁니다. 세 덩어리가 원점에서 떨어져 있기 때문입니다
# 이웃 거리 차이도 직선보다 낫습니다. 모양을 안 가정하기 때문입니다
# 치우침이 문제가 아니라 모형이 모양을 못 담은 것입니다
# 교차검증에서 무엇을 조심해야 하는지 봅니다
# 무엇 무엇이 문제인가 어떻게
# 겹마다 양성이 0 개 지표를 못 잼 층화 겹
# 재표집을 먼저 하면 같은 점이 양쪽에 겹 안에서만
# SMOTE 를 먼저 하면 만든 점이 검증에 겹 안에서만
# 문턱을 검증에서 고르면 낙관 따로 뗀 자료로
# 212강 문제 4 의 누출이 여기서는 재표집을 통해 들어옵니다
# 재표집을 겹 밖에서 하면 얼마나 낙관되는지 잽니다
# 이웃 방법으로 봅니다. 복사된 점이 검증에 들어가면 자기를 찾습니다
# 언제 재표집했나 교차검증 ROC 넓이 따로 뗀 자료 대비
# 겹을 나누기 전에 0.993220 0.228270
# 겹 안에서 0.718557 -0.046392
# 따로 뗀 자료에서의 값은 0.764950 입니다
# 먼저 늘리면 같은 점이 학습과 검증에 함께 들어가 크게 낙관됩니다
# 겹 안에서 하면 정직한 값이 나옵니다
# 로지스틱처럼 매끄러운 모형은 이 누출이 작습니다. 외울 수가 없기 때문입니다
# 층화가 왜 필요한지 봅니다
# 양성이 40 개뿐인 자료로 봅니다
# 겹 수 무작위 겹의 최소 양성 수 층화 겹의 최소 양성 수 양성 0 인 겹 비율
# 5 5.300000 8.000000 0.000000
# 10 1.075000 4.000000 0.175000
# 20 0.025000 2.000000 0.975000
# 40 0.000000 1.000000 1.000000
# 겹을 40 개로 하면 무작위로는 양성이 0 인 겹이 자주 생깁니다
# 층화하면 겹마다 최소 개수가 보장됩니다
# 212강 심화 3 의 층화 겹이 여기서 필수가 됩니다
# 실무 절차를 정리합니다
# 순서 무엇을 하나
# 먼저 물어보기 정말 치우침이 문제인가
# 드문 쪽 개수 세기 비율이 아니라 개수
# 문턱부터 옮겨 보기 가장 싸고 대개 충분
# 그래도 모자라면 자료를 늘리거나 변수를 고침
# 재표집은 마지막에 확률이 망가짐
# 셋째 줄이 이 강의의 결론입니다
# 227강은 치우친 자료를 봤습니다. 228강은 변수를 만듭니다