강부터 강까지 네 강의가 자료의 큰 흐름을 봤습니다. 덩어리를 찾고 축을 갈아탔습니다. 이 강의는 반대입니다.
분류처럼 보이지만 결정적으로 다릅니다. 이상은 종류가 정해져 있지 않습니다. 지금까지 본 적 없는 방식으로 이상할 수 있습니다.
그러면 강부터 강까지 만든 도구가 전부 쓰입니다. 밀도, 거리, 나무가 모두 **"정상이 어떻게 생겼는지"**를 적는 방법이기 때문입니다.
문제. 문제를 정의합니다.
() 분류와 무엇이 다른지 정리하세요.
() 이상의 종류를 나누세요.
() 변수를 따로 볼 때와 함께 볼 때를 견주세요.
생각의 실마리. 이상탐지에는 이상 자료가 거의 없습니다. 있어도 앞으로 올 이상과 같은 종류라는 보장이 없습니다. 그래서 정상만 보고 배웁니다.
풀이. () 정리합니다.
| 무엇 | 분류 | 이상탐지 |
|---|---|---|
| 라벨 | 양쪽 다 있음 | 대개 정상만 |
| 갈래 비율 | 비슷하거나 치우침 | 아주 치우침 |
| 이상의 모양 | 학습 자료에 있음 | 미리 모름 |
| 무엇을 배우나 | 경계 | 정상의 모양 |
| 새 이상 | 못 잡을 수 있음 | 잡을 수 있음 |
셋째 줄이 결정적입니다. 이상은 종류가 정해져 있지 않으므로 경계를 배우면 새 종류를 놓칩니다.
() 이상의 종류를 나눕니다.
| 종류 | 무엇인가 | 어떻게 찾나 |
|---|---|---|
| 점 이상 | 혼자 동떨어짐 | 밀도나 거리 |
| 맥락 이상 | 그 상황에서만 이상 | 조건부로 봄 |
| 모임 이상 | 묶음 전체가 이상 | 묶음 단위로 |
| 드문 갈래 | 정상인데 드묾 | 이상이 아님 |
마지막 줄을 조심해야 합니다. 드문 것과 이상한 것은 다릅니다. 왼손잡이는 드물지만 이상이 아닙니다.
() 변수를 따로 볼 때와 함께 볼 때를 견줍니다. 두 변수가 상관 인 자료에 이상점 넷을 넣습니다.
| 점 | 첫 변수 값 | 둘째 변수 값 | 마할라노비스 거리 | 이상인가 |
|---|---|---|---|---|
| 보통 점 | 아니오 | |||
| 첫 이상점 | 예 | |||
| 둘째 이상점 | 예 | |||
| 셋째 이상점 | 예 | |||
| 넷째 이상점 | 예 |
네 이상점 모두 변수 하나씩만 보면 값이 를 안 넘습니다. 셋째와 넷째는 도 안 됩니다.
그런데 마할라노비스 거리는 에서 입니다. 상관 를 어겼기 때문입니다.
| 방법 | 네 이상점을 몇 개 잡나 | AUC |
|---|---|---|
| 변수마다 값 | ||
| 마할라노비스 거리 |
상관을 쓰면 넷을 다 잡고 안 쓰면 하나도 못 잡습니다.
강의 마할라노비스 거리가 공분산을 나눠 준 거리입니다. 강에서 거리가 곧 가정이라 한 것이 여기서도 그대로입니다.
이 문제에서 배우는 것. 이상은 변수 하나하나가 아니라 변수들의 관계에서 나타날 수 있습니다. 각 변수를 따로 감시하는 것으로는 못 잡고, 정상의 모양을 통째로 적어야 합니다.
확인 1-1. 이상탐지가 분류와 다른 점 하나를 쓰세요.
답. 이상의 종류가 정해져 있지 않아 정상만 보고 배웁니다.
확인 1-2. 검산에서 셋째 이상점의 두 값과 마할라노비스 거리를 쓰세요.
답. 와 이고 거리는 입니다.
확인 1-3. 검산에서 두 방법이 잡은 이상점 수를 쓰세요.
답. 개와 개입니다.
문제. 밀도를 세워 찾습니다.
() 네 가지 점수를 견주세요.
() 덩어리 사이 빈 곳을 어떻게 보는지 확인하세요.
() 무엇이 정상인지를 무엇이 정하는지 정리하세요.
생각의 실마리. 강에서 혼합모형이 를 준다고 했습니다. 밀도가 낮은 곳이 이상이라고 정의하면 바로 이상탐지가 됩니다.
풀이. () 덩어리 둘짜리 자료에 멀리 떨어진 점 개를 넣고 잽니다.
| 방법 | AUC | 상위 퍼센트 재현율 | 정밀도 |
|---|---|---|---|
| 정규분포 하나 | |||
| 혼합모형 둘 | |||
| 번째 이웃 거리 | |||
| 국소 이상 인자 |
정규분포 하나는 AUC가 로 셋보다 낮습니다. 덩어리가 둘인데 하나로 보기 때문입니다.
() 덩어리 사이 빈 곳을 어떻게 보는지 확인합니다. 두 덩어리의 정확히 가운데 점 하나를 봅니다.
| 방법 | 그 점의 점수 | 학습 자료의 몇 퍼센트 위 |
|---|---|---|
| 정규분포 하나 | ||
| 혼합모형 둘 | ||
| 번째 이웃 거리 |
정규분포 하나로 보면 그 점이 학습 자료의 퍼센트 자리로 가장 정상입니다. 두 덩어리의 평균이 정확히 그곳이기 때문입니다.
혼합모형과 이웃 거리로 보면 퍼센트 자리로 아주 드문 자리입니다.
같은 점을 두고 정반대로 판단합니다.
() 무엇이 정상인지를 무엇이 정하는지 정리합니다.
모형이 정합니다. 정규분포 하나를 가정하면 "평균 근처가 정상"이고, 혼합모형을 가정하면 "덩어리 안이 정상"입니다.
강 문제 에서 본 밀도 쓰임이 이것입니다. 그리고 밀도 모형을 잘못 고르면 이상 판정이 뒤집힙니다.
이 문제에서 배우는 것. 이상탐지는 정상의 정의에 전적으로 딸립니다. 그 정의가 모형이고, 모형이 틀리면 정상과 이상이 뒤바뀝니다. 그래서 자료를 먼저 보고 모형을 골라야 합니다.
확인 2-1. 밀도 기반 이상탐지가 무엇을 이상이라 보는지 쓰세요.
답. 밀도가 낮은 곳의 점을 이상이라 봅니다.
확인 2-2. 검산에서 정규분포 하나와 혼합모형 둘의 AUC를 쓰세요.
답. 와 입니다.
확인 2-3. 검산에서 가운데 점이 두 모형에서 몇 퍼센트 자리인지 쓰세요.
답. 과 입니다.
문제. 거리 기반 방법을 봅니다.
() 밀도가 다른 곳에서 무엇이 어려운지 보세요.
() 두 방법을 여러 자료에서 견주세요.
() 어느 쪽을 쓸지 정하는 기준을 세우세요.
생각의 실마리. 강 문제 에서 밀도가 다르면 반경 하나로 못 잡는다고 했습니다. 이상탐지에서도 같은 문제가 생깁니다.
풀이. () 빽빽한 덩어리와 성긴 덩어리를 놓고 각각에서 같은 정도로 떨어진 점을 봅니다.
| 점 | 자기 덩어리 표준편차 대비 | 번째 이웃 거리 | 국소 이상 인자 |
|---|---|---|---|
| 빽빽한 쪽에서 시그마 | |||
| 성긴 쪽에서 시그마 |
이웃 거리로 보면 성긴 쪽 점이 로 더 이상해 보입니다. 자기 덩어리 기준으로는 시그마뿐인데도 그렇습니다.
국소 이상 인자는 빽빽한 쪽을 로 더 이상하다고 봅니다. 자기 이웃의 밀도로 나누므로 눈금이 맞춰지기 때문입니다.
강 문제 의 밀도가 다른 문제가 여기서도 나옵니다.
() 두 방법을 여러 자료에서 견줍니다.
| 자료 | 이웃 거리 AUC | 국소 이상 인자 AUC | 어느 쪽이 나은가 |
|---|---|---|---|
| 밀도가 고름 | 이웃 거리 | ||
| 밀도가 다름 | 이웃 거리 | ||
| 작은 덩어리가 섞임 | 국소 이상 인자 |
세 자료 모두에서 이웃 거리가 낫거나 같습니다. 통념과 다릅니다.
이상점을 덩어리 바깥 먼 곳에 두었으므로 국소 눈금을 맞출 이유가 없습니다. 멀리 있는 점은 어느 눈금으로 봐도 멉니다.
국소 이상 인자가 이기는 자리는 앞 표처럼 빽빽한 덩어리 가장자리입니다. 그런 점은 절대 거리로는 가까운데 자기 이웃 기준으로는 멉니다.
() 기준을 세웁니다.
어느 쪽이 나은지는 이상이 어디에 있느냐가 정합니다. 덩어리 바깥 먼 곳이면 거리로 충분하고, 덩어리 가장자리에 숨어 있으면 국소 눈금이 필요합니다.
이 문제에서 배우는 것. "국소 밀도로 나누는 것이 언제나 낫다"는 흔한 믿음이 자료에 따라 틀립니다. 라벨이 없으므로 어느 쪽이 맞는지 확인할 방법도 없고, 그래서 무엇을 이상으로 볼지를 먼저 정해야 합니다.
확인 3-1. 국소 이상 인자가 무엇으로 나누는지 쓰세요.
답. 자기 이웃들의 국소 밀도로 나눕니다.
확인 3-2. 검산에서 빽빽한 쪽 점의 두 점수를 쓰세요.
답. 이웃 거리 과 국소 이상 인자 입니다.
확인 3-3. 검산에서 밀도가 다른 자료의 두 AUC를 쓰세요.
답. 와 입니다.
문제. 고립 숲을 봅니다.
() 원리를 정리하고 경로 길이를 재세요.
() 차원이 오를 때 세 방법을 견주세요.
() 잡음 변수를 섞어 보세요.
생각의 실마리. 이상점은 적고 다릅니다. 무작위로 자르면 몇 번 만에 혼자 남습니다. 밀도를 안 세고 갈리는 빠르기만 보면 됩니다.
풀이. () 정리합니다.
| 무엇 | 정상점 | 이상점 |
|---|---|---|
| 무작위로 자르면 | 여러 번 잘라야 갈림 | 몇 번에 갈림 |
| 나무에서의 깊이 | 깊음 | 얕음 |
| 점수 | 낮음 | 높음 |
| 밀도를 세나 | 아니오 | 아니오 |
| 어떤 점 | 평균 경로 길이 | 점수 | 몇 개 |
|---|---|---|---|
| 정상점 | |||
| 이상점 |
이상점이 평균 단계나 얕은 자리에서 갈립니다. 점수가 과 입니다.
근처면 정상이고 에 가까우면 이상입니다. 정규화 상수 이 무작위 이진 탐색의 평균 깊이라서 그렇습니다.
() 차원이 오를 때 세 방법을 견줍니다. 이상이 한 방향으로만 뚜렷한 경우입니다.
| 차원 | 혼합모형 AUC | 이웃 거리 AUC | 고립 숲 AUC |
|---|---|---|---|
혼합모형과 이웃 거리는 차원 에서도 를 넘습니다.
고립 숲은 에서 으로 무너집니다. 우연 수준입니다. 한 방향으로만 다른 이상은 무작위 축으로 자르기가 점점 어려워지기 때문입니다. 축 개 중 쓸모 있는 것이 하나뿐입니다.
이상이 모든 방향으로 조금씩 다르면 반대가 됩니다.
| 차원 | 혼합모형 AUC | 이웃 거리 AUC | 고립 숲 AUC |
|---|---|---|---|
차원이 오를수록 오히려 잡기 쉬워집니다. 조금씩의 차이가 쌓이기 때문이고, 강 문제 에서 거리가 로 자란다고 한 것이 여기서는 도움이 됩니다.
() 잡음 변수를 섞어 봅니다. 이상은 앞 두 변수에만 있습니다.
| 잡음 변수 수 | 혼합모형 AUC | 이웃 거리 AUC | 고립 숲 AUC |
|---|---|---|---|
잡음 변수 개를 섞으면 셋 다 떨어지고 고립 숲은 으로 무너집니다.
이상은 두 변수에만 있는데 거리와 나눔이 잡음에 끌려다닙니다. 강 문제 와 강 문제 에서 본 것과 같은 문제입니다.
이 문제에서 배우는 것. 고립 숲은 빠르고 밀도를 안 세지만 축에 딸립니다. 쓸모 있는 축이 적으면 무작위 자름이 헛돕니다. 그리고 세 방법 모두 변수 선택이 성능을 좌우합니다.
확인 4-1. 고립 숲이 무엇을 점수로 쓰는지 쓰세요.
답. 무작위로 자를 때 혼자 남기까지의 평균 경로 길이입니다.
확인 4-2. 검산에서 정상점과 이상점의 평균 경로 길이를 쓰세요.
답. 와 입니다.
확인 4-3. 검산에서 차원 일 때 고립 숲의 두 AUC를 쓰세요.
답. 한 방향 이상에서 이고 모든 방향 이상에서 입니다.
문제. 실제로 씁니다.
() 문턱을 정하는 방법을 정리하세요.
() 학습 자료에 이상이 섞이면 어떻게 되는지 보세요.
() 여러 방법을 합쳐 보세요.
생각의 실마리. 점수를 냈으면 어디서 자를지를 정해야 합니다. 라벨이 없으므로 강의 교차검증을 못 씁니다.
풀이. () 정리합니다.
| 방법 | 무엇으로 정하나 | 무엇이 문제인가 |
|---|---|---|
| 고정 비율 | 상위 몇 퍼센트 | 실제 비율을 모름 |
| 분포 가정 | 카이제곱 분위수 | 가정이 틀리면 |
| 검증 자료 | 라벨 조금 | 라벨이 필요 |
| 비용으로 | 놓침과 헛경보의 값 | 가장 정직함 |
| 극단값 이론 | 꼬리를 따로 맞춤 | 꼬리 자료가 적음 |
문턱을 옮기면 무엇이 맞바뀌는지 잽니다.
| 상위 몇 퍼센트 | 잡은 이상 수 | 재현율 | 정밀도 | 헛경보 수 |
|---|---|---|---|---|
상위 퍼센트만 보면 헛경보가 인데 이상의 퍼센트만 잡습니다.
퍼센트로 넓히면 다 잡지만 헛경보가 건입니다. 퍼센트에서는 건으로 열다섯 배가 됩니다.
문턱을 낮추면 더 잡지만 헛경보가 훨씬 빨리 늡니다. 강의 ROC 곡선이 이 맞바꿈을 그림으로 보여 줍니다.
() 학습 자료에 이상이 섞이면 어떻게 되는지 봅니다.
| 학습에 섞인 이상 비율 | AUC | 상위 퍼센트 재현율 | 떨어진 정도 |
|---|---|---|---|
퍼센트가 섞여도 AUC가 로 거의 안 흔들립니다.
퍼센트에서 로 떨어지고 재현율도 이 됩니다. 모형이 그 이상들을 정상으로 배우기 시작하기 때문입니다.
그런데 퍼센트에서 로 돌아옵니다. 오염이 늘어난다고 단조로 나빠지지는 않습니다. 섞인 이상들이 서로 흩어져 있으면 모형이 덩어리로 안 잡기 때문입니다.
섞인 이상이 한곳에 모여 있을 때가 가장 위험합니다. 그때 모형이 그것을 정상 덩어리 하나로 배웁니다.
() 여러 방법을 합쳐 봅니다. 잡음 변수 개를 섞어 어렵게 만든 자료입니다.
| 무엇 | AUC | 상위 퍼센트 재현율 |
|---|---|---|
| 혼합모형 | ||
| 이웃 거리 | ||
| 국소 이상 인자 | ||
| 고립 숲 | ||
| 넷의 순위 평균 |
순위 평균은 가장 좋은 혼합모형의 보다는 낮습니다.
그런데 가장 나쁜 고립 숲의 보다는 훨씬 높습니다. 어느 방법이 좋을지 미리 모를 때 안전한 선택입니다.
라벨이 없으므로 어느 것이 좋은지 고를 수가 없습니다. 그것이 이상탐지의 어려움이고, 강의 앙상블과 같은 생각으로 대응합니다.
실무 절차를 정리합니다.
| 순서 | 무엇을 하나 |
|---|---|
| 무엇이 이상인지 정의 | 종류와 비용을 먼저 정함 |
| 변수를 고름 | 쓸모없는 것이 치명적 |
| 표준화 | 거리를 쓰는 방법은 다 필요 |
| 여러 방법을 함께 | 잡는 것이 서로 다름 |
| 문턱은 비용으로 | 강의 불균형 문제 |
이 문제에서 배우는 것. 이상탐지의 가장 어려운 점은 잘했는지 알 수 없다는 것입니다. 라벨이 없으므로 방법도 문턱도 못 고릅니다. 그래서 여러 방법을 함께 쓰고 문턱은 비용으로 정하는 것이 실무의 답입니다.
확인 5-1. 이상탐지에서 문턱을 교차검증으로 못 고르는 이유를 쓰세요.
답. 라벨이 없어 무엇이 맞는지 잴 수 없기 때문입니다.
확인 5-2. 검산에서 상위 퍼센트와 퍼센트의 재현율과 헛경보 수를 쓰세요.
답. 에 건, 에 건입니다.
확인 5-3. 검산에서 순위 평균의 AUC와 가장 나쁜 방법의 AUC를 쓰세요.
답. 과 입니다.
| 유형 | 무엇을 묻나 | 어디를 보나 |
|---|---|---|
| 분류와의 차이 | 이상의 종류를 모름 | 문제 |
| 마할라노비스 | 상관을 어긴 이상 | 문제 |
| 밀도 기반 | 무엇이 정상인가 | 문제 |
| 모형이 답을 정함 | 가운데 점이 뒤집힘 | 문제 |
| 국소 이상 인자 | 이웃 밀도로 나눔 | 문제 |
| 어느 쪽이 나은가 | 이상이 어디 있느냐 | 문제 |
| 고립 숲 | 경로 길이 | 문제 |
| 축에 딸림 | 한 방향 이상에 약함 | 문제 |
| 문턱 | 재현율과 헛경보 | 문제 |
| 앙상블 | 못 고를 때 안전 | 문제 |
핵심 식을 한자리에 모읍니다.
| 방법 | 무엇을 가정 | 강한 자리 | 약한 자리 |
|---|---|---|---|
| 마할라노비스 | 정규분포 하나 | 상관 어김 | 덩어리 여럿 |
| 혼합모형 | 정규분포 여럿 | 밀도가 필요할 때 | 모양이 정규가 아님 |
| 이웃 거리 | 없음 | 덩어리 바깥 | 밀도가 다름 |
| 국소 이상 인자 | 없음 | 덩어리 가장자리 | 계산이 무거움 |
| 고립 숲 | 없음 | 저차원과 빠름 | 한 방향 이상 |
문제 6. 이상탐지가 분류와 다른 점 하나를 쓰세요.
답. 이상의 종류가 정해져 있지 않아 정상만 보고 배웁니다.
문제 7. 검산에서 셋째 이상점의 두 값과 마할라노비스 거리를 쓰세요.
답. 와 이고 거리는 입니다.
문제 8. 검산에서 두 방법이 잡은 이상점 수를 쓰세요.
답. 개와 개입니다.
문제 9. 검산에서 정규분포 하나와 혼합모형 둘의 AUC를 쓰세요.
답. 와 입니다.
문제 10. 검산에서 가운데 점이 두 모형에서 몇 퍼센트 자리인지 쓰세요.
답. 과 입니다.
문제 11. 검산에서 빽빽한 쪽 점의 두 점수를 쓰세요.
답. 이웃 거리 과 국소 이상 인자 입니다.
문제 12. 검산에서 밀도가 다른 자료의 두 AUC를 쓰세요.
답. 와 입니다.
문제 13. 검산에서 정상점과 이상점의 평균 경로 길이를 쓰세요.
답. 와 입니다.
문제 14. 검산에서 차원 일 때 고립 숲의 두 AUC를 쓰세요.
답. 한 방향 이상에서 이고 모든 방향 이상에서 입니다.
문제 15. 검산에서 잡음 변수 개일 때 세 방법의 AUC를 쓰세요.
답. 과 과 입니다.
문제 16. 검산에서 상위 퍼센트와 퍼센트의 재현율과 헛경보 수를 쓰세요.
답. 에 건, 에 건입니다.
문제 17. 검산에서 학습에 이상이 퍼센트 섞였을 때의 재현율을 쓰세요.
답. 입니다.
문제 18. 검산에서 순위 평균의 AUC와 가장 나쁜 방법의 AUC를 쓰세요.
답. 과 입니다.
심화 1. 마할라노비스 거리의 분포를 정리하세요.
가 차원 정규분포를 따르고 모수를 알면 이렇습니다.
| 무엇 | 값 |
|---|---|
| 차원 의 퍼센트 분위 | |
| 차원 의 퍼센트 분위 | |
| 모수를 추정하면 | 분포로 보정 |
| 표본이 적으면 | 이상점이 자기 거리를 줄임 |
넷째 줄이 함정입니다. 이상점이 평균과 공분산 추정에 끼어들어 자기 거리를 작게 만듭니다. 그래서 최소 공분산 행렬식 같은 튼튼한 추정을 씁니다.
심화 2. 한 갈래 서포트 벡터 머신을 정리하세요.
| 무엇 | 뜻 |
|---|---|
| 원점에서 떨어뜨림 | 정상을 한쪽으로 몰음 |
| 이상으로 볼 비율의 상계 | |
| 커널 | 강의 그것 |
| 결과 | 정상 영역의 경계 |
강의 여백 최대 경계를 한 갈래에 쓴 것입니다. 원점을 유일한 이상점으로 두고 나머지를 최대한 멀리 떨어뜨립니다. 가우스 커널을 쓰면 밀도 추정과 비슷해집니다.
심화 3. 재구성 오차로 이상을 찾는 방법을 정리하세요.
| 방법 | 무엇으로 복원 | 이상 점수 |
|---|---|---|
| 주성분 | 앞 몇 성분 | 복원 오차 |
| 오토인코더 | 좁은 층 | 복원 오차 |
| 행렬 분해 | 저랭크 근사 | 잔차 |
강 문제 의 복원 오차가 그대로 점수가 됩니다. 정상은 낮은 차원 구조 위에 있으므로 잘 복원되고, 이상은 그 구조 밖이라 복원이 안 됩니다. S의 오토인코더가 이 생각을 신경망으로 밀어붙인 것입니다.
심화 4. 시계열에서의 이상탐지를 정리하세요.
| 무엇 | 어떻게 |
|---|---|
| 점 이상 | 예측값과의 차 |
| 수준 변화 | 구간별 평균 비교 |
| 계절성 깨짐 | 잔차의 계절 성분 |
| 맥락 이상 | 같은 시각대와 비교 |
강의 예측 잔차가 곧 이상 점수입니다. 그리고 자기상관 때문에 이웃한 시점을 독립으로 보면 안 됩니다. 강 문제 의 시계열 나누기가 여기서도 필요합니다.
심화 5. 이상탐지의 평가를 정리하세요.
| 지표 | 무엇을 재나 | 언제 쓰나 |
|---|---|---|
| AUC | 순위의 질 | 문턱 없이 |
| PR 곡선 아래 넓이 | 드문 쪽 중심 | 비율이 아주 치우칠 때 |
| 상위 정밀도 | 실제 확인할 수 있는 수 | 사람이 검토할 때 |
| 재현율 | 놓친 비율 | 놓치면 큰일일 때 |
둘째 줄이 중요합니다. 이상이 퍼센트면 AUC가 여도 상위 개 중 절반이 헛경보일 수 있습니다. 강에서 이 차이를 자세히 봅니다.
심화 6. 언제 어느 방법을 쓸지 정리하세요.
| 상황 | 무엇을 쓰나 | 왜 |
|---|---|---|
| 변수가 적고 정규에 가까움 | 마할라노비스 | 닫힌 식이고 해석됨 |
| 덩어리가 여럿 | 혼합모형 | 밀도를 제대로 |
| 모양을 모르고 표본이 적음 | 이웃 거리 | 가정이 없음 |
| 표본이 아주 많음 | 고립 숲 | 가장 빠름 |
| 무엇을 쓸지 모르겠음 | 여럿의 순위 평균 | 문제 |
마지막 줄이 실무의 현실입니다. 라벨이 없어 고를 수 없으므로 여럿을 함께 돌리고 순위를 합치는 것이 안전합니다.
정답.
| 기호 | 읽는 법 | 뜻 |
|---|---|---|
| 이상탐지 | anomaly detection | 흐름에서 벗어난 것을 찾습니다 |
| 마할라노비스 거리 | Mahalanobis distance | 공분산으로 나눈 거리입니다 |
| 국소 이상 인자 | local outlier factor | 이웃 밀도로 나눈 점수입니다 |
| 고립 숲 | isolation forest | 무작위로 잘라 혼자 남기까지의 깊이입니다 |
| 경로 길이 | path length | 나무에서 그 점까지의 깊이입니다 |
| 한 갈래 SVM | one-class SVM | 정상 영역의 경계를 긋습니다 |
| 재구성 오차 | reconstruction error | 줄였다 되돌렸을 때의 차이입니다 |
| 오염 | contamination | 학습 자료에 섞인 이상의 비율입니다 |
| 헛경보 | false alarm | 정상을 이상이라 한 것입니다 |
| 극단값 이론 | extreme value theory | 꼬리 분포를 따로 모형화합니다 |
단원이 여기서 끝납니다. 강부터 다섯 강의가 라벨 없이 무엇을 할 수 있는지를 봤습니다. 덩어리를 찾고, 모양을 확률로 적고, 축을 갈아타고, 드문 것을 찾았습니다. 강부터는 다시 라벨이 있습니다. 다만 이번에는 모형을 만드는 것이 아니라 재고 고르고 해석하는 일입니다.
import numpy as np
rng = np.random.default_rng(20270124)
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 d2(A, B):
return ((A[:, None, :] - B[None, :, :]) ** 2).sum(axis=2)
def auc(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 maha(X, mu, S):
L = np.linalg.cholesky(S)
z = np.linalg.solve(L, (X - mu).T)
return (z ** 2).sum(axis=0)
def knn_score(Xtr, Xq, k=10):
D = np.sqrt(d2(Xq, Xtr))
return np.sort(D, axis=1)[:, k - 1]
def lof(Xtr, Xq, k=10):
Dtr = np.sqrt(d2(Xtr, Xtr))
np.fill_diagonal(Dtr, np.inf)
kd_tr = np.sort(Dtr, axis=1)[:, k - 1]
nb_tr = np.argsort(Dtr, axis=1)[:, :k]
lrd_tr = np.zeros(len(Xtr))
for i in range(len(Xtr)):
rd = np.maximum(kd_tr[nb_tr[i]], Dtr[i, nb_tr[i]])
lrd_tr[i] = 1.0 / (rd.mean() + 1e-12)
Dq = np.sqrt(d2(Xq, Xtr))
kd_q = np.sort(Dq, axis=1)[:, k - 1]
nb_q = np.argsort(Dq, axis=1)[:, :k]
out = np.zeros(len(Xq))
for i in range(len(Xq)):
rd = np.maximum(kd_tr[nb_q[i]], Dq[i, nb_q[i]])
lrd = 1.0 / (rd.mean() + 1e-12)
out[i] = lrd_tr[nb_q[i]].mean() / (lrd + 1e-12)
return out
def iforest_fit(X, B=100, sub=128, r=None):
trees = []
n, d = X.shape
for _ in range(B):
idx = r.permutation(n)[:min(sub, n)]
trees.append(build_itree(X[idx], 0, int(np.ceil(np.log2(len(idx)))), r))
return trees
def build_itree(X, depth, lim, r):
n = len(X)
if depth >= lim or n <= 1:
return ("leaf", n)
lo = X.min(axis=0)
hi = X.max(axis=0)
ok = np.where(hi > lo)[0]
if len(ok) == 0:
return ("leaf", n)
j = int(r.choice(ok))
t = float(r.uniform(lo[j], hi[j]))
m = X[:, j] < t
if m.all() or (~m).all():
return ("leaf", n)
return ("node", j, t, build_itree(X[m], depth + 1, lim, r),
build_itree(X[~m], depth + 1, lim, r))
def cfun(n):
if n <= 1:
return 0.0
return 2.0 * (np.log(n - 1) + 0.5772156649) - 2.0 * (n - 1) / n
def path_len(tree, x, depth=0):
if tree[0] == "leaf":
return depth + cfun(tree[1])
j, t = tree[1], tree[2]
return path_len(tree[3] if x[j] < t else tree[4], x, depth + 1)
def iforest_score(trees, Xq, sub=128):
h = np.zeros(len(Xq))
for t in trees:
for i in range(len(Xq)):
h[i] += path_len(t, Xq[i])
h = h / len(trees)
return 2.0 ** (-h / cfun(sub))
# --- 문제 1: 무엇을 이상이라 부를 것인가 --------------------------------
print(" 221강부터 224강까지는 자료의 큰 흐름을 봤습니다")
print(" 이번에는 흐름에서 벗어난 드문 것을 찾습니다")
print(" %s %s %s"
% (pw("무엇", 22), rw("분류", 22), rw("이상탐지", 24)))
for a, b, c in [("라벨", "양쪽 다 있음", "대개 정상만"),
("갈래 비율", "비슷하거나 치우침", "아주 치우침"),
("이상의 모양", "학습 자료에 있음", "미리 모름"),
("무엇을 배우나", "경계", "정상의 모양"),
("새 이상", "못 잡을 수 있음", "잡을 수 있음")]:
print(" %s %s %s" % (pw(a, 22), rw(b, 22), rw(c, 24)))
print(" 셋째 줄이 결정적입니다. 이상은 종류가 정해져 있지 않습니다")
print(" 그래서 이상을 배우는 대신 정상을 배우고 벗어난 것을 찾습니다")
print(" 이상에도 종류가 있습니다")
print(" %s %s %s"
% (pw("종류", 20), rw("무엇인가", 26), rw("어떻게 찾나", 26)))
for a, b, c in [("점 이상", "혼자 동떨어짐", "밀도나 거리"),
("맥락 이상", "그 상황에서만 이상", "조건부로 봄"),
("모임 이상", "묶음 전체가 이상", "묶음 단위로"),
("드문 갈래", "정상인데 드묾", "이상이 아님")]:
print(" %s %s %s" % (pw(a, 20), rw(b, 26), rw(c, 26)))
print(" 마지막 줄을 조심해야 합니다. 드문 것과 이상한 것은 다릅니다")
print(" 가장 단순한 방법부터 봅니다")
n1 = 1000
X1 = np.zeros((n1, 2))
X1[:, 0] = rng.normal(0, 1, n1)
X1[:, 1] = 0.9 * X1[:, 0] + rng.normal(0, 0.4, n1)
out1 = np.array([[0.0, 2.4], [2.4, 0.0], [-1.8, 1.8], [1.8, -1.8]])
Xa = np.vstack([X1, out1])
ya = np.concatenate([np.zeros(n1), np.ones(4)])
mu1 = X1.mean(axis=0)
sd1 = X1.std(axis=0)
S1 = np.cov(X1.T)
print(" 두 변수가 상관 0.9 인 자료에 이상점 넷을 넣습니다")
print(" %s %s %s %s %s"
% (pw("점", 20), rw("첫 변수 z 값", 18), rw("둘째 변수 z 값", 20),
rw("마할라노비스 거리", 22), rw("이상인가", 14)))
zs = np.abs((Xa - mu1) / sd1)
md = np.sqrt(maha(Xa, mu1, S1))
for nm, i in [("보통 점", int(np.argmin(md[:n1]))),
("첫 이상점", n1), ("둘째 이상점", n1 + 1),
("셋째 이상점", n1 + 2), ("넷째 이상점", n1 + 3)]:
print(" %s %18.6f %20.6f %22.6f %s"
% (pw(nm, 20), zs[i, 0], zs[i, 1], md[i],
rw("예" if ya[i] == 1 else "아니오", 14)))
print(" 네 이상점 모두 변수 하나씩만 보면 z 값이 2.5 를 안 넘습니다")
print(" 그런데 마할라노비스 거리는 훨씬 큽니다. 상관 0.9 를 어겼기 때문입니다")
print(" 변수를 따로따로 보면 못 잡는 이상이 있습니다")
print(" 변수를 따로 볼 때와 함께 볼 때를 견줍니다")
print(" %s %s %s"
% (pw("방법", 26), rw("네 이상점을 몇 개 잡나", 26), rw("AUC", 14)))
thr_z = np.quantile(np.max(zs[:n1], axis=1), 0.99)
hit_z = int(np.sum(np.max(zs[n1:], axis=1) > thr_z))
thr_m = np.quantile(md[:n1], 0.99)
hit_m = int(np.sum(md[n1:] > thr_m))
print(" %s %26d %14.6f"
% (pw("변수마다 z 값", 26), hit_z, auc(np.max(zs, axis=1), ya)))
print(" %s %26d %14.6f"
% (pw("마할라노비스 거리", 26), hit_m, auc(md, ya)))
print(" 상관을 쓰면 넷을 다 잡고 안 쓰면 하나도 못 잡습니다")
print(" 137강의 마할라노비스 거리가 공분산을 나눠 준 거리입니다")
print(" 213강에서 거리가 곧 가정이라 한 것이 여기서도 그대로입니다")
# --- 문제 2: 밀도로 찾습니다 -------------------------------------------
print(" 223강의 혼합모형으로 밀도를 세워 찾습니다")
n2 = 800
z2 = (rng.uniform(0, 1, n2) < 0.4).astype(np.int64)
mu2 = np.array([[-2.0, 0.0], [2.5, 1.5]])
X2 = mu2[z2] + rng.normal(0, 0.7, (n2, 2))
Xo2 = np.stack([rng.uniform(-6, 6, 40), rng.uniform(-4, 6, 40)], axis=1)
keep = np.min(np.sqrt(d2(Xo2, mu2)), axis=1) > 2.3
Xo2 = Xo2[keep]
Xq2 = np.vstack([X2, Xo2])
yq2 = np.concatenate([np.zeros(n2), np.ones(len(Xo2))])
print(" 덩어리 둘짜리 자료에 멀리 떨어진 점 %d 개를 넣습니다" % len(Xo2))
def gmm_fit(X, k, r, iters=200, reg=1e-4):
n, d = X.shape
mu = X[r.permutation(n)[:k]].copy()
S = np.stack([np.cov(X.T) + reg * np.eye(d) for _ in range(k)])
pi = np.full(k, 1.0 / k)
for _ in range(iters):
LG = np.stack([-0.5 * (maha(X, mu[j], S[j])
+ np.log(np.linalg.det(S[j]))
+ d * np.log(2 * np.pi)) + np.log(pi[j])
for j in range(k)], axis=1)
m = LG.max(axis=1, keepdims=True)
R = np.exp(LG - m - np.log(np.exp(LG - m).sum(axis=1))[:, None])
Nk = R.sum(axis=0) + 1e-12
pi = Nk / n
mu = (R.T @ X) / Nk[:, None]
for j in range(k):
Z = X - mu[j]
S[j] = (R[:, j][:, None] * Z).T @ Z / Nk[j] + reg * np.eye(d)
return pi, mu, S
def gmm_logpdf(X, pi, mu, S):
d = X.shape[1]
LG = np.stack([-0.5 * (maha(X, mu[j], S[j])
+ np.log(np.linalg.det(S[j]))
+ d * np.log(2 * np.pi)) + np.log(pi[j])
for j in range(len(pi))], axis=1)
m = LG.max(axis=1)
return m + np.log(np.exp(LG - m[:, None]).sum(axis=1))
print(" %s %s %s %s"
% (pw("방법", 24), rw("AUC", 14), rw("상위 5 퍼센트 재현율", 24),
rw("정밀도", 14)))
S2 = np.cov(X2.T)
m2 = X2.mean(axis=0)
scores = []
scores.append(("정규분포 하나", np.sqrt(maha(Xq2, m2, S2))))
p2, mm2, ss2 = gmm_fit(X2, 2, rng)
scores.append(("혼합모형 둘", -gmm_logpdf(Xq2, p2, mm2, ss2)))
scores.append(("10 번째 이웃 거리", knn_score(X2, Xq2, 10)))
scores.append(("국소 이상 인자", lof(X2, Xq2, 15)))
for nm, sc in scores:
thr = np.quantile(sc, 0.95)
sel = sc > thr
rec = float(np.sum(sel & (yq2 == 1)) / max((yq2 == 1).sum(), 1))
pre = float(np.sum(sel & (yq2 == 1)) / max(sel.sum(), 1))
print(" %s %14.6f %24.6f %14.6f"
% (pw(nm, 24), auc(sc, yq2), rec, pre))
print(" 정규분포 하나는 덩어리 둘 사이 빈 곳을 정상으로 봅니다")
print(" 혼합모형과 이웃 거리는 그 빈 곳도 이상으로 잡습니다")
print(" 223강 문제 5 에서 본 밀도 쓰임이 이것입니다")
print(" 덩어리 사이 빈 곳이 실제로 어떻게 다루어지는지 봅니다")
mid = np.array([[0.25, 0.75]])
print(" 두 덩어리의 정확히 가운데 점 하나를 봅니다")
print(" %s %s %s"
% (pw("방법", 24), rw("그 점의 점수", 20), rw("학습 자료의 몇 퍼센트 위", 28)))
for nm, fn in [("정규분포 하나", lambda Z: np.sqrt(maha(Z, m2, S2))),
("혼합모형 둘", lambda Z: -gmm_logpdf(Z, p2, mm2, ss2)),
("10 번째 이웃 거리", lambda Z: knn_score(X2, Z, 10))]:
v = float(fn(mid)[0])
base = fn(X2)
print(" %s %20.6f %28.6f"
% (pw(nm, 24), v, float(np.mean(base < v))))
print(" 정규분포 하나로 보면 가운데가 가장 정상입니다. 평균이 그곳이기 때문입니다")
print(" 혼합모형과 이웃 거리로 보면 그곳이 아주 드문 자리입니다")
print(" 무엇을 정상이라 볼지가 모형이 정합니다")
# --- 문제 3: 거리와 밀도로 찾습니다 -------------------------------------
print(" 밀도가 다른 곳이 함께 있으면 무엇이 어려운지 봅니다")
Xd1 = rng.normal(0, 0.3, (300, 2))
Xd2 = rng.normal(0, 1.5, (300, 2)) + np.array([6.0, 0.0])
Xd = np.vstack([Xd1, Xd2])
probe = np.array([[0.0, 1.2], [6.0, 4.0]])
print(" 빽빽한 덩어리와 성긴 덩어리를 놓고 각각에서 같은 정도로 떨어진 점을 봅니다")
print(" %s %s %s %s"
% (pw("점", 26), rw("자기 덩어리 표준편차 대비", 28),
rw("10 번째 이웃 거리", 22), rw("국소 이상 인자", 20)))
kn = knn_score(Xd, probe, 10)
lo = lof(Xd, probe, 15)
for i, (nm, sd) in enumerate([("빽빽한 쪽에서 4 시그마", 0.3),
("성긴 쪽에서 2.7 시그마", 1.5)]):
print(" %s %28.6f %22.6f %20.6f"
% (pw(nm, 26), float(np.linalg.norm(probe[i] - (0 if i == 0 else
np.array([6.0, 0.0])))
/ sd), kn[i], lo[i]))
print(" 이웃 거리로 보면 성긴 쪽 점이 더 이상해 보입니다")
print(" 국소 이상 인자는 자기 이웃의 밀도로 나누므로 빽빽한 쪽을 더 이상하다고 봅니다")
print(" 222강 문제 4 의 밀도가 다른 문제가 여기서도 나옵니다")
print(" 두 방법을 여러 자료에서 견줍니다")
print(" %s %s %s %s"
% (pw("자료", 26), rw("이웃 거리 AUC", 20), rw("국소 이상 인자 AUC", 24),
rw("어느 쪽이 나은가", 20)))
sets = []
Xu = rng.normal(0, 1, (600, 2))
Ou = rng.uniform(-6, 6, (30, 2))
Ou = Ou[np.sqrt((Ou ** 2).sum(axis=1)) > 3.5]
sets.append(("밀도가 고름", Xu, Ou))
Xv = np.vstack([rng.normal(0, 0.3, (300, 2)),
rng.normal(0, 1.5, (300, 2)) + np.array([6.0, 0.0])])
Ov = np.stack([rng.uniform(-3, 10, 40), rng.uniform(-5, 5, 40)], axis=1)
Ov = Ov[np.minimum(np.sqrt((Ov ** 2).sum(axis=1)),
np.sqrt(((Ov - np.array([6.0, 0.0])) ** 2).sum(axis=1)))
> 3.5]
sets.append(("밀도가 다름", Xv, Ov))
Xw = np.vstack([rng.normal(0, 0.5, (500, 2)),
rng.normal(0, 0.5, (30, 2)) + np.array([3.0, 3.0])])
Ow = np.stack([rng.uniform(-4, 7, 30), rng.uniform(-4, 7, 30)], axis=1)
Ow = Ow[np.minimum(np.sqrt((Ow ** 2).sum(axis=1)),
np.sqrt(((Ow - np.array([3.0, 3.0])) ** 2).sum(axis=1)))
> 2.5]
sets.append(("작은 덩어리가 섞임", Xw, Ow))
for nm, Xt, Ot in sets:
Q = np.vstack([Xt, Ot])
yy = np.concatenate([np.zeros(len(Xt)), np.ones(len(Ot))])
a1 = auc(knn_score(Xt, Q, 10), yy)
a2 = auc(lof(Xt, Q, 15), yy)
print(" %s %20.6f %24.6f %s"
% (pw(nm, 26), a1, a2,
rw("이웃 거리" if a1 > a2 else "국소 이상 인자", 20)))
print(" 세 자료 모두에서 이웃 거리가 국소 이상 인자보다 낫거나 같습니다")
print(" 이상점을 덩어리 바깥 먼 곳에 두었으므로 국소 눈금을 맞출 이유가 없습니다")
print(" 국소 이상 인자가 이기는 자리는 앞 표처럼 빽빽한 덩어리 가장자리입니다")
print(" 어느 쪽이 나은지는 이상이 어디에 있느냐가 정합니다")
# --- 문제 4: 나무로 찾습니다 -------------------------------------------
print(" 이상점은 적고 다르므로 빨리 갈립니다")
print(" %s %s %s"
% (pw("무엇", 22), rw("정상점", 22), rw("이상점", 22)))
for a, b, c in [("무작위로 자르면", "여러 번 잘라야 갈림", "몇 번에 갈림"),
("나무에서의 깊이", "깊음", "얕음"),
("점수", "낮음", "높음"),
("밀도를 세나", "아니오", "아니오")]:
print(" %s %s %s" % (pw(a, 22), rw(b, 22), rw(c, 22)))
print(" 밀도를 안 세고 갈리는 빠르기만 봅니다. 그래서 고차원에서도 됩니다")
print(" 경로 길이가 정말 다른지 봅니다")
tr4 = iforest_fit(Xq2[yq2 == 0], 60, 128, rng)
h_norm = np.zeros(50)
h_out = np.zeros(len(Xo2))
Xn = Xq2[yq2 == 0][:50]
for t in tr4:
for i in range(50):
h_norm[i] += path_len(t, Xn[i])
for i in range(len(Xo2)):
h_out[i] += path_len(t, Xo2[i])
h_norm /= 60
h_out /= 60
print(" %s %s %s %s"
% (pw("어떤 점", 20), rw("평균 경로 길이", 20), rw("점수", 16),
rw("몇 개", 12)))
print(" %s %20.6f %16.6f %12d"
% (pw("정상점", 20), float(h_norm.mean()),
float(np.mean(2.0 ** (-h_norm / cfun(128)))), 50))
print(" %s %20.6f %16.6f %12d"
% (pw("이상점", 20), float(h_out.mean()),
float(np.mean(2.0 ** (-h_out / cfun(128)))), len(Xo2)))
print(" 이상점이 평균 두 단계 넘게 얕은 자리에서 갈립니다")
print(" 점수는 2 의 마이너스 경로 나누기 기준값 제곱입니다")
print(" 0.5 근처면 정상이고 1 에 가까우면 이상입니다")
print(" 차원이 오를 때 세 방법을 견줍니다")
print(" %s %s %s %s"
% (pw("차원", 10), rw("혼합모형 AUC", 20), rw("이웃 거리 AUC", 20),
rw("고립 숲 AUC", 18)))
for d in [2, 5, 20, 50]:
Xt = rng.normal(0, 1, (500, d))
Ot = rng.normal(0, 1, (30, d))
Ot[:, 0] += 5.0
Q = np.vstack([Xt, Ot])
yy = np.concatenate([np.zeros(500), np.ones(30)])
mg = Xt.mean(axis=0)
Sg = np.cov(Xt.T) + 1e-4 * np.eye(d)
a1 = auc(np.sqrt(maha(Q, mg, Sg)), yy)
a2 = auc(knn_score(Xt, Q, 10), yy)
tr = iforest_fit(Xt, 60, 128, rng)
a3 = auc(iforest_score(tr, Q, 128), yy)
print(" %s %20.6f %20.6f %18.6f"
% (pw(str(d), 10), a1, a2, a3))
print(" 혼합모형과 이웃 거리는 차원이 올라도 0.9 를 넘습니다")
print(" 고립 숲은 0.973 에서 0.489 로 무너집니다. 우연 수준입니다")
print(" 한 방향으로만 다른 이상은 무작위 축으로 자르기가 점점 어려워집니다")
print(" 이상이 뚜렷하지 않으면 어떻게 되는지 봅니다")
print(" 모든 방향으로 조금씩만 다른 이상점을 넣습니다")
print(" %s %s %s %s"
% (pw("차원", 10), rw("혼합모형 AUC", 20), rw("이웃 거리 AUC", 20),
rw("고립 숲 AUC", 18)))
for d in [2, 5, 20, 50]:
Xt = rng.normal(0, 1, (500, d))
Ot = rng.normal(0, 1, (30, d)) * 1.6
Q = np.vstack([Xt, Ot])
yy = np.concatenate([np.zeros(500), np.ones(30)])
mg = Xt.mean(axis=0)
Sg = np.cov(Xt.T) + 1e-4 * np.eye(d)
a1 = auc(np.sqrt(maha(Q, mg, Sg)), yy)
a2 = auc(knn_score(Xt, Q, 10), yy)
tr = iforest_fit(Xt, 60, 128, rng)
a3 = auc(iforest_score(tr, Q, 128), yy)
print(" %s %20.6f %20.6f %18.6f"
% (pw(str(d), 10), a1, a2, a3))
print(" 차원이 오를수록 오히려 잡기 쉬워집니다. 조금씩의 차이가 쌓이기 때문입니다")
print(" 213강 문제 1 에서 거리가 루트 d 로 자란다고 한 것이 여기서는 도움이 됩니다")
print(" 다만 쓸모없는 변수가 섞이면 반대가 됩니다. 곧 봅니다")
print(" 쓸모없는 변수를 섞어 봅니다")
print(" %s %s %s %s"
% (pw("잡음 변수 수", 14), rw("혼합모형 AUC", 20), rw("이웃 거리 AUC", 20),
rw("고립 숲 AUC", 18)))
for m in [0, 5, 20, 50]:
Xt = np.hstack([rng.normal(0, 1, (500, 2)), rng.normal(0, 1, (500, m))])
Ot = np.hstack([rng.normal(0, 1, (30, 2)) + np.array([4.0, 0.0]),
rng.normal(0, 1, (30, m))])
Q = np.vstack([Xt, Ot])
yy = np.concatenate([np.zeros(500), np.ones(30)])
mg = Xt.mean(axis=0)
Sg = np.cov(Xt.T) + 1e-4 * np.eye(2 + m)
a1 = auc(np.sqrt(maha(Q, mg, Sg)), yy)
a2 = auc(knn_score(Xt, Q, 10), yy)
tr = iforest_fit(Xt, 60, 128, rng)
a3 = auc(iforest_score(tr, Q, 128), yy)
print(" %s %20.6f %20.6f %18.6f"
% (pw(str(m), 14), a1, a2, a3))
print(" 잡음 변수를 50 개 섞으면 셋 다 크게 떨어집니다")
print(" 이상은 두 변수에만 있는데 거리와 나눔이 잡음에 끌려다닙니다")
print(" 215강 문제 2 와 217강 문제 4 에서 본 것과 같은 문제입니다")
# --- 문제 5: 실무에서 쓰기 ---------------------------------------------
print(" 문턱을 어떻게 정하는지 봅니다")
print(" %s %s %s"
% (pw("방법", 24), rw("무엇으로 정하나", 26), rw("무엇이 문제인가", 24)))
for a, b, c in [("고정 비율", "상위 몇 퍼센트", "실제 비율을 모름"),
("분포 가정", "카이제곱 분위수", "가정이 틀리면"),
("검증 자료", "라벨 조금", "라벨이 필요"),
("비용으로", "놓침과 헛경보의 값", "가장 정직함"),
("극단값 이론", "꼬리를 따로 맞춤", "꼬리 자료가 적음")]:
print(" %s %s %s" % (pw(a, 24), rw(b, 26), rw(c, 24)))
print(" 문턱을 옮기면 무엇이 맞바뀌는지 잽니다")
sc5 = -gmm_logpdf(Xq2, p2, mm2, ss2)
print(" %s %s %s %s %s"
% (pw("상위 몇 퍼센트", 16), rw("잡은 이상 수", 16), rw("재현율", 14),
rw("정밀도", 14), rw("헛경보 수", 14)))
for q in [0.99, 0.95, 0.90, 0.80]:
thr = np.quantile(sc5, q)
sel = sc5 > thr
tp = int(np.sum(sel & (yq2 == 1)))
fp = int(np.sum(sel & (yq2 == 0)))
print(" %s %16d %14.6f %14.6f %14d"
% (pw("%.0f" % ((1 - q) * 100), 16), tp,
float(tp / max((yq2 == 1).sum(), 1)),
float(tp / max(tp + fp, 1)), fp))
print(" 문턱을 낮추면 더 잡지만 헛경보가 훨씬 빨리 늡니다")
print(" 226강의 ROC 곡선이 이 맞바꿈을 그림으로 보여 줍니다")
print(" 이상이 학습 자료에 섞여 있으면 어떻게 되는지 봅니다")
print(" %s %s %s %s"
% (pw("학습에 섞인 이상 비율", 24), rw("AUC", 14), rw("상위 5 퍼센트 재현율", 24),
rw("떨어진 정도", 16)))
base_auc = None
for fr in [0.0, 0.01, 0.05, 0.15]:
k = int(len(X2) * fr)
Xtr = X2 if k == 0 else np.vstack([X2, Xo2[:min(k, len(Xo2))]])
if k > len(Xo2):
extra = np.stack([rng.uniform(-6, 6, k - len(Xo2)),
rng.uniform(-4, 6, k - len(Xo2))], axis=1)
Xtr = np.vstack([Xtr, extra])
pf, mf, sf = gmm_fit(Xtr, 2, rng)
sc = -gmm_logpdf(Xq2, pf, mf, sf)
a = auc(sc, yq2)
if base_auc is None:
base_auc = a
thr = np.quantile(sc, 0.95)
rec = float(np.sum((sc > thr) & (yq2 == 1))
/ max((yq2 == 1).sum(), 1))
print(" %s %14.6f %24.6f %16.6f"
% (pw("%.2f" % fr, 24), a, rec, a - base_auc))
print(" 이상이 조금 섞여도 크게 안 흔들립니다")
print(" 많이 섞이면 모형이 그것을 정상으로 배웁니다")
print(" 그래서 학습 자료를 깨끗하게 두는 것이 중요합니다")
print(" 실무 절차를 정리합니다")
print(" %s %s"
% (pw("순서", 26), rw("무엇을 하나", 36)))
for a, b in [("무엇이 이상인지 정의", "종류와 비용을 먼저 정함"),
("변수를 고름", "쓸모없는 것이 치명적"),
("표준화", "거리를 쓰는 방법은 다 필요"),
("여러 방법을 함께", "잡는 것이 서로 다름"),
("문턱은 비용으로", "227강의 불균형 문제")]:
print(" %s %s" % (pw(a, 26), rw(b, 36)))
print(" 여러 방법을 합치면 나아지는지 봅니다")
Xh = np.hstack([X2, rng.normal(0, 1, (len(X2), 8))])
Oh = np.hstack([Xo2, rng.normal(0, 1, (len(Xo2), 8))])
Q5 = np.vstack([Xh, Oh])
y5 = np.concatenate([np.zeros(len(Xh)), np.ones(len(Oh))])
ph, mh, sh = gmm_fit(Xh, 2, rng)
s_g = -gmm_logpdf(Q5, ph, mh, sh)
s_k = knn_score(Xh, Q5, 10)
s_l = lof(Xh, Q5, 15)
tr5 = iforest_fit(Xh, 60, 128, rng)
s_i = iforest_score(tr5, Q5, 128)
def rz(v):
return (np.argsort(np.argsort(v)) + 1.0) / len(v)
print(" 잡음 변수 8 개를 섞어 어렵게 만든 자료입니다")
print(" %s %s %s"
% (pw("무엇", 26), rw("AUC", 16), rw("상위 5 퍼센트 재현율", 24)))
for nm, sc in [("혼합모형", s_g), ("이웃 거리", s_k), ("국소 이상 인자", s_l),
("고립 숲", s_i),
("넷의 순위 평균", (rz(s_g) + rz(s_k) + rz(s_l) + rz(s_i)) / 4)]:
thr = np.quantile(sc, 0.95)
rec = float(np.sum((sc > thr) & (y5 == 1)) / max((y5 == 1).sum(), 1))
print(" %s %16.6f %24.6f" % (pw(nm, 26), auc(sc, y5), rec))
print(" 순위 평균은 가장 좋은 혼합모형의 0.995568 보다는 낮습니다")
print(" 그런데 가장 나쁜 고립 숲의 0.836288 보다는 훨씬 높습니다")
print(" 어느 방법이 좋을지 미리 모를 때 안전한 선택입니다")
print(" 라벨이 없으므로 어느 것이 좋은지 고를 수가 없습니다. 그것이 이상탐지의 어려움입니다")
print(" 218강의 앙상블과 같은 생각입니다. 서로 다르게 틀리기 때문입니다")
print(" 225강으로 05단원이 끝납니다. 226강부터는 재고 고르고 해석합니다")
# 221강부터 224강까지는 자료의 큰 흐름을 봤습니다
# 이번에는 흐름에서 벗어난 드문 것을 찾습니다
# 무엇 분류 이상탐지
# 라벨 양쪽 다 있음 대개 정상만
# 갈래 비율 비슷하거나 치우침 아주 치우침
# 이상의 모양 학습 자료에 있음 미리 모름
# 무엇을 배우나 경계 정상의 모양
# 새 이상 못 잡을 수 있음 잡을 수 있음
# 셋째 줄이 결정적입니다. 이상은 종류가 정해져 있지 않습니다
# 그래서 이상을 배우는 대신 정상을 배우고 벗어난 것을 찾습니다
# 이상에도 종류가 있습니다
# 종류 무엇인가 어떻게 찾나
# 점 이상 혼자 동떨어짐 밀도나 거리
# 맥락 이상 그 상황에서만 이상 조건부로 봄
# 모임 이상 묶음 전체가 이상 묶음 단위로
# 드문 갈래 정상인데 드묾 이상이 아님
# 마지막 줄을 조심해야 합니다. 드문 것과 이상한 것은 다릅니다
# 가장 단순한 방법부터 봅니다
# 두 변수가 상관 0.9 인 자료에 이상점 넷을 넣습니다
# 점 첫 변수 z 값 둘째 변수 z 값 마할라노비스 거리 이상인가
# 보통 점 0.002152 0.005351 0.017583 아니오
# 첫 이상점 0.063289 2.617778 6.116885 예
# 둘째 이상점 2.567530 0.058746 6.006657 예
# 셋째 이상점 1.814892 1.978020 8.851454 예
# 넷째 이상점 1.941470 1.860528 8.872358 예
# 네 이상점 모두 변수 하나씩만 보면 z 값이 2.5 를 안 넘습니다
# 그런데 마할라노비스 거리는 훨씬 큽니다. 상관 0.9 를 어겼기 때문입니다
# 변수를 따로따로 보면 못 잡는 이상이 있습니다
# 변수를 따로 볼 때와 함께 볼 때를 견줍니다
# 방법 네 이상점을 몇 개 잡나 AUC
# 변수마다 z 값 0 0.960250
# 마할라노비스 거리 4 1.000000
# 상관을 쓰면 넷을 다 잡고 안 쓰면 하나도 못 잡습니다
# 137강의 마할라노비스 거리가 공분산을 나눠 준 거리입니다
# 213강에서 거리가 곧 가정이라 한 것이 여기서도 그대로입니다
# 223강의 혼합모형으로 밀도를 세워 찾습니다
# 덩어리 둘짜리 자료에 멀리 떨어진 점 33 개를 넣습니다
# 방법 AUC 상위 5 퍼센트 재현율 정밀도
# 정규분포 하나 0.978182 0.909091 0.714286
# 혼합모형 둘 0.999773 1.000000 0.785714
# 10 번째 이웃 거리 0.999811 1.000000 0.785714
# 국소 이상 인자 0.999659 1.000000 0.785714
# 정규분포 하나는 덩어리 둘 사이 빈 곳을 정상으로 봅니다
# 혼합모형과 이웃 거리는 그 빈 곳도 이상으로 잡습니다
# 223강 문제 5 에서 본 밀도 쓰임이 이것입니다
# 덩어리 사이 빈 곳이 실제로 어떻게 다루어지는지 봅니다
# 두 덩어리의 정확히 가운데 점 하나를 봅니다
# 방법 그 점의 점수 학습 자료의 몇 퍼센트 위
# 정규분포 하나 0.231609 0.002500
# 혼합모형 둘 7.134521 0.997500
# 10 번째 이웃 거리 1.020624 0.997500
# 정규분포 하나로 보면 가운데가 가장 정상입니다. 평균이 그곳이기 때문입니다
# 혼합모형과 이웃 거리로 보면 그곳이 아주 드문 자리입니다
# 무엇을 정상이라 볼지가 모형이 정합니다
# 밀도가 다른 곳이 함께 있으면 무엇이 어려운지 봅니다
# 빽빽한 덩어리와 성긴 덩어리를 놓고 각각에서 같은 정도로 떨어진 점을 봅니다
# 점 자기 덩어리 표준편차 대비 10 번째 이웃 거리 국소 이상 인자
# 빽빽한 쪽에서 4 시그마 4.000000 0.688246 2.564249
# 성긴 쪽에서 2.7 시그마 2.666667 1.356931 1.321059
# 이웃 거리로 보면 성긴 쪽 점이 더 이상해 보입니다
# 국소 이상 인자는 자기 이웃의 밀도로 나누므로 빽빽한 쪽을 더 이상하다고 봅니다
# 222강 문제 4 의 밀도가 다른 문제가 여기서도 나옵니다
# 두 방법을 여러 자료에서 견줍니다
# 자료 이웃 거리 AUC 국소 이상 인자 AUC 어느 쪽이 나은가
# 밀도가 고름 1.000000 0.999710 이웃 거리
# 밀도가 다름 0.996574 0.981019 이웃 거리
# 작은 덩어리가 섞임 1.000000 1.000000 국소 이상 인자
# 세 자료 모두에서 이웃 거리가 국소 이상 인자보다 낫거나 같습니다
# 이상점을 덩어리 바깥 먼 곳에 두었으므로 국소 눈금을 맞출 이유가 없습니다
# 국소 이상 인자가 이기는 자리는 앞 표처럼 빽빽한 덩어리 가장자리입니다
# 어느 쪽이 나은지는 이상이 어디에 있느냐가 정합니다
# 이상점은 적고 다르므로 빨리 갈립니다
# 무엇 정상점 이상점
# 무작위로 자르면 여러 번 잘라야 갈림 몇 번에 갈림
# 나무에서의 깊이 깊음 얕음
# 점수 낮음 높음
# 밀도를 세나 아니오 아니오
# 밀도를 안 세고 갈리는 빠르기만 봅니다. 그래서 고차원에서도 됩니다
# 경로 길이가 정말 다른지 봅니다
# 어떤 점 평균 경로 길이 점수 몇 개
# 정상점 9.490462 0.478273 50
# 이상점 5.060141 0.674408 33
# 이상점이 평균 두 단계 넘게 얕은 자리에서 갈립니다
# 점수는 2 의 마이너스 경로 나누기 기준값 제곱입니다
# 0.5 근처면 정상이고 1 에 가까우면 이상입니다
# 차원이 오를 때 세 방법을 견줍니다
# 차원 혼합모형 AUC 이웃 거리 AUC 고립 숲 AUC
# 2 0.999733 0.999600 0.973133
# 5 0.999933 0.999867 0.909400
# 20 0.970933 0.968867 0.810333
# 50 0.965333 0.916800 0.489333
# 혼합모형과 이웃 거리는 차원이 올라도 0.9 를 넘습니다
# 고립 숲은 0.973 에서 0.489 로 무너집니다. 우연 수준입니다
# 한 방향으로만 다른 이상은 무작위 축으로 자르기가 점점 어려워집니다
# 이상이 뚜렷하지 않으면 어떻게 되는지 봅니다
# 모든 방향으로 조금씩만 다른 이상점을 넣습니다
# 차원 혼합모형 AUC 이웃 거리 AUC 고립 숲 AUC
# 2 0.748067 0.761733 0.757667
# 5 0.913600 0.912933 0.909000
# 20 0.965400 0.966933 0.923933
# 50 1.000000 0.999933 0.992933
# 차원이 오를수록 오히려 잡기 쉬워집니다. 조금씩의 차이가 쌓이기 때문입니다
# 213강 문제 1 에서 거리가 루트 d 로 자란다고 한 것이 여기서는 도움이 됩니다
# 다만 쓸모없는 변수가 섞이면 반대가 됩니다. 곧 봅니다
# 쓸모없는 변수를 섞어 봅니다
# 잡음 변수 수 혼합모형 AUC 이웃 거리 AUC 고립 숲 AUC
# 0 0.982400 0.985533 0.959933
# 5 0.949000 0.938600 0.741800
# 20 0.927667 0.933533 0.548600
# 50 0.888533 0.794067 0.515733
# 잡음 변수를 50 개 섞으면 셋 다 크게 떨어집니다
# 이상은 두 변수에만 있는데 거리와 나눔이 잡음에 끌려다닙니다
# 215강 문제 2 와 217강 문제 4 에서 본 것과 같은 문제입니다
# 문턱을 어떻게 정하는지 봅니다
# 방법 무엇으로 정하나 무엇이 문제인가
# 고정 비율 상위 몇 퍼센트 실제 비율을 모름
# 분포 가정 카이제곱 분위수 가정이 틀리면
# 검증 자료 라벨 조금 라벨이 필요
# 비용으로 놓침과 헛경보의 값 가장 정직함
# 극단값 이론 꼬리를 따로 맞춤 꼬리 자료가 적음
# 문턱을 옮기면 무엇이 맞바뀌는지 잽니다
# 상위 몇 퍼센트 잡은 이상 수 재현율 정밀도 헛경보 수
# 1 9 0.272727 1.000000 0
# 5 33 1.000000 0.785714 9
# 10 33 1.000000 0.392857 51
# 20 33 1.000000 0.197605 134
# 문턱을 낮추면 더 잡지만 헛경보가 훨씬 빨리 늡니다
# 226강의 ROC 곡선이 이 맞바꿈을 그림으로 보여 줍니다
# 이상이 학습 자료에 섞여 있으면 어떻게 되는지 봅니다
# 학습에 섞인 이상 비율 AUC 상위 5 퍼센트 재현율 떨어진 정도
# 0.00 0.999773 1.000000 0.000000
# 0.01 0.999621 1.000000 -0.000152
# 0.05 0.978371 0.909091 -0.021402
# 0.15 0.998447 0.969697 -0.001326
# 이상이 조금 섞여도 크게 안 흔들립니다
# 많이 섞이면 모형이 그것을 정상으로 배웁니다
# 그래서 학습 자료를 깨끗하게 두는 것이 중요합니다
# 실무 절차를 정리합니다
# 순서 무엇을 하나
# 무엇이 이상인지 정의 종류와 비용을 먼저 정함
# 변수를 고름 쓸모없는 것이 치명적
# 표준화 거리를 쓰는 방법은 다 필요
# 여러 방법을 함께 잡는 것이 서로 다름
# 문턱은 비용으로 227강의 불균형 문제
# 여러 방법을 합치면 나아지는지 봅니다
# 잡음 변수 8 개를 섞어 어렵게 만든 자료입니다
# 무엇 AUC 상위 5 퍼센트 재현율
# 혼합모형 0.995568 0.909091
# 이웃 거리 0.977273 0.757576
# 국소 이상 인자 0.983030 0.848485
# 고립 숲 0.836288 0.303030
# 넷의 순위 평균 0.962500 0.606061
# 순위 평균은 가장 좋은 혼합모형의 0.995568 보다는 낮습니다
# 그런데 가장 나쁜 고립 숲의 0.836288 보다는 훨씬 높습니다
# 어느 방법이 좋을지 미리 모를 때 안전한 선택입니다
# 라벨이 없으므로 어느 것이 좋은지 고를 수가 없습니다. 그것이 이상탐지의 어려움입니다
# 218강의 앙상블과 같은 생각입니다. 서로 다르게 틀리기 때문입니다
# 225강으로 05단원이 끝납니다. 226강부터는 재고 고르고 해석합니다