단원 홈
4단원 · 7차시

스무 줄로 만든 첫 모델,
그리고 넘어야 할 기준선

지난 시간에 다듬고 나눈 표 위에, 오늘은 2단원에서 직접 짠 k-NN 을 그대로 얹습니다. 프로젝트에서 처음으로 ‘작동하는 것’이 나오는 시간입니다. 그런데 나온 숫자가 좋은 숫자인지는, 그 숫자 혼자서는 절대 말해 주지 않습니다.

성취기준 12인기04-03
k-최근접 이웃기준선 다수결훈련·테스트 정확도 %p실험 기록
🎯 학습 목표
  • 6차시가 만든 훈련 110 · 테스트 48 위에 k-NN 을 얹어, 팀의 첫 모델을 실제로 돌린다.
  • k 를 바꿔 가며 훈련 정확도와 테스트 정확도를 재고, 두 곡선이 갈라지는 자리를 읽는다.
  • 기준선을 함께 계산해, 우리 모델의 성능을 “몇 %” 가 아니라 “기준선보다 몇 %p” 로 말한다.
🤔

여는 장면 — 85.4% 는 좋은 숫자인가

4분 · 오늘 팀이 해야 할 일 하나

한 팀이 코드를 돌렸습니다. 화면 맨 아래에 이런 줄이 찍혔습니다.

📖 화면에 뜬 한 줄

테스트 정확도 85.4% (41/48)

팀원들이 환호했습니다. 그런데 옆 팀이 지나가며 말합니다. “우리는 92% 나왔는데.” 순간 조용해집니다. 우리가 진 걸까요?

이 물음에는 아직 답할 수 없습니다. 두 숫자를 나란히 놓는 것만으로는 아무것도 알 수 없기 때문입니다. 답하려면 먼저 다른 것을 물어야 합니다.

🎯 먼저 물어야 할 것

코드를 한 줄도 짜지 않은 모델은 몇 점일까?
우리 데이터에서 늘 ‘가능’ 이라고만 대답하는 모델의 점수를 재어 보면 60.4% 입니다. 그러니 85.4% 는 ‘85.4점’ 이 아니라 60.4% 위에 25.0%p 를 쌓아 올린 것입니다.

옆 팀은 어떨까요. 만약 옆 팀 문제의 아무것도 안 하는 모델이 90% 라면, 옆 팀의 92% 는 겨우 +2%p 입니다. 그러면 이긴 쪽은 우리입니다. 정확도는 홀로는 아무 뜻이 없습니다. 늘 견줄 것을 함께 적어야 숫자가 됩니다.

2단원 12차시에서 이미 한 번 겪은 이야기입니다. “정확도 98% 짜리 쓸모없는 모델” — 1,000명 중 환자가 20명인 검진에서 모두에게 ‘정상’ 이라고만 답해도 98점이 나왔지요. 그때는 남의 이야기였지만, 오늘은 우리 손으로 만든 모델에 같은 잣대를 댑니다.

한 사람이 키보드와 마우스를 잡고 모니터를 보고, 옆에 앉은 사람이 손가락으로 화면을 가리키고 있다
오늘 22분은 이 장면이어야 합니다 — 한 사람이 키보드를 잡고, 옆 사람이 화면을 짚어 가며 출력을 읽습니다. 빈칸 다섯 곳을 채우고 나면 화면에 표 하나가 뜨는데, 그 표를 함께 읽는 사람이 있어야 숫자가 그냥 지나가지 않습니다. 출처: Calqui, Wikimedia Commons (CC BY-SA 3.0)
💡 오늘 팀이 만들 것 — 산출물 셋
  • k 표 — k 를 바꿔 가며 잰 훈련 정확도와 테스트 정확도
  • 기준선 한 줄 — 아무것도 안 배운 모델의 점수, 그리고 우리와의 차이(%p)
  • 실험 기록 첫 줄 — 오늘 쓴 설정과 결과를 공책에 한 줄. 10차시가 이 줄들을 쌓아 씁니다.
1

도구는 이미 만들어 두었다 — 2단원 8차시의 세 함수

개념 · 다시 배우지 않는다. 가져다 쓴다

오늘 새로 배우는 알고리즘은 없습니다. 2단원 8차시 「가까운 것끼리 — 이웃 몇 명에게 물어볼 것인가」에서 여러분은 nearest · knn · accuracy 세 함수를 손으로 짰습니다 — 앞의 둘은 빈칸을 직접 채웠고, accuracy 는 그 자리에서 함께 읽었지요. 오늘은 그 세 함수를 글자 하나 고치지 않고 우리 데이터 위에 다시 얹습니다. (오늘은 accuracy 도 빈칸입니다. 그때 읽기만 한 한 줄을 이번에는 직접 씁니다.)

걸음함수하는 일어디서 배웠나
①nearest 훈련 데이터를 거리 순으로 줄 세우고 앞에서 k 개를 뽑는다2단원 8차시
②knn 뽑힌 k 개의 이름표를 세어 다수결로 답한다2단원 8차시
③accuracy 맞힌 개수를 전체로 나눈다2단원 8차시
거리dist 차를 제곱해 모두 더하고 뿌리를 씌운다. 특성이 몇 개든 상관없다2단원 5차시
자minmax_fit / minmax_apply 0~1 로 옮길 기준을 훈련에서만 뽑아 적용한다2단원 5차시 · 4단원 6차시

여기서 눈여겨볼 것은 순서입니다. k-NN 은 거리로 답을 정합니다. 그래서 2단원 5차시 「센티미터와 걸음 수를 나란히」의 정규화가 반드시 앞에 와야 합니다. 6차시에서 이미 해 두었지요 — 밝기는 80~331, 반사도는 0.43~1.7 이라 자를 맞추지 않으면 거리가 밝기 하나의 것이 됩니다.

⚠️ 6차시의 훈련/테스트가 ‘넘어오는’ 것이 아니다

파이썬 실행기는 쪽마다 새로 켜집니다. 6차시 쪽에서 만든 train·test 는 이 쪽에 남아 있지 않습니다. 그냥 쓰면 첫 줄에서 NameError 로 죽습니다.

그래서 오늘 코드 맨 위 【0 이어받기】가 6차시와 똑같은 코드로 훈련 110 · 테스트 48 을 다시 만듭니다. 다시 만들어도 같은 것이 나오는 까닭은 씨앗(SEED = 42)을 고정했기 때문입니다. 씨앗을 고정하지 않았다면 6차시와 7차시가 서로 다른 데이터로 이야기하게 됩니다.

정규화·분할·k-NN 을 다시 설명하지 않는 것은 시간을 아끼려는 것만이 아닙니다. 이 단원은 배우는 단원이 아니라 만드는 단원이기 때문입니다. 앞 단원에서 만든 부품이 실제로 쓸 만한 물건이었는지는, 그것을 우리 데이터에 얹어 봐야 압니다.

2

기준선 — 견줄 것이 없으면 정확도는 숫자가 아니다

개념 · 오늘의 논지가 여기 있다

기준선은 2단원 11차시에서 이미 만난 말입니다. 거기서 k 를 훈련 인원수(45)까지 키우자 누구를 물어도 같은 답만 나왔고, 그 점수가 바로 “아무것도 안 배운 값” 이었지요.

만드는 법은 한 문장입니다.

ℹ️ 기준선 모델

훈련 데이터에서 가장 흔한 이름표를 하나 고르고, 무엇을 물어도 그것만 대답한다. 코드가 필요 없고, 특성을 보지도 않습니다.

견본 데이터로 실제로 세어 보면 이렇습니다.

어디가능불가합여기서 나오는 것
훈련5654110 가장 흔한 이름표 = ‘가능’ (여기서 고른다)
테스트291948 늘 ‘가능’ 이라 하면 29개를 맞힌다 → 29/48 = 60.4%

훈련의 56 대 54 는 아슬아슬한 차이입니다. 두 개만 뒤집혀도 기준선의 이름표가 ‘불가’ 로 바뀝니다. 그래도 규칙은 규칙입니다 — 가장 흔한 이름표는 반드시 훈련에서 고릅니다.

⚠️ 테스트를 보고 고르면 그것도 누수다

“테스트에 가능이 29개니까 가능으로 하자” 는 시험지를 미리 본 것입니다. 이 견본에서는 훈련도 테스트도 ‘가능’ 이 많아 어느 쪽으로 골라도 60.4% 로 값이 같습니다. 값이 같다고 규칙이 없어지지는 않습니다. 다른 데이터에서는 값이 갈리고, 그때 기준선이 낮게 잡히면 우리 모델이 실제보다 좋아 보입니다.

테스트 48개를 몇 개나 맞히는가 기준선 · 늘 '가능' 29/48 60.4% 우리 모델 · k=7 41/48 85.4% +25.0%p 이 화살표의 길이가 '우리가 만든 것'이다. 왼쪽 60.4% 는 코드를 한 줄도 짜지 않아도 나온다.

기준선 60.4% 와 k=7 모델 85.4% (견본 데이터 · 씨앗 42 · 테스트 48개). 발표에 “85.4%” 만 적으면 왼쪽 회색 막대가 통째로 감춰집니다.

%p 라는 단위도 여기서 굳혀 둡시다. 60.4% 에서 85.4% 로 간 것은 “25% 올랐다” 가 아니라 25.0%p 차이입니다. 비율의 차를 말할 때는 %p 를 씁니다. 이 표기 하나가 발표에서 오해를 크게 줄여 줍니다.

3

손잡이는 k 하나 — 그런데 정답이 없다

개념 · 표 하나가 세 가지를 말한다

k-NN 에서 우리가 돌릴 수 있는 손잡이는 k 하나입니다. 작으면 잡음 한 점에 휘둘리고, 크면 뭉개집니다. 2단원 11차시에서 두 곡선이 갈라지는 그림을 이미 봤지요. 그 그림이 우리 데이터에서도 그대로 나오는지가 오늘 확인할 것입니다.

견본 데이터(훈련 110 · 테스트 48 · 씨앗 42)로 잰 표입니다.

k훈련 정확도테스트 정확도맞힌 수읽는 법
1100.0%70.8%34/48 훈련은 만점, 테스트는 가장 나쁘다
384.5%81.2%39/48 k=1 보다 10.4%p 좋아졌다
581.8%83.3%40/48 계속 오른다
776.4%85.4%41/48 이 표에서 가장 높다
978.2%79.2%38/48 여기서부터 내려간다
1576.4%75.0%36/48 훈련도 테스트도 함께 낮다
2577.3%75.0%36/48 더 키워도 나아지지 않는다

이 표 하나가 세 가지를 말합니다.

1️⃣

k=1 의 훈련 100% 는 자랑이 아니다

훈련의 한 점에게 가장 가까운 이웃은 자기 자신이고 거리가 0.0 입니다. 자기 답을 자기가 베낀 것이니 100% 가 나오는 게 당연합니다. 같은 판의 테스트는 70.8% 로 표에서 가장 낮습니다.

2️⃣

k 를 키우면 좋아지다가 다시 나빠진다

70.8 → 81.2 → 83.3 → 85.4 → 79.2 → 75.0 → 75.0. 작으면 잡음 한 점에 휘둘리고 크면 뭉개진다가 한 표에서 둘 다 보입니다.

3️⃣

k 를 끝까지 키우면 기준선이 된다

k 가 훈련 크기(110)와 같아지면 모든 점의 이웃이 훈련 전체가 되어 늘 같은 다수결만 나옵니다. 그때 테스트 정확도는 60.4% — 기준선과 정확히 같아집니다.

⚠️ 짝수 k 를 표에 넣지 마라

k 가 짝수면 표가 3 대 3 처럼 동점이 날 수 있습니다. 그때 max(votes, key=votes.get) 는 먼저 들어간 이름표, 곧 더 가까운 이웃의 답을 돌려줍니다. 우연에 기대는 셈이지요.

실제로 재 보면 k=2 의 예측이 k=1 과 48개 전부 같고, k=4(83.3%)가 k=3(81.2%)보다, k=6(85.4%)이 k=5(83.3%)보다 높게 나옵니다. 짝수를 섞어 표를 만들면 “k 를 키우면 계속 좋아진다” 는 없는 이야기가 만들어집니다. 그래서 코드의 K_LIST 는 홀수만 담고 있습니다.

그리고 가장 중요한 것 — “k=7 이 정답” 이 아닙니다. 같은 158행을 다른 씨앗으로 나누면, 같은 후보 일곱(1·3·5·7·9·15·25) 안에서 고른 최고 k 가 3 · 5 · 7 · 9 · 25 로 갈립니다. k 에는 정답이 없고, 재 봐야 압니다. 아래 시뮬레이터에서 직접 확인해 보세요.

💻

손으로 ① — 첫 모델 판에서 기준선을 넘겨 보기

6분 · 표 세 줄을 공책에 옮겨 적는다

아래 판은 파이썬 코드와 똑같은 계산을 그 자리에서 합니다. 견본 데이터 158행을 씨앗으로 섞어 훈련 110 · 테스트 48 로 나누고, 훈련만으로 자를 맞춘 뒤, k-NN 을 돌려 두 정확도를 잽니다. 가로 점선이 기준선이고, 테스트 점이 그 선 위에 있으면 초록 · 아래면 빨강입니다.

🧪 첫 모델 판 — k · 씨앗 · 정규화 INTERACTIVE

k 슬라이더를 밀면 두 곡선 위의 점이 움직이고, 아래 숫자가 그 자리에서 다시 계산됩니다. 씨앗을 바꾸면 훈련/테스트를 나누는 방식이 달라져 곡선 전체가 흔들립니다. 정규화를 끄면 자를 맞추지 않은 채 거리를 잽니다. ▶ 를 누르면 k=1 부터 한 칸씩 그려집니다.

훈련 정확도 테스트 정확도 기준선(늘 한쪽만 말하는 모델) 기준선 위 기준선 아래(이 견본에서는 안 나온다)
7 42
지금 k7
훈련 정확도76.4%
테스트 정확도85.4%
맞힌 수41/48
기준선60.4%
기준선 대비+25.0%p
이 판의 최고 k7 · 85.4%
훈련 − 테스트-9.1%p
[안내] 씨앗 42 · 정규화 켬 · 훈련 110 · 테스트 48 로 시작합니다.
🎯 과제 — 공책에 표를 만들고 세 줄을 채운다

가로줄에 씨앗 / k / 훈련 / 테스트 / 기준선 / 차이(%p) / 넘었나 일곱 칸을 그리세요.

  1. 씨앗 42 · 정규화 켬에서 k=1 · k=7 · k=25 세 줄을 채운다.
  2. 반례 만들기 — 씨앗을 바꿔 가며 k=7 이 1등이 아닌 판을 하나 찾아 그 씨앗과 그때의 1등 k 를 적는다.
  3. 문턱 찾기 — 씨앗을 바꿔 가며 기준선이 가장 낮은 판과 가장 높은 판을 찾아 두 값을 적는다.

다 채운 팀은 하나 더: 정규화를 끄고 씨앗 42 에서 k=7 과 k=9 를 재 보세요. 한 자리는 켠 쪽이 높고 다른 한 자리는 끈 쪽이 높습니다. 어느 쪽인가요?

💡 판을 읽는 법
  • 노란 선이 하늘색 선보다 위에 있는 것이 보통입니다. 훈련 문제는 이미 답을 본 문제니까요. 둘의 벌어짐이 클수록 ‘외운 것’ 에 가깝습니다(2단원 11차시의 과적합).
  • k=1 자리에서 노란 점은 늘 100% 입니다. 자기 자신이 자기의 1등 이웃이기 때문입니다.
  • 회색 점선 아래로 하늘색 점이 내려가면 그 설정은 아무것도 안 배운 모델보다 못하다는 뜻입니다. 이 판에서는 씨앗 여덟 개 · 정규화 켬/끔 어디에서도 그런 자리가 나오지 않습니다 — 우리 데이터가 그만큼은 배울 만하다는 뜻입니다. 대신 아래 코드에서 빈칸 ②를 min 으로 잘못 채우면 테스트가 33.3% 까지 내려가 기준선 아래로 떨어집니다.
💻

손으로 ② — 빈칸 다섯을 채우고 진짜로 돌린다

12분 · 오늘의 본 실습

아래 코드가 오늘의 본 실습입니다. 길어 보이지만 여러분이 손댈 곳은 다섯 군데뿐입니다. 위쪽 대부분은 6차시에서 이미 완성한 것 — 데이터 160줄, load·clean·split·minmax_fit 같은 함수들 — 을 다시 실어 둔 것입니다. 손대지 마세요.

⚠️ 채우기 전에는 실행이 안 된다

????? 는 파이썬 문법이 아니라서, 다섯 곳을 다 채우기 전에 실행하면 SyntaxError 로 멈춥니다. 그것이 정상입니다. 오류가 가리키는 줄로 찾아가면 됩니다. 빈칸 다섯은 모두 코드의 아래쪽, nearest · knn · accuracy · baseline 네 함수 안에 모여 있습니다.

빈칸어느 함수물음힌트
①nearest 무엇을 기준으로 줄을 세워야 ‘가까운 순’ 이 되나? item 은 (특성, 이름표) 짝이다. 특성은 item[0]
②knn 표를 다 셌다. 다수결의 답은? votes 는 이름표 → 표 수 딕셔너리. 값이 가장 큰 열쇠를 돌려준다
③accuracy 몇 개를 맞혔나? 예측 knn(train, feat, k) 과 정답 label 을 견준다
④baseline 훈련에서 가장 흔한 이름표는? ②와 같은 꼴이다. counts 에서 고른다
⑤baseline 늘 common 만 말하면 테스트에서 몇 개를 맞히나? 정답이 common 과 같은 것만 센다
💡 다 채웠으면 이 넷을 확인한다
  • 【0】 줄에 원본 160행 → 다듬은 뒤 158행, 훈련 110 · 테스트 48 이 찍혔는가. 여기가 6차시와 같아야 오늘 표가 6차시와 이어집니다.
  • 【6】 표의 k=1 훈련 정확도가 100.0% 인가. 아니면 ①이나 ③이 틀렸습니다.
  • 【7】의 기준선이 60.4% 인가. 39.6% 가 나왔다면 ④가 min 입니다.
  • 맨 끝 【8】의 도전 셋이 다 찍히는가. 전부 도는 데 브라우저에서 2초쯤 걸립니다.

정답 다섯 줄은 이렇습니다. 먼저 스스로 채워 본 뒤에 펼쳐 보세요.

빈칸 다섯의 답 펼치기

① dist(point, item[0])  ·  ② max(votes, key=votes.get)  ·  ③ knn(train, feat, k) == label  ·  ④ max(counts, key=counts.get)  ·  ⑤ label == common

②와 ④가 같은 꼴인 것에 눈길을 두세요. 다수결은 k-NN 안에도 있고 기준선 안에도 있습니다. 차이는 무엇에 대고 다수결을 하느냐뿐입니다 — k-NN 은 가까운 이웃 k 개에게, 기준선은 훈련 데이터 전체에게 묻습니다. 그래서 k 를 훈련 크기까지 키우면 둘이 같아집니다.

잘못 채우면 무슨 일이 나는가

다섯 자리에 흔한 오답을 실제로 넣고 돌려 본 결과입니다. ①·③ 은 요란하게 죽지만, ②·④·⑤ 는 조용히 틀립니다.

빈칸흔한 오답실제로 일어나는 일
①dist(point, item[1]) TypeError — 이름표(글자)에서 뺄셈을 하려 든다. 바로 멈춘다
③... != label k=7 정확도가 14.6%. 85.4% 를 정확히 뒤집은 값이다
②min(votes, key=votes.get) k=3 58.3% · k=5 33.3% · k=7 33.3% — 기준선 60.4% 아래로 떨어진다. 다만 k=1 은 70.8% 로 같다(표가 하나뿐이면 min 과 max 가 같으니까)
④min(counts, key=counts.get) 기준선이 ‘불가’ 39.6% 가 되어 우리 모델이 +45.8%p 로 부풀려진다. 오류가 나지 않고 표는 더 예뻐진다
⑤label != common 같은 방향의 착시. 기준선 39.6%
⚠️ 오늘 가장 무서운 자리는 ④ 다

④를 틀리면 오류도 안 나고, 결과는 더 좋아 보입니다. 발표까지 그대로 갈 수 있는 잘못입니다. 그래서 규칙 하나를 외워 둡시다 — 기준선이 유난히 낮게 나오면 먼저 기준선을 의심한다. 두 이름표의 개수를 직접 세어(가능 56 · 불가 54) 큰 쪽이 골라졌는지 확인하면 30초면 끝납니다.

코드 안에 이미 들어 있는 도전 셋

【8】 아래는 실행하면 저절로 찍히는 도전입니다. 표를 보고 물음에 답해 보세요.

①

정규화를 빼면?

훈련에서 밝기 하나가 거리 제곱의 87.14% 를 가져갑니다(폭 251). 그런데 k=7 정확도는 85.4% → 83.3%, 2.1%p밖에 안 떨어지고 k=9 에서는 뺀 쪽이 더 높습니다(83.3% vs 79.2%).

②

k 를 훈련 수만큼 키우면?

k=110 에서 테스트 60.4% — 기준선과 정확히 같습니다. 훈련 정확도는 50.9% 인데, 훈련 110 중 ‘가능’ 이 56개(50.9%)라서 그렇습니다. 두 숫자가 딱 맞아떨어지는지 확인해 보세요.

③

씨앗을 바꾸면?

씨앗 여덟 개로 재면 기준선이 41.7%~60.4%, 최고 정확도가 75.0%~85.4% 로 흔들립니다. 여덟 중 k=7 이 1등인 것은 씨앗 42 하나뿐입니다.

ℹ️ 정규화는 정확도를 올리려고 하는 것이 아니다

도전①의 결과를 보고 “그럼 정규화는 안 해도 되네” 라고 쓰면 틀립니다. 정규화의 목적은 단위를 고르는 사람의 손을 떼는 것입니다. 누군가 밝기를 0~1 눈금으로 적어 왔다면 정규화 없는 표는 통째로 달라집니다. 2단원 8차시에서 g · mg · kg 로 단위를 바꿔 가며 본 그 결론과 같습니다 — 단위를 누가 정하느냐에 답이 흔들리면, 그건 모델이 아니라 우연입니다.

💻

손으로 ③ — 견본을 우리 팀 것으로 갈아 끼운다

4분 · 자기 데이터가 준비된 팀만

4차시에서 데이터를 구했고 6차시에서 다듬었다면, 이제 갈아 끼울 차례입니다. 코드에서 손댈 곳은 【0】 상자 하나뿐입니다. 그 아래 함수는 한 글자도 고치지 않습니다.

⚠️ DATA 만 바꾸면 안 된다 — 여섯 줄이 한 벌이다

DATA 를 바꾸면서 NAMES 를 그대로 두면 load() 가 바로 ValueError: 열 수가 안 맞는 줄 로 막습니다. 일부러 거기서 막게 해 두었습니다 — 그냥 두면 한참 뒤 엉뚱한 자리에서 터지기 때문입니다.

줄무엇을 적나견본에서는
NAMES열 이름 전부. DATA 의 열 수와 개수가 같아야 한다 반사도 밝기 투명도 이물질 찌그러짐 촬영조건 재활용
FEATURES모델에 넣을 열. 수치만 앞의 다섯
LABEL맞히려는 열재활용
GROUP성능을 쪼개어 볼 열. 모델에는 넣지 않는다촬영조건
POSITIVE찾아내려는 쪽. 9차시의 네 칸이 이걸 1 로 센다가능
DATA표 자체160줄

SEED · RATIO · K_LIST · MIN_TEST · MIN_GROUP 다섯은 건드리지 않습니다. 이 다섯이 같아야 6·7·8·9·10차시가 같은 이야기를 합니다.

🎯 갈아 끼우기 전에 점검표
  • 행 70개 이상 — 30% 를 테스트로 떼면 20개가 넘어야 합니다.
  • 수치 특성 3~6개 — 2개면 볼 것이 없고, 너무 많으면 22분에 못 끝냅니다.
  • 이름표는 딱 두 가지 — 세 가지면 오늘은 돌지만 9차시의 네 칸이 못 받습니다.
  • 적은 쪽 이름표가 30% 이상 — 90 대 10 이면 기준선이 90% 라 넘기가 매우 어렵습니다.
  • 집단 열 하나(값 2~3가지) — 없으면 9차시가 통째로 안 돕니다.
  • 값이 모두 같은 열을 특성에 넣지 않기 — minmax_apply 가 0 으로 나누어 죽습니다.
⚠️ 경고가 뜨면 거기서 멈춘다

코드가 매번 check_sizes() 로 테스트 크기와 집단 크기를 확인합니다. 테스트가 20개 미만이거나 집단 하나가 15개 미만이면 ⚠️ 줄이 찍힙니다. 그때 나온 정확도는 읽으면 안 되는 숫자입니다. 테스트가 4개라면 나올 수 있는 정확도가 0 · 25 · 50 · 75 · 100% 다섯 개뿐이라, “k 를 키웠더니 좋아졌다” 같은 말을 할 근거가 없습니다. 돌리지 말고 데이터를 더 모으러 가세요.

화이트보드에 그린 구조도 앞 책상에서, 검은 티셔츠를 입은 사람은 모니터를 보며 작업하고, 옆에 앉은 줄무늬 옷의 사람은 그 앞의 종이 쪽으로 손을 뻗어 내려다보고 있다
갈아 끼운 뒤에는 반드시 다른 사람이 출력을 한 번 읽게 하세요. 기준선 39.6% 같은 잘못은 코드를 짠 사람 눈에는 잘 안 보입니다 — 8차시가 통째로 이 이야기입니다. 출처: Bdecarne, Wikimedia Commons (CC BY-SA 4.0)
📖

정리 — 오늘 손에 쥔 것

6분 · 산출물 확인과 다음 시간까지 할 것

오늘 배운 것은 알고리즘이 아니라 숫자를 읽는 법입니다. 세 줄로 줄이면 이렇습니다.

① 정확도는 홀로 서지 못한다

85.4% 는 그 자체로 좋지도 나쁘지도 않습니다. 기준선 60.4% 를 함께 적어야 +25.0%p 라는 뜻이 생깁니다.

② 훈련 정확도는 성능이 아니다

k=1 의 훈련 100.0% 는 자기 답을 자기가 베낀 결과입니다. 같은 판의 테스트는 70.8% 로 표에서 가장 낮았습니다.

③ 한 번 돌린 숫자는 성적표가 아니다

씨앗을 바꾸면 기준선이 41.7%~60.4% 로, 최고 k 가 3·5·7·9·25 로 갈립니다. 발표에는 씨앗을 함께 적습니다.

실험 기록 — 오늘 공책에 남길 한 줄

10차시에서 이 줄들을 쌓아 모델 카드를 씁니다. 오늘 첫 줄을 이렇게 적어 두세요.

#설정전체 정확도기준선차이메모
1특성 5개 · k=7 · 정규화 O · 씨앗 42 85.4%60.4%+25.0%p 기준이 되는 한 판
2같은 설정 · k=1 70.8%60.4%+10.4%p k 만 바꿨다
💡 실패한 줄을 지우지 마라

좋아진 줄만 남기면 무엇 덕분에 좋아졌는지 말할 수 없게 됩니다. ‘정규화를 껐더니 나빠졌다’ 도 한 줄입니다. 그리고 한 번에 하나만 바꾸세요. k 와 특성을 같이 바꾸면 어느 쪽이 한 일인지 영영 모릅니다.

여기까지 못 했으면 — 이렇게 하세요

ℹ️ 팀마다 진도가 다른 것이 정상이다
  • 자기 데이터가 아직 없는 팀 — 코드를 그대로 두고 견본으로 오늘을 끝내세요. 빈칸 다섯을 채우고 【0】【6】【7】의 숫자를 공책에 옮겨 적으면 오늘의 목표는 달성입니다. 견본 한 벌로 6·7·8·9·10차시가 전부 돌아갑니다.
  • 데이터는 있는데 행이 모자란 팀(70행 미만) — 갈아 끼우지 말고 견본으로 진행하세요. 그리고 다음 시간까지 몇 행을 더 모을지를 숫자로 정해 오세요. 테스트가 20개를 못 넘으면 표를 읽을 수 없습니다.
  • 빈칸을 다 못 채운 팀 — 위의 ‘빈칸 다섯의 답’ 을 펼쳐 채워 넣고 실행부터 하세요. 숫자를 한 번도 못 보고 끝나는 것이 가장 나쁩니다. 답을 보고 채운 뒤, ③에 != 를 넣으면 왜 14.6% 가 되는지만 설명할 수 있으면 됩니다.
  • 시간이 남은 팀 — 시뮬레이터가 만들 수 있는 설정은 씨앗 8 × 정규화 2 × k 7 = 112가지입니다. 그 가운데 기준선과의 차이가 가장 작은 자리를 찾아 씨앗 · 정규화 · k 를 적어 두세요. 앞에서 본 대로 기준선 아래로 내려가는 자리는 하나도 없지만, 가장 좁은 곳은 +6.2%p 까지 붙습니다. 그 한 줄이 10차시 실험 기록의 좋은 재료가 됩니다.

그런데 85.4% 는 누구의 85.4% 인가

오늘은 여기서 닫습니다. 다만 한 가지만 남겨 둡니다. 똑같은 예측 48개를 촬영 조건으로 쪼개 보면 이렇습니다.

어디n우리 모델(k=7)그 집단의 기준선차이
전체4885.4% 60.4%+25.0%p
밝음2896.4% 57.1%+39.3%p
어두움2070.0% 65.0%+5.0%p

어두운 곳에서 찍은 사진만 놓고 보면, 우리 모델은 아무것도 안 배운 모델보다 5.0%p 나을 뿐입니다. “전체 85.4%” 한 줄만 적으면 이 사실이 통째로 감춰집니다. 이 한 칸을 어떻게 찾아내고 어떻게 적을 것인지가 9차시의 일입니다.

🎯 다음 시간(8차시)까지 할 것
  • 오늘의 실험 기록 두 줄을 공책에 옮겨 적어 온다(설정 · 전체 · 기준선 · 차이 · 메모).
  • 팀원이 각자 채운 코드를 한 벌로 합쳐 온다. 합칠 때 서로 다른 곳이 있으면 지우지 말고 표시해 두세요 — 8차시가 그것을 다룹니다.
  • 자기 데이터를 넣은 팀은 【0】 여섯 줄을 적어 온다(NAMES · FEATURES · LABEL · GROUP · POSITIVE · 행 수).
✅

확인 문제

2번 · 3번 · 5번 · 6번은 오늘 직접 돌려 본 결과를 묻습니다

✍️ 문제마다 답을 쓰고 제출하기를 누르세요. 제출하면 모범 답안이 열리고, 제출한 답은 선생님께 전달됩니다.

1. k-NN 이 답을 정하는 과정을 세 걸음으로 나누어 쓰고, 왜 그 앞에 정규화가 반드시 와야 하는지 한 문장으로 덧붙이세요.
📖 모범 답안

① 새 자료와 훈련 데이터 사이의 거리를 재어 가까운 순으로 줄을 세운다(nearest). ② 앞에서 k 개를 뽑는다. ③ 뽑힌 k 개의 이름표를 세어 다수결로 답한다(knn).

정규화가 앞에 와야 하는 까닭은 k-NN 이 오직 거리로만 답을 정하기 때문입니다. 단위가 큰 열이 거리를 독차지합니다. 견본에서 실제로 재 보면 밝기(폭 251) 하나가 거리 제곱의 87.14% 를 가져가고, 반사도(폭 1.27)의 몫은 0.00% 입니다. 자를 맞추지 않으면 나머지 네 특성은 사실상 없는 것이 됩니다.

2. 오늘 돌린 판에서 k=1 은 훈련 100.0% · 테스트 70.8% 였습니다. 이 두 숫자가 왜 그렇게 나오는지 설명하고, 그래서 k=1 을 고르면 안 되는 까닭을 쓰세요.
📖 모범 답안

훈련 100.0% — 훈련 데이터의 한 점에게 가장 가까운 이웃은 자기 자신이고 그 거리는 0.0 입니다. k=1 이면 자기 자신 한 명에게만 묻는 셈이니 자기 이름표를 그대로 되돌려 받습니다. 배운 결과가 아니라 베낀 결과입니다.

테스트 70.8% — 처음 보는 48개에서는 이웃 하나가 잘못 적힌 기록이면 그대로 끌려갑니다. 그래서 k 표 일곱 줄 가운데 가장 낮은 값이 나왔습니다(34/48).

고르면 안 되는 까닭: 훈련 정확도는 성능이 아니기 때문입니다. 고를 근거는 오직 테스트 쪽 숫자이고, 거기서 k=1 은 k=3(81.2%)보다 10.4%p 나쁩니다. “훈련 100%” 는 자랑이 아니라 증상입니다(2단원 11차시).

3. 기준선이 60.4%, 우리 모델(k=7)이 85.4% 였습니다. 차이는 몇 %p 인가요? 그리고 발표문에 “정확도 85.4%” 만 적으면 무엇이 감춰지는지 두 가지를 쓰세요.
📖 모범 답안

차이는 +25.0%p 입니다(41/48 − 29/48 = 12/48).

감춰지는 것 ① — 그 85.4% 가운데 60.4%p 는 코드를 한 줄도 짜지 않아도 나오는 몫입니다. 늘 ‘가능’ 이라고만 말하면 48개 중 29개가 맞습니다. 우리가 만든 것은 나머지 25.0%p 입니다.

감춰지는 것 ② — 그 값이 씨앗 42 로 한 번 나눈 판에서 나왔다는 사실입니다. 같은 158행을 다른 씨앗으로 나누면 기준선이 41.7%~60.4% 로, 최고 정확도가 75.0%~85.4% 로 흔들립니다. 발표에는 기준선과 씨앗을 함께 적어야 합니다.

4. 어떤 문제에서 기준선이 90% 라고 합니다. 그 문제에서 정확도 91% 인 모델을 어떻게 읽어야 할까요? 그리고 우리 견본 안에도 그와 닮은 자리가 실제로 하나 있습니다. 어디일까요?
📖 모범 답안

기준선 90% 에 정확도 91% 면 +1%p 입니다. 91 이라는 큰 숫자에 속으면 안 됩니다 — 아무것도 배우지 않은 모델과 사실상 같은 성능입니다. 게다가 이런 문제는 대개 한쪽 이름표가 90% 를 차지하는 치우친 데이터라, 정확도 대신 정밀도·재현율로 다시 재야 합니다(2단원 12차시).

우리 안의 자리 — 어두운 곳에서 찍은 사진 20개입니다. 그 집단만 놓고 보면 기준선이 65.0% 인데 우리 모델은 70.0% 로 +5.0%p 뿐입니다. 밝은 사진 28개에서는 57.1% → 96.4% 로 +39.3%p 인데도요. 전체 한 줄(85.4%)만 보면 이 차이가 보이지 않습니다. 9차시에서 직접 쪼개어 보게 됩니다.

5. 어떤 팀이 “우리 문제의 최적 k 는 7 입니다” 라고 발표했습니다. 이 문장이 왜 위험한지 쓰고, 시뮬레이터에서 찾을 수 있는 반례를 씨앗 값과 함께 하나 드세요.
📖 모범 답안

위험한 까닭: “k=7 이 1등” 은 씨앗 42 로 한 번 나눈 판에서만 참이기 때문입니다. 같은 158행을 다르게 나누면 1등이 바뀝니다. ‘최적’ 이라는 말은 이 데이터를 이렇게 나누었을 때라는 단서 없이는 쓸 수 없습니다.

반례 예시(시뮬레이터에서 씨앗만 바꾸면 그대로 나옵니다):

  • 씨앗 100 — 1등이 k=25(85.4%)이고, k=7 은 75.0% 에 그칩니다.
  • 씨앗 2 — 1등이 k=9(75.0%)이고, k=7 은 70.8% 입니다.
  • 씨앗 5 — k=7 이 68.8% 로 k=3(75.0%)보다 나쁩니다.

고쳐 쓴다면: “씨앗 42 로 나눈 이 분할에서는 후보 일곱 가운데 k=7 이 가장 높았습니다(85.4%, 기준선 대비 +25.0%p). 다른 분할에서는 1등이 3·5·9·25 로 바뀝니다.”

6. k 를 훈련 데이터 수(110)까지 키우면 테스트 정확도가 60.4% 가 되어 기준선과 ‘거의’ 가 아니라 정확히 같아집니다. 왜 정확히 같아질까요? 그리고 그때 훈련 정확도로 찍힌 50.9% 는 어디서 온 숫자인가요?
📖 모범 답안

정확히 같은 까닭 — k 가 훈련 크기와 같아지면 어느 점을 물어도 이웃 목록이 훈련 전체가 됩니다. 그러면 다수결의 결과는 늘 ‘훈련에서 가장 흔한 이름표’ 하나로 고정됩니다. 그것은 기준선 모델과 똑같이 행동하는 함수입니다. 비슷한 것이 아니라 같은 답을 48개 전부 내놓기 때문에 값이 정확히 일치합니다. (k 를 111 이나 200 으로 더 키워도 ranked[:k] 가 목록 길이에서 잘려 60.4% 그대로입니다.)

훈련 50.9% — 같은 이유로 훈련 110개에도 전부 ‘가능’ 이라고 답하는데, 훈련의 ‘가능’ 은 56개입니다. 56/110 = 50.9%. 화면의 숫자와 직접 센 개수가 맞아떨어지는지 확인해 보세요 — 이렇게 숫자 하나를 손으로 검산하는 습관이 조용히 틀리는 코드를 잡아냅니다.

🔎

더 알아보기

기준선과 견주는 습관은 교실 밖에서도 똑같다 — 일기예보, 교차 검증, 백만 달러짜리 대회

미국 국립기상청 플래그스태프 예보실. 책상마다 모니터가 늘어서 있고 몇몇 화면에 기상 레이더 영상과 지도가 떠 있으며, 벽 위쪽에도 큰 화면이 걸려 있다. 왼쪽 안쪽에 한 사람이 화면 앞에 앉아 있다
현장

일기예보의 기준선 — ‘평년값’과 ‘오늘과 같음’

기준선과 견주는 습관은 인공지능보다 훨씬 오래되었습니다. 기상학에서는 예보를 채점할 때 아무 계산도 하지 않은 예보를 옆에 세워 둡니다. 대표적인 것이 둘입니다. 하나는 기후값(평년값) 예보 — 그 날짜에 여러 해 동안 평균적으로 나타난 날씨를 그대로 말하는 것이고, 다른 하나는 지속성 예보 — “내일도 오늘과 같다” 고 말하는 것입니다.

둘 다 오늘 우리의 ‘늘 가능이라고만 말하는 모델’ 과 같은 자리에 있습니다. 그래서 예보 성능은 “몇 % 맞았다” 와 함께 기술 점수(skill score)로 말합니다. 기준 예보보다 오차를 얼마나 줄였는가를 비율로 나타낸 것으로, 완벽하면 1, 기준 예보와 같으면 0, 기준 예보보다 못하면 음수가 됩니다. 오늘 쓴 ‘기준선 대비 +25.0%p’ 와 생각이 같습니다.

맑은 날이 대부분인 곳에서는 “내일도 맑음” 만 말해도 적중률이 매우 높게 나옵니다. 그러니 적중률 하나로는 그 예보가 잘했는지 알 수 없지요 — 확인 문제 4번의 ‘기준선 90% 에 91%’ 와 같은 이야기입니다. 사진은 미국 국립기상청의 예보실로, 여러 화면에 띄운 레이더·관측 자료를 모아 예보를 냅니다.

사진: 미국 국립기상청 플래그스태프 예보실 · 출처: Bill Morrow, Wikimedia Commons (CC BY 2.0)

5겹 교차 검증 — 다섯 번 나누어 다섯 번 잰다 1회2회3회4회5회 → 점수 ①→ 점수 ②→ 점수 ③→ 점수 ④→ 점수 ⑤ 테스트 조각 훈련 조각 보고: 다섯 점수의 평균 ± 흔들림
원리 더 깊이

씨앗마다 흔들린다면 — 한 번 말고 여러 번 나누어 잰다

오늘 도전③에서 씨앗 여덟 개로 나누어 보니 기준선이 41.7%~60.4% 로, 최고 정확도가 75.0%~85.4% 로 흔들렸습니다. 테스트가 48개뿐이라 어떤 48개가 테스트에 뽑혔느냐에 점수가 크게 휘둘린 것이지요. 이 흔들림을 줄이는 표준 방법이 교차 검증(cross-validation)입니다.

그림처럼 데이터를 다섯 조각으로 나누고, 다섯 번 돌리며 매번 다른 한 조각을 테스트로 씁니다. 그러면 모든 행이 딱 한 번씩 시험 문제가 되고, 점수가 다섯 개 나옵니다. 이것을 평균과 함께 얼마나 흔들렸는지까지 적으면 “씨앗 42 한 판의 85.4%” 보다 훨씬 믿을 만한 숫자가 됩니다. 기준선도 조각마다 따로 재어, 같은 조각끼리 견주는 것이 원칙입니다.

k 를 고를 때도 씁니다. 후보 k 마다 교차 검증 평균을 내어 고르고, 마지막 성적은 그 과정에 한 번도 쓰지 않은 테스트로 따로 잽니다. 그렇지 않으면 k 를 고르느라 테스트를 여러 번 들여다본 셈이 되어, 오늘 배운 ‘테스트를 보고 고르는 누수’ 가 다른 모양으로 되살아납니다.

넷플릭스 프라이즈 — 기준선은 회사의 기존 시스템 별점 예측 오차(RMSE) · 낮을수록 좋다 → 0.96 0.85 시네매치(기존) 0.9525 상금 조건 (10% 감소) 0.8572 2009년 우승 0.8567 여러 팀이 3년 가까이 매달려 넘은 거리 성적은 늘 '기존 시스템보다 몇 % 나은가'로 매겼다
역사

백만 달러가 걸린 기준선 — 넷플릭스 프라이즈

2006년 영화 대여 회사 넷플릭스는 공개 대회를 열었습니다. 회원이 매긴 별점 약 1억 개를 내놓고, 자기 회사 추천 시스템 ‘시네매치’ 보다 별점 예측 오차를 10% 줄이는 팀에게 100만 달러를 주겠다고 했지요. 성적의 잣대가 ‘몇 점’ 이 아니라 기존 시스템과의 차이였다는 점이 오늘 수업과 같습니다.

그 10% 는 쉽지 않았습니다. 세계 곳곳에서 수많은 팀이 뛰어들었지만 선을 넘은 것은 2009년, 여러 팀이 힘을 합친 BellKor’s Pragmatic Chaos 였습니다. 똑같은 점수를 낸 다른 연합 팀이 있었는데, 먼저 제출한 쪽이 우승을 가져갔습니다. 마지막 몇 걸음은 수많은 모델의 예측을 섞고 나서야 겨우 나왔습니다.

뒷이야기도 생각해 볼 만합니다. 넷플릭스는 우승한 방법을 통째로 서비스에 넣지 않았습니다. 뒤에 회사 기술 블로그는 더 얻은 정확도가 그 복잡한 모델을 실제로 돌리는 수고만큼의 값어치는 아니었다고 설명했습니다. 기준선을 넘었는가 다음에는 넘은 만큼이 쓸모 있는가를 물어야 한다는 것 — 10차시 모델 카드에서 우리도 적게 될 물음입니다.

🔁 되돌아보기

오늘 2단원의 부품 다섯을 우리 데이터에 얹어 첫 모델을 돌리고, 그 점수를 기준선 60.4% 대비 +25.0%p 로 읽는 법을 익혔습니다. 다음 시간에는 팀원이 각자 채운 코드를 한 벌로 합치면서, 돌아가긴 하는데 답이 이상한 세 가지 고장을 직접 잡습니다.