강에서 라는 손잡이를 만들었습니다. 그런데 손잡이를 어디에 둘지는 안 정했습니다.
학습 자료로 재면 이 언제나 이깁니다. 벌점은 학습 오차를 늘리는 장치이기 때문입니다. 새 자료에서의 오차를 재야 하는데, 새 자료가 없습니다.
이 강의는 그 방법과, 그 방법 자체가 얼마나 흔들리는지를 봅니다. 교차검증은 숫자를 하나 뱉지만 그 숫자도 추정값입니다.
문제. 세 가지 방법으로 오차를 잽니다.
() 학습 자료로 잰 값이 얼마나 치우치는지 재세요.
() 겹 수에 따라 무엇이 달라지는지 정리하세요.
() 겹 수와 치우침의 관계를 재세요.
생각의 실마리. 강 문제 에서 같은 자료로 고르고 같은 자료로 점수를 매기면 구조적으로 낙관된다고 했습니다. 그 낙관을 없애려면 점수를 매길 때 안 본 자료가 필요합니다.
풀이. () 잽니다. 표본 에 계수 인 회귀에서 자료를 번 새로 뽑아 평균 냅니다.
| 무엇으로 쟀나 | 평균 | 참 오차와의 차 | 표준편차 |
|---|---|---|---|
| 학습 자료 그대로 | |||
| 따로 뗀 개 | |||
| 겹 교차검증 | |||
| 참 오차 개 |
학습 자료로 잰 값이 참 오차의 절반도 안 됩니다. 표본 에 계수 이면 자유도의 분의 을 자료 맞추기에 쓰므로 그만큼 낙관됩니다.
따로 떼기와 교차검증은 둘 다 위로 치우칩니다. 학습에 쓰는 자료가 개보다 적기 때문입니다. 따로 떼기는 개로 학습해 치우치고, 겹은 개로 학습해 치우칩니다.
표준편차를 보면 차이가 더 큽니다. 따로 떼기는 이고 겹은 으로 절반 가까이 작습니다. 시험지가 개뿐인 것과 개인 것의 차이입니다.
() 겹 수가 무엇을 바꾸는지 정리합니다.
| 방법 | 학습에 쓰는 수 | 시험에 쓰는 수 | 추정을 몇 번 평균 |
|---|---|---|---|
| 따로 떼기 | |||
| 겹 | |||
| 겹 | |||
| 하나씩 빼기 |
겹을 늘리면 학습에 쓰는 자료가 늘어 편향이 줄어듭니다. 대신 학습 집합끼리 겹쳐서 추정끼리 상관되므로, 겹을 늘려도 분산이 마냥 줄지는 않습니다. 문제 에서 잽니다.
() 겹 수와 치우침의 관계를 잽니다. 자료를 번 새로 뽑습니다.
| 겹 수 | 교차검증 평균 | 참 오차 | 치우친 정도 |
|---|---|---|---|
겹이 적으면 학습 자료가 적어 오차를 크게 봅니다. 겹은 표본 으로 계수 을 맞추므로 치우침이 로 참 오차만큼 큽니다.
겹부터는 치우침이 확 줄어듭니다. 이고 겹은 입니다. 실무에서 겹이나 겹을 쓰는 이유가 이것입니다.
이 문제에서 배우는 것. 교차검증이 학습 오차보다 나은 것은 점수를 안 본 자료로 매기기 때문입니다. 그리고 교차검증은 참 오차를 정확히 맞히는 것이 아니라 위로 조금 치우친 값을 줍니다. 그 치우침의 크기는 겹 수가 정합니다.
확인 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. 하나씩 빼기가 회귀에서 한 번에 계산되는 이유를 정리하세요.
선형 평활자에서는 이고, 번째를 뺀 예측이 모자 행렬의 대각 성분만으로 나옵니다.
| 무엇 | 값 |
|---|---|
| 나이브 계산 | 모형을 번 적합 |
| 이 공식 | 모형을 한 번 적합 |
| 필요한 것 | 의 대각 성분 |
강의 지렛대 가 그대로 쓰입니다. 지렛대가 큰 점은 자기 예측에 크게 기여하므로 뺐을 때 오차가 크게 벌어지고, 로 나누는 것이 그 보정입니다. 릿지에서도 로 같은 꼴이 성립합니다.
심화 2. 교차검증이 무엇의 불편추정인지 정확히 쓰세요.
겹 교차검증은 표본 으로 학습한 모형의 위험이 아니라 표본 로 학습한 모형의 위험을 재는 데 가깝습니다.
| 무엇을 재나 | 표본 크기 |
|---|---|
| 우리가 알고 싶은 것 | |
| 교차검증이 재는 것 | |
| 겹에서 | |
| 하나씩 빼기에서 |
학습 곡선이 가파른 구간에 있으면 이 차이가 큽니다. 문제 에서 겹의 치우침이 였던 것이 그것입니다. 강의 학습 곡선이 평평해지는 구간이면 겹 수를 줄여도 됩니다.
심화 3. 층화 교차검증이 왜 필요한지 설명하세요.
갈래가 대 로 치우친 자료를 겹으로 무작위 나누면 드문 갈래가 아예 없는 겹이 생길 수 있습니다.
| 무엇 | 무작위 겹 | 층화 겹 |
|---|---|---|
| 겹마다 비율 | 흔들림 | 원래 비율 유지 |
| 드문 갈래 | 없는 겹이 생김 | 언제나 들어감 |
| 추정의 분산 | 큼 | 작음 |
층화는 나누는 운의 일부를 없애는 장치입니다. 문제 에서 본 나누기의 분산을 줄이므로, 갈래가 치우칠수록 이득이 큽니다. 회귀에서도 를 구간으로 나눠 층화할 수 있습니다.
심화 4. 시계열에서 어떻게 나눠야 하는지 정리하세요.
| 방법 | 학습 | 시험 |
|---|---|---|
| 늘어나는 창 | 처음부터 까지 | 부터 까지 |
| 구르는 창 | 부터 까지 | 부터 까지 |
| 사이 띄우기 | 까지 | 부터 |
셋째 줄이 자주 빠집니다. 이웃한 시점끼리 상관되어 있으면 바로 다음 시점을 시험지로 써도 정보가 샙니다. 강에서 본 대로 예측 지평만큼 사이를 띄워야 실제 쓸 상황과 맞습니다.
심화 5. 교차검증으로 고른 모형의 신뢰구간을 쓰면 왜 안 되는지 설명하세요.
강 문제 의 선택 후 추론 문제입니다. 자료로 를 고르고 같은 자료로 계수의 구간을 만들면 고르는 단계의 불확실성이 빠집니다.
| 무엇을 셌나 | 무엇이 빠졌나 |
|---|---|
| 고른 에서의 표준오차 | 가 흔들린다는 사실 |
| 고른 변수의 계수 | 다른 변수가 뽑힐 수도 있었음 |
문제 에서 바깥 겹마다 다른 가 나온 것이 증거입니다. 자료가 조금만 바뀌어도 과 사이를 오갑니다. 붓스트랩으로 고르는 절차 전체를 다시 돌려야 그 흔들림이 구간에 들어갑니다.
심화 6. 교차검증과 정보기준의 관계를 정리하세요.
| 무엇 | 무엇을 근사하나 | 언제 맞나 |
|---|---|---|
| AIC | 하나씩 빼기 교차검증 | 표본이 클 때 |
| BIC | 주변우도 | 참 모형이 후보에 있을 때 |
| 교차검증 | 예측 위험 직접 | 나눌 수 있으면 언제나 |
AIC와 하나씩 빼기는 표본이 크면 같은 값에 수렴합니다. 정보기준은 계산이 한 번이라 싸지만 우도를 쓸 수 있어야 하고 모수 수를 셀 수 있어야 합니다. 릿지처럼 계수가 연속적으로 줄어드는 모형에서는 모수 수가 정수가 아니므로 유효 자유도를 따로 세야 하고, 교차검증은 그런 것 없이 그냥 잽니다.
정답.
| 기호 | 읽는 법 | 뜻 |
|---|---|---|
| 겹 | fold | 자료를 나눈 한 조각입니다 |
| 겹 교차검증 | k-fold cross validation | 겹마다 한 번씩 시험을 봅니다 |
| 하나씩 빼기 | leave-one-out | 겹 수를 표본 수와 같게 합니다 |
| 층화 겹 | stratified fold | 겹마다 갈래 비율을 지킵니다 |
| 두 겹 교차검증 | nested cross validation | 안쪽에서 고르고 바깥에서 잽니다 |
| 한 표준오차 규칙 | one standard error rule | 문턱 안에서 가장 단순한 것을 고릅니다 |
| 자료 누출 | data leakage | 시험지의 정보가 학습에 들어갑니다 |
| 개체 단위 나누기 | group split | 같은 개체를 한쪽에만 둡니다 |
| 반복 교차검증 | repeated CV | 나누기를 여러 번 바꿔 평균 냅니다 |
| 유효 자유도 | effective degrees of freedom | 축소된 모형이 실제로 쓴 자유도입니다 |
다음은 213강 차원의 저주와 측도의 집중입니다. 이 강의가 를 고르는 법을 만들었습니다. 다음 강의는 변수가 많아지면 왜 자료가 갑자기 부족해지는지를 봅니다.
import numpy as np
rng = np.random.default_rng(20261024)
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 ridge(X, y, lam):
p = X.shape[1]
return np.linalg.solve(X.T @ X / len(y) + lam * np.eye(p),
X.T @ y / len(y))
def mse(X, y, w):
return float(np.mean((y - X @ w) ** 2))
def kfold_idx(n, k, r):
idx = r.permutation(n)
return np.array_split(idx, k)
def cv_error(X, y, lam, k, r, fol=None):
if fol is None:
fol = kfold_idx(len(y), k, r)
es = []
for i in range(k):
te = fol[i]
tr = np.concatenate([fol[j] for j in range(k) if j != i])
es.append(mse(X[te], y[te], ridge(X[tr], y[tr], lam)))
return float(np.mean(es))
def gen(n, p, r, sig=1.0, w=None, ws=1.0):
X = r.normal(0, 1, (n, p))
if w is None:
w = r.normal(0, ws, p)
return X, X @ w + r.normal(0, sig, n), w
# --- 문제 1: 왜 나눠야 하는가 -------------------------------------------
print(" 205강 문제 1 에서 같은 자료로 고르고 재면 낙관된다고 했습니다")
print(" 이제 그 낙관이 얼마나 되는지 재고 어떻게 없애는지 봅니다")
n1, p1 = 60, 20
print(" 한 번만 재면 운이 섞이므로 자료를 200 번 새로 뽑아 평균 냅니다")
print(" %s %s %s %s"
% (pw("무엇으로 쟀나", 22), rw("평균", 14), rw("참 오차와의 차", 18),
rw("표준편차", 14)))
R0 = 200
acc = {k: [] for k in ["학습 자료 그대로", "따로 뗀 20 개", "5 겹 교차검증",
"참 오차 20000 개"]}
Xh, yh, wf = gen(20000, p1, rng)
for _ in range(R0):
Xa, ya, _ = gen(n1, p1, rng, w=wf)
wa = ridge(Xa, ya, 1e-8)
acc["학습 자료 그대로"].append(mse(Xa, ya, wa))
ho = rng.permutation(n1)
acc["따로 뗀 20 개"].append(
mse(Xa[ho[40:]], ya[ho[40:]], ridge(Xa[ho[:40]], ya[ho[:40]], 1e-8)))
acc["5 겹 교차검증"].append(cv_error(Xa, ya, 1e-8, 5, rng))
acc["참 오차 20000 개"].append(mse(Xh, yh, wa))
tt_e = float(np.mean(acc["참 오차 20000 개"]))
for nm in ["학습 자료 그대로", "따로 뗀 20 개", "5 겹 교차검증", "참 오차 20000 개"]:
v = np.array(acc[nm])
print(" %s %14.6f %18.6f %14.6f"
% (pw(nm, 22), float(v.mean()), float(v.mean()) - tt_e,
float(v.std())))
print(" 학습 자료로 잰 값이 참 오차보다 한참 작습니다")
print(" 표본 60 에 계수 20 이면 자유도의 3 분의 1 을 자료 맞추기에 씁니다")
print(" 교차검증은 모든 자료를 한 번씩 시험지로 씁니다")
print(" 왜 모든 자료를 시험지로 쓰는 것이 이득인지 봅니다")
print(" %s %s %s %s"
% (pw("방법", 20), rw("학습에 쓰는 수", 18), rw("시험에 쓰는 수", 18),
rw("추정을 몇 번 평균", 20)))
for nm, a, b, c in [("따로 떼기", "40", "20", "1"),
("5 겹", "48", "60", "5"),
("10 겹", "54", "60", "10"),
("하나씩 빼기", "59", "60", "60")]:
print(" %s %s %s %s"
% (pw(nm, 20), rw(a, 18), rw(b, 18), rw(c, 20)))
print(" 겹을 늘리면 학습에 쓰는 자료가 늘어 편향이 줄어듭니다")
print(" 대신 학습 집합끼리 겹쳐서 추정끼리 상관됩니다")
print(" 그래서 겹을 늘려도 분산이 마냥 줄지는 않습니다. 문제 2 에서 봅니다")
print(" 겹 수에 따라 편향이 얼마나 다른지 잽니다")
print(" %s %s %s %s"
% (pw("겹 수", 12), rw("교차검증 평균", 18), rw("참 오차", 14),
rw("치우친 정도", 16)))
R1 = 200
tvs = []
for _ in range(R1):
Xc, yc, _ = gen(n1, p1, rng, w=wf)
tvs.append(mse(Xh, yh, ridge(Xc, yc, 1e-8)))
tv0 = float(np.mean(tvs))
for k in [2, 5, 10, 60]:
vs = []
for _ in range(R1):
Xa, ya, _ = gen(n1, p1, rng, w=wf)
vs.append(cv_error(Xa, ya, 1e-8, k, rng))
print(" %s %18.6f %14.6f %16.6f"
% (pw(str(k), 12), float(np.mean(vs)), tv0,
float(np.mean(vs)) - tv0))
print(" 겹이 적으면 학습 자료가 적어 오차를 크게 봅니다")
print(" 2 겹은 표본 30 으로 계수 20 을 맞추므로 크게 치우칩니다")
print(" 5 겹부터는 치우침이 확 줄어듭니다")
# --- 문제 2: 교차검증 값 자체가 흔들립니다 -------------------------------
print(" 교차검증 값도 하나의 추정이므로 흔들립니다")
print(" 같은 자료에 나누기만 바꿔 가며 100 번 재 봅니다")
X2, y2, w2 = gen(n1, p1, rng)
print(" %s %s %s %s"
% (pw("겹 수", 12), rw("평균", 14), rw("표준편차", 14),
rw("가장 큰 값 빼기 작은 값", 26)))
for k in [2, 5, 10, 60]:
vs = [cv_error(X2, y2, 1e-8, k, rng) for _ in range(100)]
vs = np.array(vs)
print(" %s %14.6f %14.6f %26.6f"
% (pw(str(k), 12), float(vs.mean()), float(vs.std()),
float(vs.max() - vs.min())))
print(" 하나씩 빼기는 나누는 방법이 하나뿐이라 흔들림이 0 입니다")
print(" 5 겹은 같은 자료인데도 나누기에 따라 값이 크게 달라집니다")
print(" 자료가 바뀌면 얼마나 흔들리는지도 잽니다")
print(" %s %s %s %s"
% (pw("무엇이 바뀌나", 24), rw("표준편차", 16), rw("무엇 때문인가", 22),
rw("어떻게 줄이나", 20)))
sd_split = float(np.std([cv_error(X2, y2, 1e-8, 5, rng) for _ in range(100)]))
sd_data = float(np.std([cv_error(*gen(n1, p1, rng)[:2], 1e-8, 5, rng)
for _ in range(100)]))
print(" %s %16.6f %s %s"
% (pw("나누기만", 24), sd_split, rw("나누는 운", 22),
rw("여러 번 반복해 평균", 20)))
print(" %s %16.6f %s %s"
% (pw("자료까지", 24), sd_data, rw("표본 추출의 운", 22),
rw("자료를 늘리는 수밖에", 20)))
print(" 자료가 바뀌는 쪽이 훨씬 큽니다. 반복으로는 못 없앱니다")
print(" 반복 교차검증은 나누는 운만 지웁니다")
print(" 겹을 늘리면 추정끼리 얼마나 닮는지 봅니다")
print(" 학습 집합 둘 사이에서 서로 다른 부분의 비율은 1 나누기 (k-1) 입니다")
print(" %s %s %s"
% (pw("겹 수", 12), rw("학습 집합 중 다른 부분", 26),
rw("자료가 바뀔 때의 표준편차", 28)))
for k in [2, 5, 10, 60]:
sd = float(np.std([cv_error(*gen(n1, p1, rng, w=wf)[:2], 1e-8, k, rng)
for _ in range(100)]))
print(" %s %26.6f %28.6f"
% (pw(str(k), 12), 1.0 / (k - 1), sd))
print(" 하나씩 빼기는 학습 집합이 1.7 퍼센트만 다릅니다. 60 개 추정이 거의 같습니다")
print(" 그래서 60 번 평균 낸다고 60 배 정확해지지 않습니다")
print(" 163강의 유효 표본 크기가 여기서 다시 나옵니다")
# --- 문제 3: 교차검증으로 lambda 를 고릅니다 ----------------------------
print(" 211강의 lambda 를 교차검증으로 골라 봅니다")
n3, p3 = 50, 30
Xr, yr, wr = gen(n3, p3, rng, sig=1.0, ws=0.3)
Xv, yv, _ = gen(20000, p3, rng, w=wr)
lams = [1e-4, 1e-3, 1e-2, 0.05, 0.2, 1.0, 5.0]
fol3 = kfold_idx(n3, 5, rng)
print(" 후보를 견주려면 모든 후보를 같은 나누기로 재야 합니다")
print(" %s %s %s %s"
% (pw("lambda", 12), rw("5 겹 교차검증", 18), rw("참 오차", 14),
rw("차", 12)))
cvs, tes = [], []
for lam in lams:
c = cv_error(Xr, yr, lam, 5, rng, fol3)
t = mse(Xv, yv, ridge(Xr, yr, lam))
cvs.append(c)
tes.append(t)
print(" %s %18.6f %14.6f %12.6f"
% (pw("%.4f" % lam, 12), c, t, c - t))
i_cv = int(np.argmin(cvs))
i_te = int(np.argmin(tes))
print(" 교차검증이 고른 lambda 는 %.4f 입니다" % lams[i_cv])
print(" 참 오차가 가장 작은 lambda 는 %.4f 입니다" % lams[i_te])
print(" 교차검증이 고른 자리와 참 오차가 가장 작은 자리가 다릅니다")
print(" 그런데 참 오차로 보면 2.000586 과 1.926198 로 거의 같습니다")
print(" 곡선이 바닥 근처에서 평평해 어느 쪽을 골라도 손해가 작습니다")
print(" 값 자체는 잘 안 맞습니다. 큰 lambda 쪽에서는 위로 작은 쪽에서는 아래로 틀립니다")
print(" 교차검증은 값을 맞히는 도구가 아니라 순서를 대충 맞히는 도구입니다")
print(" 나누기를 후보마다 새로 하면 어떻게 되는지 봅니다")
print(" %s %s %s %s"
% (pw("lambda", 12), rw("같은 나누기", 16), rw("후보마다 새 나누기", 22),
rw("차", 12)))
for lam in lams:
a = cv_error(Xr, yr, lam, 5, rng, fol3)
b = cv_error(Xr, yr, lam, 5, rng)
print(" %s %16.6f %22.6f %12.6f"
% (pw("%.4f" % lam, 12), a, b, b - a))
print(" 왼쪽 열은 lambda 0.2000 을 고르는데 오른쪽 열은 0.0500 을 고릅니다")
print(" 나누는 운이 후보 사이 차이보다 커져 답이 바뀌었습니다")
print(" 후보를 견줄 때는 반드시 같은 나누기를 씁니다")
print(" 고른 lambda 의 교차검증 값을 성능으로 보고하면 안 됩니다")
print(" %s %s %s"
% (pw("무엇", 30), rw("값", 16), rw("참 오차와의 차", 18)))
w_sel = ridge(Xr, yr, lams[i_cv])
t_sel = mse(Xv, yv, w_sel)
for nm, v in [("고른 lambda 의 교차검증 값", cvs[i_cv]),
("고른 lambda 의 참 오차", t_sel),
("교차검증 값 중 가장 작은 것", min(cvs))]:
print(" %s %16.6f %18.6f" % (pw(nm, 30), v, v - t_sel))
print(" 7 개 중 가장 작은 것을 골랐으니 그 값은 이미 낙관되어 있습니다")
print(" 189강 문제 3 의 여러 번 보기 문제가 여기서도 나옵니다")
print(" 후보가 늘면 낙관이 얼마나 커지는지 잽니다")
print(" 아무 쓸모 없는 후보를 늘려 가며 최소값이 얼마나 내려가는지 봅니다")
print(" %s %s %s"
% (pw("후보 수", 12), rw("최소 교차검증 값", 20), rw("참 오차", 14)))
lam_b = lams[i_cv]
te_b = mse(Xv, yv, ridge(Xr, yr, lam_b))
for m in [1, 5, 20, 100]:
vals = [cv_error(Xr, yr, lam_b, 5, rng) for _ in range(m)]
print(" %s %20.6f %14.6f"
% (pw(str(m), 12), float(min(vals)), te_b))
print(" 후보는 모두 같은 lambda 이고 나누기만 다릅니다")
print(" 그런데 후보가 늘수록 최소값이 계속 내려갑니다. 참 오차는 그대로입니다")
print(" 가장 좋은 것을 고르는 행위 자체가 값을 끌어내립니다")
# --- 문제 4: 흔한 실수 -------------------------------------------------
print(" 교차검증을 잘못 쓰는 대표적인 방식을 봅니다")
print(" 라벨과 아무 상관 없는 변수 3000 개에서 상관 큰 20 개를 고릅니다")
n4, p4 = 60, 3000
def cv_err_sel(X, y, k, r, pre):
fol = kfold_idx(len(y), k, r)
es = []
for i in range(k):
te = fol[i]
tr = np.concatenate([fol[j] for j in range(k) if j != i])
if pre is None:
cc = np.abs(X[tr].T @ (y[tr] - y[tr].mean())) / len(tr)
sel = np.argsort(-cc)[:20]
else:
sel = pre
es.append(mse(X[te][:, sel], y[te],
ridge(X[tr][:, sel], y[tr], 1e-3)))
return float(np.mean(es))
bad, good = [], []
for _ in range(60):
X4 = rng.normal(0, 1, (n4, p4))
y4 = rng.normal(0, 1, n4)
c4 = np.abs(X4.T @ (y4 - y4.mean())) / n4
top = np.argsort(-c4)[:20]
bad.append(cv_err_sel(X4, y4, 5, rng, top))
good.append(cv_err_sel(X4, y4, 5, rng, None))
print(" 60 번 반복해 평균 냅니다")
print(" %s %s %s"
% (pw("언제 변수를 골랐나", 26), rw("5 겹 교차검증 오차", 22),
rw("맞나", 10)))
print(" %s %22.6f %s"
% (pw("전체 자료로 먼저 고름", 26), float(np.mean(bad)), rw("아니오", 10)))
print(" %s %22.6f %s"
% (pw("겹 안에서 다시 고름", 26), float(np.mean(good)), rw("예", 10)))
print(" %s %22.6f %s"
% (pw("참 오차 (라벨이 무작위)", 26), 1.0, rw("기준", 10)))
print(" 라벨이 무작위이므로 어떤 방법도 오차 1.0 아래로 못 갑니다")
print(" 먼저 고르면 시험지의 답을 미리 본 셈이라 오차가 내려갑니다")
print(" 제대로 하면 오히려 1.0 보다 큽니다. 쓸모없는 변수 20 개를 넣었으니 당연합니다")
print(" 변수 선택은 전처리가 아니라 학습의 일부입니다")
print(" 자료에 구조가 있으면 무엇을 어떻게 나눠야 하는지 봅니다")
print(" %s %s %s"
% (pw("어떤 자료", 22), rw("무엇이 새는가", 24), rw("어떻게 나누나", 22)))
for a, b, c in [("시계열", "미래로 과거를 맞힘", "시점 기준 앞뒤로"),
("한 사람이 여러 줄", "같은 사람이 양쪽에", "사람 단위로"),
("여러 병원 자료", "같은 장비 특성", "병원 단위로"),
("중복 기록", "같은 줄이 양쪽에", "중복 먼저 제거")]:
print(" %s %s %s" % (pw(a, 22), rw(b, 24), rw(c, 22)))
print(" 199강에서 시계열은 앞뒤를 지켜야 한다고 했습니다")
print(" 같은 개체가 양쪽에 들어가면 얼마나 새는지 잽니다")
n5, m5 = 40, 5
sub = np.repeat(np.arange(n5), m5)
u = rng.normal(0, 1.5, n5)
Z5 = rng.normal(0, 1, (n5 * m5, 3))
w5 = np.array([1.0, -0.5, 0.3])
y5 = Z5 @ w5 + u[sub] + rng.normal(0, 0.3, n5 * m5)
D5 = np.zeros((n5 * m5, n5))
D5[np.arange(n5 * m5), sub] = 1.0
X5 = np.hstack([Z5, D5])
def cv_group(X, y, g, k, r, by_group):
if by_group:
gs = np.unique(g)
fol = kfold_idx(len(gs), k, r)
fol = [np.where(np.isin(g, gs[f]))[0] for f in fol]
else:
fol = kfold_idx(len(y), k, r)
es = []
for i in range(k):
te = fol[i]
tr = np.concatenate([fol[j] for j in range(k) if j != i])
es.append(mse(X[te], y[te], ridge(X[tr], y[tr], 1e-3)))
return float(np.mean(es))
print(" 한 사람에게서 5 줄씩 나오고 사람마다 고유한 치우침이 있습니다")
print(" 모형은 사람 더미 40 개를 변수로 씁니다. 186강의 더미변수입니다")
print(" %s %s %s"
% (pw("어떻게 나눴나", 22), rw("교차검증 오차", 18), rw("무엇을 재나", 22)))
print(" %s %18.6f %s"
% (pw("줄 단위로", 22), cv_group(X5, y5, sub, 5, rng, False),
rw("본 사람의 새 줄", 22)))
print(" %s %18.6f %s"
% (pw("사람 단위로", 22), cv_group(X5, y5, sub, 5, rng, True),
rw("처음 보는 사람", 22)))
print(" 줄 단위로 나누면 시험지의 사람을 학습에서 이미 봤습니다")
print(" 그 사람의 치우침을 외운 채로 시험을 보므로 오차가 작게 나옵니다")
print(" 둘 다 틀린 값은 아닙니다. 재는 대상이 다를 뿐입니다")
print(" 쓸 곳이 처음 보는 사람이면 사람 단위가 맞는 값입니다")
# --- 문제 5: 실무에서 쓰기 ---------------------------------------------
print(" 실무에서 교차검증을 쓸 때의 선택을 정리합니다")
print(" %s %s %s"
% (pw("상황", 22), rw("무엇을 쓰나", 20), rw("왜", 26)))
for a, b, c in [("자료가 아주 적음", "하나씩 빼기", "학습 자료를 최대로"),
("보통", "5 겹 또는 10 겹", "편향과 계산의 절충"),
("갈래가 치우침", "층화 겹", "겹마다 비율을 지킴"),
("자료가 아주 많음", "따로 떼기", "한 번으로 충분"),
("고를 것이 많음", "겹을 두 겹으로", "고르기와 재기를 분리")]:
print(" %s %s %s" % (pw(a, 22), rw(b, 20), rw(c, 26)))
print(" 마지막 줄이 문제 3 에서 본 낙관을 없애는 방법입니다")
print(" 두 겹 교차검증으로 낙관을 없애 봅니다")
print(" 안쪽에서 lambda 를 고르고 바깥쪽에서 성능을 잽니다")
def nested(X, y, lams_, kout, kin, r):
fol = kfold_idx(len(y), kout, r)
es, picks = [], []
for i in range(kout):
te = fol[i]
tr = np.concatenate([fol[j] for j in range(kout) if j != i])
cs = [cv_error(X[tr], y[tr], lm, kin, r) for lm in lams_]
lm = lams_[int(np.argmin(cs))]
picks.append(lm)
es.append(mse(X[te], y[te], ridge(X[tr], y[tr], lm)))
return float(np.mean(es)), picks
e_nest, picks = nested(Xr, yr, lams, 5, 4, rng)
print(" 한 번만 재면 자료 하나의 운이 섞이므로 40 번 반복해 평균 냅니다")
print(" %s %s %s"
% (pw("무엇", 28), rw("40 번 평균", 16), rw("참 오차와의 차", 18)))
a1, a2, a3 = [], [], []
for _ in range(40):
Xq, yq, wq = gen(n3, p3, rng, sig=1.0, ws=0.3)
Xw, yw, _ = gen(4000, p3, rng, w=wq)
fq = kfold_idx(n3, 5, rng)
cq = [cv_error(Xq, yq, lm, 5, rng, fq) for lm in lams]
lq = lams[int(np.argmin(cq))]
a1.append(min(cq))
a2.append(nested(Xq, yq, lams, 5, 4, rng)[0])
a3.append(mse(Xw, yw, ridge(Xq, yq, lq)))
t3 = float(np.mean(a3))
for nm, v in [("한 겹 교차검증의 최소값", float(np.mean(a1))),
("두 겹 교차검증 값", float(np.mean(a2))),
("고른 lambda 의 참 오차", t3)]:
print(" %s %16.6f %18.6f" % (pw(nm, 28), v, v - t3))
print(" 한 겹의 최소값에는 반대 방향의 치우침 둘이 섞여 있습니다")
print(" 학습 자료가 40 개뿐이라 위로 가고 7 개 중 최소를 골라 아래로 갑니다")
print(" 둘이 거의 상쇄되어 0.067355 밖에 안 어긋납니다. 우연히 잘 맞은 것입니다")
print(" 두 겹은 고르기의 낙관만 지우므로 위 치우침이 남아 0.232023 이 됩니다")
print(" 두 겹이 더 정확한 값을 주지는 않습니다. 정직한 값을 줄 뿐입니다")
print(" 바깥 겹마다 고른 lambda 는 %s 입니다"
% " ".join("%.4f" % v for v in picks))
print(" 겹마다 다른 lambda 를 고르는 것이 정상입니다")
print(" 두 겹 교차검증이 재는 것은 lambda 하나가 아니라 고르는 절차입니다")
print(" 교차검증 곡선이 평평할 때 어떻게 고르는지 봅니다")
print(" %s %s %s %s"
% (pw("lambda", 12), rw("교차검증", 14), rw("한 표준오차 위인가", 22),
rw("계수 크기", 14)))
fol_s = fol3
ses = []
for lam in lams:
per = []
for i in range(5):
te = fol_s[i]
tr = np.concatenate([fol_s[j] for j in range(5) if j != i])
per.append(mse(Xr[te], yr[te], ridge(Xr[tr], yr[tr], lam)))
ses.append((float(np.mean(per)), float(np.std(per) / np.sqrt(5))))
i_m = int(np.argmin([a for a, _ in ses]))
thr = ses[i_m][0] + ses[i_m][1]
for lam, (m_, s_) in zip(lams, ses):
print(" %s %14.6f %s %14.6f"
% (pw("%.4f" % lam, 12), m_,
rw("예" if m_ <= thr else "아니오", 22),
float(np.linalg.norm(ridge(Xr, yr, lam)))))
print(" 최소값에 한 표준오차를 더한 문턱이 %.6f 입니다" % thr)
print(" 그 안에 드는 가장 큰 lambda 를 고르면 더 단순한 모형이 됩니다")
print(" 이 예에서는 문턱 안에 드는 것이 최소 자리 하나뿐이라 답이 안 바뀝니다")
print(" 곡선이 평평할 때라야 규칙이 일을 합니다. 그때는 더 큰 lambda 를 고릅니다")
print(" 마지막으로 교차검증이 못 하는 것을 정리합니다")
print(" %s %s"
% (pw("무엇을 못 하나", 26), rw("왜", 34)))
for a, b in [("분포가 바뀌면 못 잡음", "같은 분포라고 가정하고 나눔"),
("표본이 적으면 흔들림", "문제 2 의 표준편차가 큼"),
("여러 번 보면 낙관", "문제 3 의 후보 수 효과"),
("샌 자료를 못 잡음", "문제 4 의 개체 겹침")]:
print(" %s %s" % (pw(a, 26), rw(b, 34)))
print(" 교차검증은 만능이 아니라 가정 위에서만 맞는 도구입니다")
print(" 212강은 lambda 를 고르는 법을 봤습니다. 213강은 차원의 저주를 봅니다")
# 205강 문제 1 에서 같은 자료로 고르고 재면 낙관된다고 했습니다
# 이제 그 낙관이 얼마나 되는지 재고 어떻게 없애는지 봅니다
# 한 번만 재면 운이 섞이므로 자료를 200 번 새로 뽑아 평균 냅니다
# 무엇으로 쟀나 평균 참 오차와의 차 표준편차
# 학습 자료 그대로 0.664301 -0.849451 0.138007
# 따로 뗀 20 개 2.059905 0.546153 0.765656
# 5 겹 교차검증 1.749904 0.236153 0.428040
# 참 오차 20000 개 1.513751 0.000000 0.228063
# 학습 자료로 잰 값이 참 오차보다 한참 작습니다
# 표본 60 에 계수 20 이면 자유도의 3 분의 1 을 자료 맞추기에 씁니다
# 교차검증은 모든 자료를 한 번씩 시험지로 씁니다
# 왜 모든 자료를 시험지로 쓰는 것이 이득인지 봅니다
# 방법 학습에 쓰는 수 시험에 쓰는 수 추정을 몇 번 평균
# 따로 떼기 40 20 1
# 5 겹 48 60 5
# 10 겹 54 60 10
# 하나씩 빼기 59 60 60
# 겹을 늘리면 학습에 쓰는 자료가 늘어 편향이 줄어듭니다
# 대신 학습 집합끼리 겹쳐서 추정끼리 상관됩니다
# 그래서 겹을 늘려도 분산이 마냥 줄지는 않습니다. 문제 2 에서 봅니다
# 겹 수에 따라 편향이 얼마나 다른지 잽니다
# 겹 수 교차검증 평균 참 오차 치우친 정도
# 2 3.154991 1.492736 1.662255
# 5 1.800753 1.492736 0.308017
# 10 1.605659 1.492736 0.112923
# 60 1.537831 1.492736 0.045096
# 겹이 적으면 학습 자료가 적어 오차를 크게 봅니다
# 2 겹은 표본 30 으로 계수 20 을 맞추므로 크게 치우칩니다
# 5 겹부터는 치우침이 확 줄어듭니다
# 교차검증 값도 하나의 추정이므로 흔들립니다
# 같은 자료에 나누기만 바꿔 가며 100 번 재 봅니다
# 겹 수 평균 표준편차 가장 큰 값 빼기 작은 값
# 2 3.209785 1.138035 8.478569
# 5 1.549662 0.207097 0.912511
# 10 1.455124 0.120413 0.707143
# 60 1.390711 0.000000 0.000000
# 하나씩 빼기는 나누는 방법이 하나뿐이라 흔들림이 0 입니다
# 5 겹은 같은 자료인데도 나누기에 따라 값이 크게 달라집니다
# 자료가 바뀌면 얼마나 흔들리는지도 잽니다
# 무엇이 바뀌나 표준편차 무엇 때문인가 어떻게 줄이나
# 나누기만 0.196570 나누는 운 여러 번 반복해 평균
# 자료까지 0.461954 표본 추출의 운 자료를 늘리는 수밖에
# 자료가 바뀌는 쪽이 훨씬 큽니다. 반복으로는 못 없앱니다
# 반복 교차검증은 나누는 운만 지웁니다
# 겹을 늘리면 추정끼리 얼마나 닮는지 봅니다
# 학습 집합 둘 사이에서 서로 다른 부분의 비율은 1 나누기 (k-1) 입니다
# 겹 수 학습 집합 중 다른 부분 자료가 바뀔 때의 표준편차
# 2 1.000000 1.253808
# 5 0.250000 0.468251
# 10 0.111111 0.366278
# 60 0.016949 0.356416
# 하나씩 빼기는 학습 집합이 1.7 퍼센트만 다릅니다. 60 개 추정이 거의 같습니다
# 그래서 60 번 평균 낸다고 60 배 정확해지지 않습니다
# 163강의 유효 표본 크기가 여기서 다시 나옵니다
# 211강의 lambda 를 교차검증으로 골라 봅니다
# 후보를 견주려면 모든 후보를 같은 나누기로 재야 합니다
# lambda 5 겹 교차검증 참 오차 차
# 0.0001 5.067032 2.861638 2.205394
# 0.0010 4.829982 2.849550 1.980432
# 0.0100 3.450478 2.740753 0.709725
# 0.0500 2.061907 2.424023 -0.362116
# 0.2000 1.595194 2.000586 -0.405392
# 1.0000 2.018717 1.926198 0.092519
# 5.0000 2.957458 2.577949 0.379509
# 교차검증이 고른 lambda 는 0.2000 입니다
# 참 오차가 가장 작은 lambda 는 1.0000 입니다
# 교차검증이 고른 자리와 참 오차가 가장 작은 자리가 다릅니다
# 그런데 참 오차로 보면 2.000586 과 1.926198 로 거의 같습니다
# 곡선이 바닥 근처에서 평평해 어느 쪽을 골라도 손해가 작습니다
# 값 자체는 잘 안 맞습니다. 큰 lambda 쪽에서는 위로 작은 쪽에서는 아래로 틀립니다
# 교차검증은 값을 맞히는 도구가 아니라 순서를 대충 맞히는 도구입니다
# 나누기를 후보마다 새로 하면 어떻게 되는지 봅니다
# lambda 같은 나누기 후보마다 새 나누기 차
# 0.0001 5.067032 2.609752 -2.457280
# 0.0010 4.829982 2.809754 -2.020228
# 0.0100 3.450478 3.481117 0.030639
# 0.0500 2.061907 1.616570 -0.445338
# 0.2000 1.595194 1.790775 0.195582
# 1.0000 2.018717 1.916179 -0.102537
# 5.0000 2.957458 2.975685 0.018227
# 왼쪽 열은 lambda 0.2000 을 고르는데 오른쪽 열은 0.0500 을 고릅니다
# 나누는 운이 후보 사이 차이보다 커져 답이 바뀌었습니다
# 후보를 견줄 때는 반드시 같은 나누기를 씁니다
# 고른 lambda 의 교차검증 값을 성능으로 보고하면 안 됩니다
# 무엇 값 참 오차와의 차
# 고른 lambda 의 교차검증 값 1.595194 -0.405392
# 고른 lambda 의 참 오차 2.000586 0.000000
# 교차검증 값 중 가장 작은 것 1.595194 -0.405392
# 7 개 중 가장 작은 것을 골랐으니 그 값은 이미 낙관되어 있습니다
# 189강 문제 3 의 여러 번 보기 문제가 여기서도 나옵니다
# 후보가 늘면 낙관이 얼마나 커지는지 잽니다
# 아무 쓸모 없는 후보를 늘려 가며 최소값이 얼마나 내려가는지 봅니다
# 후보 수 최소 교차검증 값 참 오차
# 1 1.728606 2.000586
# 5 1.191139 2.000586
# 20 1.119750 2.000586
# 100 1.060290 2.000586
# 후보는 모두 같은 lambda 이고 나누기만 다릅니다
# 그런데 후보가 늘수록 최소값이 계속 내려갑니다. 참 오차는 그대로입니다
# 가장 좋은 것을 고르는 행위 자체가 값을 끌어내립니다
# 교차검증을 잘못 쓰는 대표적인 방식을 봅니다
# 라벨과 아무 상관 없는 변수 3000 개에서 상관 큰 20 개를 고릅니다
# 60 번 반복해 평균 냅니다
# 언제 변수를 골랐나 5 겹 교차검증 오차 맞나
# 전체 자료로 먼저 고름 0.490653 아니오
# 겹 안에서 다시 고름 1.337844 예
# 참 오차 (라벨이 무작위) 1.000000 기준
# 라벨이 무작위이므로 어떤 방법도 오차 1.0 아래로 못 갑니다
# 먼저 고르면 시험지의 답을 미리 본 셈이라 오차가 내려갑니다
# 제대로 하면 오히려 1.0 보다 큽니다. 쓸모없는 변수 20 개를 넣었으니 당연합니다
# 변수 선택은 전처리가 아니라 학습의 일부입니다
# 자료에 구조가 있으면 무엇을 어떻게 나눠야 하는지 봅니다
# 어떤 자료 무엇이 새는가 어떻게 나누나
# 시계열 미래로 과거를 맞힘 시점 기준 앞뒤로
# 한 사람이 여러 줄 같은 사람이 양쪽에 사람 단위로
# 여러 병원 자료 같은 장비 특성 병원 단위로
# 중복 기록 같은 줄이 양쪽에 중복 먼저 제거
# 199강에서 시계열은 앞뒤를 지켜야 한다고 했습니다
# 같은 개체가 양쪽에 들어가면 얼마나 새는지 잽니다
# 한 사람에게서 5 줄씩 나오고 사람마다 고유한 치우침이 있습니다
# 모형은 사람 더미 40 개를 변수로 씁니다. 186강의 더미변수입니다
# 어떻게 나눴나 교차검증 오차 무엇을 재나
# 줄 단위로 0.152363 본 사람의 새 줄
# 사람 단위로 2.061251 처음 보는 사람
# 줄 단위로 나누면 시험지의 사람을 학습에서 이미 봤습니다
# 그 사람의 치우침을 외운 채로 시험을 보므로 오차가 작게 나옵니다
# 둘 다 틀린 값은 아닙니다. 재는 대상이 다를 뿐입니다
# 쓸 곳이 처음 보는 사람이면 사람 단위가 맞는 값입니다
# 실무에서 교차검증을 쓸 때의 선택을 정리합니다
# 상황 무엇을 쓰나 왜
# 자료가 아주 적음 하나씩 빼기 학습 자료를 최대로
# 보통 5 겹 또는 10 겹 편향과 계산의 절충
# 갈래가 치우침 층화 겹 겹마다 비율을 지킴
# 자료가 아주 많음 따로 떼기 한 번으로 충분
# 고를 것이 많음 겹을 두 겹으로 고르기와 재기를 분리
# 마지막 줄이 문제 3 에서 본 낙관을 없애는 방법입니다
# 두 겹 교차검증으로 낙관을 없애 봅니다
# 안쪽에서 lambda 를 고르고 바깥쪽에서 성능을 잽니다
# 한 번만 재면 자료 하나의 운이 섞이므로 40 번 반복해 평균 냅니다
# 무엇 40 번 평균 참 오차와의 차
# 한 겹 교차검증의 최소값 1.951196 0.067355
# 두 겹 교차검증 값 2.115865 0.232023
# 고른 lambda 의 참 오차 1.883841 0.000000
# 한 겹의 최소값에는 반대 방향의 치우침 둘이 섞여 있습니다
# 학습 자료가 40 개뿐이라 위로 가고 7 개 중 최소를 골라 아래로 갑니다
# 둘이 거의 상쇄되어 0.067355 밖에 안 어긋납니다. 우연히 잘 맞은 것입니다
# 두 겹은 고르기의 낙관만 지우므로 위 치우침이 남아 0.232023 이 됩니다
# 두 겹이 더 정확한 값을 주지는 않습니다. 정직한 값을 줄 뿐입니다
# 바깥 겹마다 고른 lambda 는 1.0000 0.2000 0.2000 1.0000 0.2000 입니다
# 겹마다 다른 lambda 를 고르는 것이 정상입니다
# 두 겹 교차검증이 재는 것은 lambda 하나가 아니라 고르는 절차입니다
# 교차검증 곡선이 평평할 때 어떻게 고르는지 봅니다
# lambda 교차검증 한 표준오차 위인가 계수 크기
# 0.0001 5.067032 아니오 1.815020
# 0.0010 4.829982 아니오 1.811482
# 0.0100 3.450478 아니오 1.778384
# 0.0500 2.061907 아니오 1.664139
# 0.2000 1.595194 예 1.410720
# 1.0000 2.018717 아니오 0.879639
# 5.0000 2.957458 아니오 0.331924
# 최소값에 한 표준오차를 더한 문턱이 1.937942 입니다
# 그 안에 드는 가장 큰 lambda 를 고르면 더 단순한 모형이 됩니다
# 이 예에서는 문턱 안에 드는 것이 최소 자리 하나뿐이라 답이 안 바뀝니다
# 곡선이 평평할 때라야 규칙이 일을 합니다. 그때는 더 큰 lambda 를 고릅니다
# 마지막으로 교차검증이 못 하는 것을 정리합니다
# 무엇을 못 하나 왜
# 분포가 바뀌면 못 잡음 같은 분포라고 가정하고 나눔
# 표본이 적으면 흔들림 문제 2 의 표준편차가 큼
# 여러 번 보면 낙관 문제 3 의 후보 수 효과
# 샌 자료를 못 잡음 문제 4 의 개체 겹침
# 교차검증은 만능이 아니라 가정 위에서만 맞는 도구입니다
# 212강은 lambda 를 고르는 법을 봤습니다. 213강은 차원의 저주를 봅니다