단원의 여섯 방법은 모두 정답을 보고 배웠습니다. 이제 정답이 없습니다.
지도학습에서는 목적함수가 저절로 정해졌습니다. 강에서 "무엇을 최소화할 것인가"를 물었을 때 답이 예측 오차였습니다. 여기서는 그 답이 없습니다.
이 강의는 가장 널리 쓰이는 답 하나를 세웁니다. 비슷한 것끼리 뭉치게 하고, 뭉친 정도를 제곱합으로 잽니다. 그리고 그 답이 무엇을 못 찾는지까지 봅니다.
문제. 목적함수를 정합니다.
() 지도학습과 무엇이 다른지 정리하세요.
() 제곱합이 어떻게 쪼개지는지 확인하세요.
() 왜 중심이 평균인지 보이세요.
생각의 실마리. "비슷한 것끼리 묶는다"를 수식으로 적어야 합니다. 각 점이 자기 군집의 대표에서 얼마나 떨어졌는지를 다 더하는 것이 가장 단순한 방식입니다.
풀이. () 정리합니다.
| 무엇 | 지도학습 | 군집 |
|---|---|---|
| 무엇이 주어지나 | 와 | 만 |
| 무엇을 최소화 | 예측 오차 | 군집 안 흩어짐 |
| 정답이 있나 | 예 | 없음 |
| 잘했는지 재기 | 검증 오차 | 어렵고 애매함 |
| 몇 개로 나눌지 | 정해져 있음 | 우리가 정함 |
() 제곱합이 어떻게 쪼개지는지 확인합니다. 참 군집이 셋인 자료입니다.
| 군집 안 제곱합 | 군집 사이 제곱합 | 둘의 합 | |
|---|---|---|---|
마지막 열이 로 와 무관하게 일정합니다. 를 키우면 군집 안이 줄고 군집 사이가 정확히 그만큼 늡니다.
강의 분산분석에서 본 제곱합 분해와 같은 식입니다. 거기서는 처리 효과와 오차로 나눴고 여기서는 군집 사이와 군집 안으로 나눕니다.
그래서 군집 안을 최소화하는 것은 군집 사이를 최대화하는 것과 같습니다.
() 왜 중심이 평균인지 보입니다. 첫 군집 안에서 중심을 옮겨 봅니다.
| 어느 점을 중심으로 두나 | 제곱합 | 차 |
|---|---|---|
| 평균 | ||
| 중앙값 | ||
| 첫 점 | ||
| 평균에서 옮김 |
평균이 가장 작고 다른 어느 점으로 옮겨도 늘어납니다.
거리를 절댓값으로 바꾸면 중앙값이 나옵니다. 그것이 중앙값이고, 강에서 본 이상점 문제를 여기서도 그렇게 다룹니다.
이 문제에서 배우는 것. 군집의 목적함수는 자연법칙이 아니라 선택입니다. 제곱합을 고르면 평균이 따라오고, 절댓값을 고르면 중앙값이 따라옵니다. 무엇을 최소화할지 정하는 순간 나머지가 정해집니다.
확인 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. 최적 군집을 찾는 것이 왜 어려운지 정리하세요.
| 무엇 | 값 |
|---|---|
| 가능한 배정의 수 | 스털링 수로 대략 |
| 최적 해 찾기 | NP 어려움 |
| 이면 | 동적계획법으로 다항 시간 |
| 이면 | 평균 하나 |
차원이 이상이고 가 이상이면 어렵습니다. 그래서 문제 의 번갈아 풀기 같은 근사 절차를 쓰고, 여러 번 돌려 가장 좋은 것을 고르는 것이 실무의 표준입니다.
심화 2. 평균 플러스플러스의 보장을 정리하세요.
| 무엇 | 값 |
|---|---|
| 무작위 시작 | 아무 보장 없음 |
| 플러스플러스 | 최적의 배 |
| 그 뒤 반복 | 더 줄어들 뿐 |
| 여러 번 돌리면 | 더 좋아짐 |
시작점만 잘 골라도 기댓값에 상계가 생깁니다. 문제 에서 가장 나쁜 값이 에서 로 준 것이 이 보장의 실제 모습입니다.
심화 3. 커널 평균과 스펙트럼 군집의 관계를 정리하세요.
| 무엇 | 뜻 |
|---|---|
| 중심을 명시 안 함 | 커널 값만으로 거리 계산 |
| 강의 커널 요령 | 그대로 적용 |
| 가우스 커널이면 | 고리도 갈라짐 |
| 스펙트럼 군집 | 그래프 라플라시안의 고유벡터에 평균 |
강의 커널이 여기서 다시 쓰입니다. 특성 공간에서 공 모양이면 원래 공간에서는 아무 모양이어도 되므로, 문제 의 고리 문제가 풀립니다.
심화 4. 빈 군집이 생기는 경우를 정리하세요.
| 상황 | 무엇이 일어나나 |
|---|---|
| 어떤 중심이 아무 점도 안 맡음 | 평균을 못 구함 |
| 대처 | 가장 먼 점을 그 중심으로 |
| 대처 | 가장 큰 군집을 쪼갬 |
| 대처 | 그 중심을 버리고 를 줄임 |
문제 의 나쁜 자리에서 참 덩어리 개가 비었는데, 이는 중심이 비었다는 것과 다릅니다. 중심이 실제로 비는 것은 시작점이 겹칠 때 생기고, 플러스플러스가 그것도 줄여 줍니다.
심화 5. 조정 랜드 지수를 정리하세요.
| 무엇 | 값 |
|---|---|
| 완전히 같음 | |
| 우연 수준 | |
| 우연보다 나쁨 | 음수 |
| 순도와 다른 점 | 군집 수에 안 속음 |
순도는 를 키우면 저절로 올라갑니다. 이면 순도가 입니다. 조정 랜드 지수는 우연 수준을 빼므로 그런 일이 없고, 문제 의 둘째 줄처럼 순도가 속이는 경우를 막아 줍니다.
심화 6. 언제 평균을 쓸지 정리하세요.
| 상황 | 쓰나 | 왜 |
|---|---|---|
| 빠른 첫 시도 | 예 | 가장 싸고 단순함 |
| 덩어리가 공 모양 | 예 | 가정에 맞음 |
| 모양을 모름 | 절반 | 강과 견줘 봄 |
| 밀도가 다름 | 아니오 | 강 |
| 확률이 필요함 | 아니오 | 강의 혼합모형 |
첫 줄이 실무의 현실입니다. 무엇이 있는지 모를 때 평균을 몇 개 로 돌려 보는 것이 가장 싼 탐색이고, 그 결과가 이상하면 다음 강의들로 넘어갑니다.
정답.
| 기호 | 읽는 법 | 뜻 |
|---|---|---|
| 군집 | clustering | 라벨 없이 비슷한 것끼리 묶습니다 |
| 군집 안 제곱합 | within-cluster sum of squares | 중심까지 거리 제곱의 합입니다 |
| 평균 플러스플러스 | k-means++ | 멀리 떨어진 점을 시작 중심으로 고릅니다 |
| 팔꿈치 방법 | elbow method | 목적함수가 꺾이는 를 고릅니다 |
| 실루엣 | silhouette | 안과 밖의 거리 비입니다 |
| 간격 통계량 | gap statistic | 무작위 자료와의 차를 봅니다 |
| 순도 | purity | 각 군집의 최빈 갈래 비율입니다 |
| 조정 랜드 지수 | adjusted Rand index | 우연 수준을 뺀 일치도입니다 |
| 보로노이 조각 | Voronoi cell | 한 중심이 맡는 볼록한 영역입니다 |
| 미니배치 | mini-batch | 일부 표본으로 갱신합니다 |
다음은 222강 계층적 군집과 밀도 기반 군집입니다. 이 강의는 덩어리가 공 모양이고 개수를 안다고 가정했습니다. 다음 강의는 둘 다 안 가정합니다. 개수를 안 정하고 모양도 안 정합니다.
import numpy as np
rng = np.random.default_rng(20261227)
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 kmeans(X, k, init=None, iters=200, r=None):
n = len(X)
if init is None:
C = X[r.permutation(n)[:k]].copy()
else:
C = init.copy()
lab = np.zeros(n, dtype=np.int64)
for _ in range(iters):
D = d2(X, C)
new = np.argmin(D, axis=1)
if np.array_equal(new, lab) and _ > 0:
break
lab = new
for j in range(k):
m = lab == j
if m.any():
C[j] = X[m].mean(axis=0)
return C, lab, float(np.sum(np.min(d2(X, C), axis=1)))
def kpp_init(X, k, r):
n = len(X)
C = [X[r.integers(0, n)]]
for _ in range(k - 1):
D = np.min(d2(X, np.stack(C)), axis=1)
p = D / max(D.sum(), 1e-300)
C.append(X[r.choice(n, p=p)])
return np.stack(C)
# --- 문제 1: 라벨이 없을 때 무엇을 최소화하는가 -------------------------
print(" 04단원의 여섯 방법은 모두 정답을 보고 배웠습니다")
print(" 이번에는 정답이 없습니다. 무엇을 최소화할지부터 정해야 합니다")
print(" %s %s %s"
% (pw("무엇", 22), rw("지도학습", 22), rw("군집", 24)))
for a, b, c in [("무엇이 주어지나", "x 와 y", "x 만"),
("무엇을 최소화", "예측 오차", "군집 안 흩어짐"),
("정답이 있나", "예", "없음"),
("잘했는지 재기", "검증 오차", "어렵고 애매함"),
("몇 개로 나눌지", "정해져 있음", "우리가 정함")]:
print(" %s %s %s" % (pw(a, 22), rw(b, 22), rw(c, 24)))
print(" 군집이 최소화하는 것은 군집 안 제곱합입니다")
print(" 각 점에서 자기 군집 중심까지의 거리 제곱을 다 더한 값입니다")
print(" 이 목적함수가 무엇을 뜻하는지 봅니다")
print(" 전체 흩어짐이 군집 안 흩어짐과 군집 사이 흩어짐으로 쪼개집니다")
n1 = 600
mu = np.array([[0.0, 0.0], [4.0, 0.0], [2.0, 3.5]])
z1 = rng.integers(0, 3, n1)
X1 = mu[z1] + rng.normal(0, 0.8, (n1, 2))
tot = float(np.sum((X1 - X1.mean(axis=0)) ** 2))
print(" %s %s %s %s"
% (pw("k", 8), rw("군집 안 제곱합", 20), rw("군집 사이 제곱합", 20),
rw("둘의 합", 18)))
for k in [1, 2, 3, 5, 10]:
best = None
for _ in range(10):
C, lab, w = kmeans(X1, k, kpp_init(X1, k, rng), 200, rng)
if best is None or w < best[2]:
best = (C, lab, w)
C, lab, w = best
cnt = np.array([(lab == j).sum() for j in range(k)])
bt = float(np.sum(cnt[:, None] * (C - X1.mean(axis=0)) ** 2))
print(" %s %20.6f %20.6f %18.6f"
% (pw(str(k), 8), w, bt, w + bt))
print(" 마지막 열이 %.6f 로 k 와 무관하게 일정합니다" % tot)
print(" k 를 키우면 군집 안이 줄고 군집 사이가 그만큼 늡니다")
print(" 166강의 분산분석에서 본 제곱합 분해와 같은 식입니다")
print(" 왜 중심이 평균인지 확인합니다")
print(" 한 군집 안에서 제곱합을 최소로 하는 점을 찾습니다")
G = X1[lab == 0]
print(" %s %s %s"
% (pw("어느 점을 중심으로 두나", 28), rw("제곱합", 20), rw("차", 16)))
base = float(np.sum((G - G.mean(axis=0)) ** 2))
for nm, c in [("평균", G.mean(axis=0)),
("중앙값", np.median(G, axis=0)),
("첫 점", G[0]),
("평균에서 0.3 옮김", G.mean(axis=0) + 0.3)]:
v = float(np.sum((G - c) ** 2))
print(" %s %20.6f %16.6f" % (pw(nm, 28), v, v - base))
print(" 평균이 가장 작습니다. 다른 어느 점으로 옮겨도 늘어납니다")
print(" 제곱합을 미분해 0 으로 두면 평균이 나옵니다")
print(" 거리를 절댓값으로 바꾸면 중앙값이 나옵니다. 그것이 k 중앙값입니다")
# --- 문제 2: 번갈아 푸는 방법 -------------------------------------------
print(" 이 문제는 정확히 풀기 어렵습니다. 그래서 번갈아 풉니다")
print(" %s %s %s"
% (pw("단계", 20), rw("무엇을 고정하고", 22), rw("무엇을 푸나", 24)))
for a, b, c in [("배정", "중심을 고정", "각 점을 가까운 중심에"),
("갱신", "배정을 고정", "각 군집의 평균으로"),
("반복", "안 바뀔 때까지", "유한 번에 멈춤")]:
print(" %s %s %s" % (pw(a, 20), rw(b, 22), rw(c, 24)))
print(" 두 단계 모두 목적함수를 줄이거나 그대로 둡니다")
print(" 그래서 반드시 멈추지만 가장 좋은 자리라는 보장은 없습니다")
print(" 목적함수가 정말 단조로 줄어드는지 봅니다")
C0 = X1[rng.permutation(n1)[:3]].copy()
C = C0.copy()
print(" %s %s %s %s"
% (pw("반복", 10), rw("배정 뒤 목적함수", 22), rw("갱신 뒤 목적함수", 22),
rw("배정이 바뀐 점 수", 22)))
lab = np.zeros(n1, dtype=np.int64)
for it in range(1, 9):
new = np.argmin(d2(X1, C), axis=1)
ch = int((new != lab).sum()) if it > 1 else n1
lab = new
w1 = float(np.sum(np.min(d2(X1, C), axis=1)))
for j in range(3):
m = lab == j
if m.any():
C[j] = X1[m].mean(axis=0)
w2 = float(np.sum(np.min(d2(X1, C), axis=1)))
print(" %s %22.6f %22.6f %22d"
% (pw(str(it), 10), w1, w2, ch))
print(" 두 열이 모두 줄어들고 배정이 바뀐 점 수가 0 으로 갑니다")
print(" 107강의 좌표하강과 같은 구조입니다. 한 번에 한 쪽만 최적화합니다")
print(" 시작점에 따라 답이 달라지는지 봅니다")
print(" 덩어리 여덟 개를 원 위에 고르게 놓은 어려운 자료를 씁니다")
ang = np.arange(8) * 2 * np.pi / 8
mu2 = np.stack([3 * np.cos(ang), 3 * np.sin(ang)], axis=1)
z2 = rng.integers(0, 8, 600)
X2 = mu2[z2] + rng.normal(0, 0.5, (600, 2))
print(" %s %s %s %s"
% (pw("시작 방법", 26), rw("목적함수 평균", 20), rw("가장 나쁜 값", 20),
rw("가장 좋은 값", 20)))
for nm, kind in [("무작위 점 여덟", "rand"), ("k 평균 플러스플러스", "kpp")]:
vs = []
for _ in range(150):
ini = (X2[rng.permutation(600)[:8]] if kind == "rand"
else kpp_init(X2, 8, rng))
_, _, w = kmeans(X2, 8, ini, 200, rng)
vs.append(w)
vs = np.array(vs)
print(" %s %20.6f %20.6f %20.6f"
% (pw(nm, 26), float(vs.mean()), float(vs.max()), float(vs.min())))
print(" 둘 다 가장 좋은 값은 같은 자리에 닿습니다")
print(" 그런데 평균과 가장 나쁜 값이 다릅니다. 무작위 시작이 더 자주 갇힙니다")
print(" k 평균 플러스플러스는 멀리 떨어진 점을 중심으로 고릅니다")
print(" 실무에서는 여러 번 돌려 가장 좋은 것을 고릅니다")
print(" 나쁜 자리에 갇히는 예를 하나 봅니다")
worst = None
for _ in range(300):
ini = X2[rng.permutation(600)[:8]]
C2, l2, w2 = kmeans(X2, 8, ini, 200, rng)
if worst is None or w2 > worst[2]:
worst = (C2, l2, w2)
best = None
for _ in range(60):
C3, l3, w3 = kmeans(X2, 8, kpp_init(X2, 8, rng), 200, rng)
if best is None or w3 < best[2]:
best = (C3, l3, w3)
print(" %s %s %s %s"
% (pw("무엇", 24), rw("목적함수", 18), rw("빈 덩어리 수", 18),
rw("가장 큰 군집 크기", 22)))
for nm, res in [("가장 나쁜 자리", worst), ("가장 좋은 자리", best)]:
hit = [int(np.bincount(z2[res[1] == j], minlength=8).argmax())
for j in range(8) if (res[1] == j).any()]
miss = 8 - len(set(hit))
cn = max(int((res[1] == j).sum()) for j in range(8))
print(" %s %18.6f %18d %22d"
% (pw(nm, 24), res[2], miss, cn))
print(" 나쁜 자리에서는 한 덩어리에 중심 둘이 들어가고 다른 덩어리 둘이 하나로 묶입니다")
print(" 그래서 아무 중심도 안 맡은 참 덩어리가 생깁니다")
print(" 목적함수 값만 보면 어느 쪽인지 알 수 있습니다. 그래서 여러 번 돌립니다")
# --- 문제 3: k 를 어떻게 고르는가 ---------------------------------------
print(" 군집 개수를 정하는 것이 가장 어렵습니다")
print(" %s %s %s"
% (pw("방법", 22), rw("무엇을 보나", 24), rw("무엇이 문제인가", 26)))
for a, b, c in [("팔꿈치", "목적함수가 꺾이는 자리", "눈으로 정함"),
("실루엣", "안과 밖의 거리 비", "덩어리 모양에 딸림"),
("간격 통계량", "무작위 자료와 비교", "계산이 비쌈"),
("아는 것 쓰기", "문제의 뜻", "언제나 있지는 않음"),
("다음 단계 성능", "군집을 쓴 결과", "가장 정직함")]:
print(" %s %s %s" % (pw(a, 22), rw(b, 24), rw(c, 26)))
print(" 마지막 줄이 실무에서 가장 믿을 만합니다")
print(" 팔꿈치와 실루엣을 나란히 잽니다")
def silhouette(X, lab, k):
n = len(X)
D = np.sqrt(d2(X, X))
s = np.zeros(n)
for i in range(n):
own = lab[i]
m = lab == own
m[i] = False
a = D[i, m].mean() if m.any() else 0.0
b = np.inf
for j in range(k):
if j == own:
continue
mj = lab == j
if mj.any():
b = min(b, D[i, mj].mean())
s[i] = 0.0 if max(a, b) == 0 else (b - a) / max(a, b)
return float(s.mean())
print(" 참 군집이 셋인 자료입니다")
print(" %s %s %s %s"
% (pw("k", 8), rw("목적함수", 18), rw("앞 k 대비 감소", 20),
rw("실루엣", 16)))
prev = None
for k in [1, 2, 3, 4, 5, 6, 8]:
best = None
for _ in range(12):
C, lab, w = kmeans(X1, k, kpp_init(X1, k, rng), 200, rng)
if best is None or w < best[2]:
best = (C, lab, w)
dd = 0.0 if prev is None else prev - best[2]
prev = best[2]
sl = silhouette(X1, best[1], k) if k > 1 else 0.0
print(" %s %18.6f %20.6f %16.6f"
% (pw(str(k), 8), best[2], dd, sl))
print(" 감소량이 k 가 3 을 넘으면서 확 작아집니다. 그 자리가 팔꿈치입니다")
print(" 실루엣도 k 가 3 일 때 가장 큽니다")
print(" 둘이 같은 답을 주는 것은 이 자료가 쉬운 경우이기 때문입니다")
print(" 군집이 없는 자료에서 무엇이 나오는지 봅니다")
X0 = rng.uniform(0, 1, (500, 2))
print(" 균등분포에서 뽑은 자료입니다. 참 군집이 없습니다")
print(" %s %s %s %s"
% (pw("k", 8), rw("목적함수", 18), rw("앞 k 대비 감소", 20),
rw("실루엣", 16)))
prev = None
for k in [1, 2, 3, 4, 6]:
best = None
for _ in range(12):
C, lab, w = kmeans(X0, k, kpp_init(X0, k, rng), 200, rng)
if best is None or w < best[2]:
best = (C, lab, w)
dd = 0.0 if prev is None else prev - best[2]
prev = best[2]
sl = silhouette(X0, best[1], k) if k > 1 else 0.0
print(" %s %18.6f %20.6f %16.6f"
% (pw(str(k), 8), best[2], dd, sl))
print(" 군집이 없는데도 목적함수는 계속 줄고 실루엣도 0.4 를 넘습니다")
print(" 군집을 찾으라고 하면 언제나 찾아 줍니다. 있든 없든 상관없이")
print(" 그래서 실루엣 값 하나로 군집이 있다고 말하면 안 됩니다")
print(" 무작위 자료와 견주는 것이 왜 필요한지 봅니다")
print(" %s %s %s %s"
% (pw("k", 8), rw("실제 자료 로그 목적함수", 28),
rw("무작위 자료 평균", 22), rw("차", 14)))
for k in [1, 2, 3, 4, 6]:
best = None
for _ in range(12):
C, lab, w = kmeans(X1, k, kpp_init(X1, k, rng), 200, rng)
if best is None or w < best[2]:
best = (C, lab, w)
lo = float(np.log(best[2]))
ref = []
for _ in range(10):
lo_ = X1.min(axis=0)
hi_ = X1.max(axis=0)
Xr = rng.uniform(lo_, hi_, (n1, 2))
b2 = None
for _ in range(6):
_, _, wr = kmeans(Xr, k, kpp_init(Xr, k, rng), 200, rng)
if b2 is None or wr < b2:
b2 = wr
ref.append(np.log(b2))
print(" %s %28.6f %22.6f %14.6f"
% (pw(str(k), 8), lo, float(np.mean(ref)),
float(np.mean(ref)) - lo))
print(" 차가 가장 큰 자리가 간격 통계량이 고르는 k 입니다")
print(" 무작위 자료도 k 를 키우면 목적함수가 줄어드는 것을 빼는 것입니다")
print(" 212강에서 후보를 많이 보면 최소값이 내려간다고 한 것과 같은 보정입니다")
# --- 문제 4: 무엇을 못 하는가 -------------------------------------------
print(" 이 방법이 어떤 모양의 덩어리만 찾는지 봅니다")
print(" %s %s %s"
% (pw("자료 모양", 24), rw("k 평균이 찾나", 20), rw("왜", 26)))
for a, b, c in [("공 모양이고 크기 비슷", "예", "가정에 맞음"),
("길쭉한 타원", "아니오", "거리가 등방성"),
("크기가 아주 다름", "아니오", "큰 것을 쪼갬"),
("겹친 고리", "아니오", "볼록한 조각만"),
("밀도가 다름", "아니오", "222강의 방법")]:
print(" %s %s %s" % (pw(a, 24), rw(b, 20), rw(c, 26)))
print(" 경계가 언제나 두 중심의 수직이등분선입니다. 볼록한 조각으로 나뉩니다")
print(" 세 가지 어려운 자료에서 실제로 재 봅니다")
def purity(lab, z, k):
tot = 0
for j in range(k):
m = lab == j
if m.any():
tot += np.bincount(z[m]).max()
return float(tot / len(z))
print(" %s %s %s"
% (pw("자료", 26), rw("순도", 16), rw("무엇이 문제인가", 26)))
za = rng.integers(0, 2, 500)
Xa = np.stack([rng.normal(0, 3.0, 500) + za * 0.0,
rng.normal(0, 0.3, 500) + za * 2.0], axis=1)
best = None
for _ in range(20):
C, lab, w = kmeans(Xa, 2, kpp_init(Xa, 2, rng), 200, rng)
if best is None or w < best[2]:
best = (C, lab, w)
print(" %s %16.6f %s"
% (pw("길쭉한 띠 둘", 26), purity(best[1], za, 2),
rw("긴 쪽으로 잘림", 26)))
zb = (rng.uniform(0, 1, 600) < 0.08).astype(np.int64)
Xb = np.where(zb[:, None] == 1,
rng.normal(0, 0.3, (600, 2)) + np.array([2.5, 0.0]),
rng.normal(0, 2.0, (600, 2)))
best = None
for _ in range(20):
C, lab, w = kmeans(Xb, 2, kpp_init(Xb, 2, rng), 200, rng)
if best is None or w < best[2]:
best = (C, lab, w)
jb = int(np.bincount(best[1][zb == 1]).argmax())
prec_b = float(np.sum((best[1] == jb) & (zb == 1))
/ max((best[1] == jb).sum(), 1))
print(" %s %16.6f %s"
% (pw("큰 덩어리와 작은 덩어리", 26), purity(best[1], zb, 2),
rw("작은 쪽 군집 정밀도 %.4f" % prec_b, 26)))
th = rng.uniform(0, 2 * np.pi, 600)
zc = (rng.uniform(0, 1, 600) < 0.5).astype(np.int64)
rr = np.where(zc == 1, 1.0, 3.0) + rng.normal(0, 0.15, 600)
Xc = np.stack([rr * np.cos(th), rr * np.sin(th)], axis=1)
best = None
for _ in range(20):
C, lab, w = kmeans(Xc, 2, kpp_init(Xc, 2, rng), 200, rng)
if best is None or w < best[2]:
best = (C, lab, w)
print(" %s %16.6f %s"
% (pw("겹친 고리 둘", 26), purity(best[1], zc, 2),
rw("반으로 갈림", 26)))
print(" 순도 0.5 는 아무것도 못 맞혔다는 뜻입니다")
print(" 둘째 줄은 순도가 높아 보이는데 이는 다수 갈래가 92 퍼센트이기 때문입니다")
print(" 작은 덩어리를 맡은 군집의 정밀도가 0.1254 입니다. 큰 덩어리 점이 여덟 배나 섞였습니다")
print(" 작은 덩어리를 감싸면서 큰 덩어리의 한쪽을 함께 잘라 온 것입니다")
print(" 셋 다 사람 눈에는 뻔한데 이 방법은 제대로 못 찾습니다")
print(" 222강의 밀도 기반 방법이 고리를 찾습니다")
print(" 눈금을 바꾸면 답이 바뀌는 것도 봅니다")
print(" %s %s %s"
% (pw("둘째 변수 배율", 18), rw("순도", 16), rw("표준화 후 순도", 20)))
for sc in [1.0, 3.0, 10.0]:
A = X1 * np.array([1.0, sc])
best = None
for _ in range(20):
C, lab, w = kmeans(A, 3, kpp_init(A, 3, rng), 200, rng)
if best is None or w < best[2]:
best = (C, lab, w)
p1 = purity(best[1], z1, 3)
sd = A.std(axis=0)
best = None
for _ in range(20):
C, lab, w = kmeans(A / sd, 3, kpp_init(A / sd, 3, rng), 200, rng)
if best is None or w < best[2]:
best = (C, lab, w)
print(" %s %16.6f %20.6f"
% (pw("%.0f" % sc, 18), p1, purity(best[1], z1, 3)))
print(" 215강과 220강에서 본 것과 같습니다. 거리를 쓰면 눈금이 답을 정합니다")
print(" 다만 표준화가 언제나 옳은 것도 아닙니다. 참으로 중요한 축을 눌러 버릴 수 있습니다")
# --- 문제 5: 실무에서 쓰기 ---------------------------------------------
print(" 군집이 잘 됐는지 어떻게 재는지 정리합니다")
print(" %s %s %s"
% (pw("무엇", 22), rw("라벨이 필요한가", 22), rw("무엇을 재나", 26)))
for a, b, c in [("군집 안 제곱합", "아니오", "얼마나 뭉쳤나"),
("실루엣", "아니오", "안과 밖의 거리 비"),
("순도", "예", "한 군집에 한 갈래인가"),
("조정 랜드 지수", "예", "쌍이 같이 묶였나"),
("다음 단계 성능", "그 단계의 라벨", "쓸모가 있나")]:
print(" %s %s %s" % (pw(a, 22), rw(b, 22), rw(c, 26)))
print(" 라벨이 있으면 군집을 왜 하는지 되물어야 합니다")
print(" 군집을 특성으로 써서 지도학습에 도움이 되는지 봅니다")
n5 = 700
z5 = rng.integers(0, 4, n5)
cen = np.array([[0.0, 0.0], [4.0, 0.0], [0.0, 4.0], [4.0, 4.0]])
X5 = cen[z5] + rng.normal(0, 0.9, (n5, 2))
y5 = ((z5 == 0) | (z5 == 3)).astype(float)
X5t = cen[rng.integers(0, 4, 2000)] + rng.normal(0, 0.9, (2000, 2))
zt5 = np.argmin(d2(X5t, cen), axis=1)
y5t = ((zt5 == 0) | (zt5 == 3)).astype(float)
def logit_acc(A, ya, B, yb, steps=4000, lr=0.3):
Aa = np.hstack([A, np.ones((len(A), 1))])
w = np.zeros(Aa.shape[1])
for _ in range(steps):
p = 1.0 / (1.0 + np.exp(-Aa @ w))
w -= lr * (Aa.T @ (p - ya)) / len(ya)
Bb = np.hstack([B, np.ones((len(B), 1))])
return float(np.mean(((Bb @ w) > 0) == yb))
best = None
for _ in range(20):
C, lab, w = kmeans(X5, 4, kpp_init(X5, 4, rng), 200, rng)
if best is None or w < best[2]:
best = (C, lab, w)
C5, lab5, _ = best
lab5t = np.argmin(d2(X5t, C5), axis=1)
E = np.eye(4)
print(" 참 갈래가 배타적 논리합 배치입니다. 직선으로는 못 나눕니다")
print(" %s %s %s"
% (pw("무엇을 넣었나", 28), rw("로지스틱 정확도", 20), rw("변수 수", 14)))
print(" %s %20.6f %14d"
% (pw("원래 변수 둘", 28), logit_acc(X5, y5, X5t, y5t), 2))
print(" %s %20.6f %14d"
% (pw("군집 표시만", 28), logit_acc(E[lab5], y5, E[lab5t], y5t), 4))
print(" %s %20.6f %14d"
% (pw("둘 다", 28),
logit_acc(np.hstack([X5, E[lab5]]), y5,
np.hstack([X5t, E[lab5t]]), y5t), 6))
print(" 군집 표시를 넣으면 직선 모형이 배타적 논리합을 풉니다")
print(" 228강의 특성공학이 하는 일이고 라벨 없이 만든 특성입니다")
print(" 군집이 그 자체로 답이 아니라 재료가 되는 쓰임입니다")
print(" 큰 자료에서 어떻게 하는지 정리합니다")
print(" %s %s %s"
% (pw("무엇", 24), rw("비용", 22), rw("어떻게 줄이나", 24)))
for a, b, c in [("한 번 배정", "n 곱하기 k 곱하기 d", "삼각부등식으로 건너뜀"),
("반복 횟수", "대개 수십 번", "좋은 시작점"),
("여러 번 돌리기", "그만큼 곱하기", "플러스플러스로 줄임"),
("아주 큰 자료", "다 못 올림", "작은 묶음으로 갱신")]:
print(" %s %s %s" % (pw(a, 24), rw(b, 22), rw(c, 24)))
print(" 작은 묶음으로 갱신해도 되는지 잽니다")
print(" %s %s %s %s"
% (pw("한 번에 보는 점 수", 20), rw("목적함수", 18), rw("전부 볼 때 대비", 22),
rw("배정 계산 횟수", 20)))
Cf, labf, wf = kmeans(X1, 3, kpp_init(X1, 3, rng), 200, rng)
for bs in [30, 100, 600]:
C = kpp_init(X1, 3, rng)
cnt = np.zeros(3)
for it in range(60):
idx = rng.permutation(n1)[:bs]
lb = np.argmin(d2(X1[idx], C), axis=1)
for j in range(3):
m = lb == j
if m.any():
cnt[j] += m.sum()
C[j] = C[j] + (X1[idx][m] - C[j]).sum(axis=0) / cnt[j]
w = float(np.sum(np.min(d2(X1, C), axis=1)))
print(" %s %18.6f %22.6f %20d"
% (pw(str(bs), 20), w, w - wf, 60 * bs * 3))
print(" 점 100 개씩 보면 0.389302 차이로 거의 같은 자리에 갑니다")
print(" 계산은 18000 번으로 전부 볼 때의 6 분의 1 입니다")
print(" 30 개는 너무 적습니다. 461.057189 나 뒤처져 못 따라갑니다")
print(" 묶음이 너무 작으면 중심이 흔들려 수렴이 안 됩니다")
print(" 235강의 미니배치가 같은 생각입니다")
print(" 마지막으로 무엇을 조심해야 하는지 정리합니다")
print(" %s %s"
% (pw("흔한 오해", 30), rw("실제로는", 34)))
for a, b in [("군집이 나오면 군집이 있다", "없어도 나옴"),
("실루엣이 높으면 좋다", "모양에 딸림"),
("k 를 정하는 정답이 있다", "목적이 정함"),
("표준화는 언제나 옳다", "중요한 축을 누를 수 있음")]:
print(" %s %s" % (pw(a, 30), rw(b, 34)))
print(" 221강은 공 모양 덩어리를 나눴습니다. 222강은 모양을 안 가정합니다")
# 04단원의 여섯 방법은 모두 정답을 보고 배웠습니다
# 이번에는 정답이 없습니다. 무엇을 최소화할지부터 정해야 합니다
# 무엇 지도학습 군집
# 무엇이 주어지나 x 와 y x 만
# 무엇을 최소화 예측 오차 군집 안 흩어짐
# 정답이 있나 예 없음
# 잘했는지 재기 검증 오차 어렵고 애매함
# 몇 개로 나눌지 정해져 있음 우리가 정함
# 군집이 최소화하는 것은 군집 안 제곱합입니다
# 각 점에서 자기 군집 중심까지의 거리 제곱을 다 더한 값입니다
# 이 목적함수가 무엇을 뜻하는지 봅니다
# 전체 흩어짐이 군집 안 흩어짐과 군집 사이 흩어짐으로 쪼개집니다
# k 군집 안 제곱합 군집 사이 제곱합 둘의 합
# 1 3955.631101 0.000000 3955.631101
# 2 2240.378888 1715.252213 3955.631101
# 3 729.442615 3226.188486 3955.631101
# 5 537.157943 3418.473158 3955.631101
# 10 282.961101 3672.670000 3955.631101
# 마지막 열이 3955.631101 로 k 와 무관하게 일정합니다
# k 를 키우면 군집 안이 줄고 군집 사이가 그만큼 늡니다
# 166강의 분산분석에서 본 제곱합 분해와 같은 식입니다
# 왜 중심이 평균인지 확인합니다
# 한 군집 안에서 제곱합을 최소로 하는 점을 찾습니다
# 어느 점을 중심으로 두나 제곱합 차
# 평균 35.526110 0.000000
# 중앙값 36.453969 0.927859
# 첫 점 70.124645 34.598535
# 평균에서 0.3 옮김 48.486110 12.960000
# 평균이 가장 작습니다. 다른 어느 점으로 옮겨도 늘어납니다
# 제곱합을 미분해 0 으로 두면 평균이 나옵니다
# 거리를 절댓값으로 바꾸면 중앙값이 나옵니다. 그것이 k 중앙값입니다
# 이 문제는 정확히 풀기 어렵습니다. 그래서 번갈아 풉니다
# 단계 무엇을 고정하고 무엇을 푸나
# 배정 중심을 고정 각 점을 가까운 중심에
# 갱신 배정을 고정 각 군집의 평균으로
# 반복 안 바뀔 때까지 유한 번에 멈춤
# 두 단계 모두 목적함수를 줄이거나 그대로 둡니다
# 그래서 반드시 멈추지만 가장 좋은 자리라는 보장은 없습니다
# 목적함수가 정말 단조로 줄어드는지 봅니다
# 반복 배정 뒤 목적함수 갱신 뒤 목적함수 배정이 바뀐 점 수
# 1 3623.932400 2216.374605 600
# 2 2216.374605 1895.205842 56
# 3 1895.205842 1043.180625 104
# 4 1043.180625 735.748783 96
# 5 735.748783 729.599343 15
# 6 729.599343 729.442615 2
# 7 729.442615 729.442615 0
# 8 729.442615 729.442615 0
# 두 열이 모두 줄어들고 배정이 바뀐 점 수가 0 으로 갑니다
# 107강의 좌표하강과 같은 구조입니다. 한 번에 한 쪽만 최적화합니다
# 시작점에 따라 답이 달라지는지 봅니다
# 덩어리 여덟 개를 원 위에 고르게 놓은 어려운 자료를 씁니다
# 시작 방법 목적함수 평균 가장 나쁜 값 가장 좋은 값
# 무작위 점 여덟 396.767838 618.005467 306.957075
# k 평균 플러스플러스 365.617196 477.813702 306.957075
# 둘 다 가장 좋은 값은 같은 자리에 닿습니다
# 그런데 평균과 가장 나쁜 값이 다릅니다. 무작위 시작이 더 자주 갇힙니다
# k 평균 플러스플러스는 멀리 떨어진 점을 중심으로 고릅니다
# 실무에서는 여러 번 돌려 가장 좋은 것을 고릅니다
# 나쁜 자리에 갇히는 예를 하나 봅니다
# 무엇 목적함수 빈 덩어리 수 가장 큰 군집 크기
# 가장 나쁜 자리 578.289362 2 135
# 가장 좋은 자리 306.957075 0 90
# 나쁜 자리에서는 한 덩어리에 중심 둘이 들어가고 다른 덩어리 둘이 하나로 묶입니다
# 그래서 아무 중심도 안 맡은 참 덩어리가 생깁니다
# 목적함수 값만 보면 어느 쪽인지 알 수 있습니다. 그래서 여러 번 돌립니다
# 군집 개수를 정하는 것이 가장 어렵습니다
# 방법 무엇을 보나 무엇이 문제인가
# 팔꿈치 목적함수가 꺾이는 자리 눈으로 정함
# 실루엣 안과 밖의 거리 비 덩어리 모양에 딸림
# 간격 통계량 무작위 자료와 비교 계산이 비쌈
# 아는 것 쓰기 문제의 뜻 언제나 있지는 않음
# 다음 단계 성능 군집을 쓴 결과 가장 정직함
# 마지막 줄이 실무에서 가장 믿을 만합니다
# 팔꿈치와 실루엣을 나란히 잽니다
# 참 군집이 셋인 자료입니다
# k 목적함수 앞 k 대비 감소 실루엣
# 1 3955.631101 0.000000 0.000000
# 2 2240.378888 1715.252213 0.445821
# 3 729.442615 1510.936273 0.622244
# 4 632.897259 96.545356 0.509223
# 5 537.137917 95.759341 0.418345
# 6 454.767344 82.370573 0.341601
# 8 354.201305 100.566039 0.350698
# 감소량이 k 가 3 을 넘으면서 확 작아집니다. 그 자리가 팔꿈치입니다
# 실루엣도 k 가 3 일 때 가장 큽니다
# 둘이 같은 답을 주는 것은 이 자료가 쉬운 경우이기 때문입니다
# 군집이 없는 자료에서 무엇이 나오는지 봅니다
# 균등분포에서 뽑은 자료입니다. 참 군집이 없습니다
# k 목적함수 앞 k 대비 감소 실루엣
# 1 82.484472 0.000000 0.000000
# 2 50.333585 32.150887 0.362161
# 3 32.163146 18.170440 0.380217
# 4 19.941817 12.221328 0.421717
# 6 13.944652 5.997165 0.370528
# 군집이 없는데도 목적함수는 계속 줄고 실루엣도 0.4 를 넘습니다
# 군집을 찾으라고 하면 언제나 찾아 줍니다. 있든 없든 상관없이
# 그래서 실루엣 값 하나로 군집이 있다고 말하면 안 됩니다
# 무작위 자료와 견주는 것이 왜 필요한지 봅니다
# k 실제 자료 로그 목적함수 무작위 자료 평균 차
# 1 8.282895 8.762305 0.479410
# 2 7.714400 8.247500 0.533100
# 3 6.592281 7.794712 1.202432
# 4 6.450517 7.365142 0.914625
# 6 6.119786 6.986164 0.866378
# 차가 가장 큰 자리가 간격 통계량이 고르는 k 입니다
# 무작위 자료도 k 를 키우면 목적함수가 줄어드는 것을 빼는 것입니다
# 212강에서 후보를 많이 보면 최소값이 내려간다고 한 것과 같은 보정입니다
# 이 방법이 어떤 모양의 덩어리만 찾는지 봅니다
# 자료 모양 k 평균이 찾나 왜
# 공 모양이고 크기 비슷 예 가정에 맞음
# 길쭉한 타원 아니오 거리가 등방성
# 크기가 아주 다름 아니오 큰 것을 쪼갬
# 겹친 고리 아니오 볼록한 조각만
# 밀도가 다름 아니오 222강의 방법
# 경계가 언제나 두 중심의 수직이등분선입니다. 볼록한 조각으로 나뉩니다
# 세 가지 어려운 자료에서 실제로 재 봅니다
# 자료 순도 무엇이 문제인가
# 길쭉한 띠 둘 0.522000 긴 쪽으로 잘림
# 큰 덩어리와 작은 덩어리 0.926667 작은 쪽 군집 정밀도 0.1254
# 겹친 고리 둘 0.505000 반으로 갈림
# 순도 0.5 는 아무것도 못 맞혔다는 뜻입니다
# 둘째 줄은 순도가 높아 보이는데 이는 다수 갈래가 92 퍼센트이기 때문입니다
# 작은 덩어리를 맡은 군집의 정밀도가 0.1254 입니다. 큰 덩어리 점이 여덟 배나 섞였습니다
# 작은 덩어리를 감싸면서 큰 덩어리의 한쪽을 함께 잘라 온 것입니다
# 셋 다 사람 눈에는 뻔한데 이 방법은 제대로 못 찾습니다
# 222강의 밀도 기반 방법이 고리를 찾습니다
# 눈금을 바꾸면 답이 바뀌는 것도 봅니다
# 둘째 변수 배율 순도 표준화 후 순도
# 1 0.983333 0.983333
# 3 0.981667 0.983333
# 10 0.676667 0.983333
# 215강과 220강에서 본 것과 같습니다. 거리를 쓰면 눈금이 답을 정합니다
# 다만 표준화가 언제나 옳은 것도 아닙니다. 참으로 중요한 축을 눌러 버릴 수 있습니다
# 군집이 잘 됐는지 어떻게 재는지 정리합니다
# 무엇 라벨이 필요한가 무엇을 재나
# 군집 안 제곱합 아니오 얼마나 뭉쳤나
# 실루엣 아니오 안과 밖의 거리 비
# 순도 예 한 군집에 한 갈래인가
# 조정 랜드 지수 예 쌍이 같이 묶였나
# 다음 단계 성능 그 단계의 라벨 쓸모가 있나
# 라벨이 있으면 군집을 왜 하는지 되물어야 합니다
# 군집을 특성으로 써서 지도학습에 도움이 되는지 봅니다
# 참 갈래가 배타적 논리합 배치입니다. 직선으로는 못 나눕니다
# 무엇을 넣었나 로지스틱 정확도 변수 수
# 원래 변수 둘 0.525500 2
# 군집 표시만 0.996000 4
# 둘 다 0.996000 6
# 군집 표시를 넣으면 직선 모형이 배타적 논리합을 풉니다
# 228강의 특성공학이 하는 일이고 라벨 없이 만든 특성입니다
# 군집이 그 자체로 답이 아니라 재료가 되는 쓰임입니다
# 큰 자료에서 어떻게 하는지 정리합니다
# 무엇 비용 어떻게 줄이나
# 한 번 배정 n 곱하기 k 곱하기 d 삼각부등식으로 건너뜀
# 반복 횟수 대개 수십 번 좋은 시작점
# 여러 번 돌리기 그만큼 곱하기 플러스플러스로 줄임
# 아주 큰 자료 다 못 올림 작은 묶음으로 갱신
# 작은 묶음으로 갱신해도 되는지 잽니다
# 한 번에 보는 점 수 목적함수 전부 볼 때 대비 배정 계산 횟수
# 30 1190.499804 461.057189 5400
# 100 729.831917 0.389302 18000
# 600 730.986148 1.543533 108000
# 점 100 개씩 보면 0.389302 차이로 거의 같은 자리에 갑니다
# 계산은 18000 번으로 전부 볼 때의 6 분의 1 입니다
# 30 개는 너무 적습니다. 461.057189 나 뒤처져 못 따라갑니다
# 묶음이 너무 작으면 중심이 흔들려 수렴이 안 됩니다
# 235강의 미니배치가 같은 생각입니다
# 마지막으로 무엇을 조심해야 하는지 정리합니다
# 흔한 오해 실제로는
# 군집이 나오면 군집이 있다 없어도 나옴
# 실루엣이 높으면 좋다 모양에 딸림
# k 를 정하는 정답이 있다 목적이 정함
# 표준화는 언제나 옳다 중요한 축을 누를 수 있음
# 221강은 공 모양 덩어리를 나눴습니다. 222강은 모양을 안 가정합니다