P7-2.1 비교표와 오류 사례 읽기¶
Section ID: P7-2.1 Version: v2026.07.22
예측 모델을 하나 붙여 보고, 그 결과를 비교표와 오류 사례로 읽기 시작합니다.
하지만 여기서도 출발점은 모델 이름이 아닙니다. 먼저 문제 정의, 데이터 분리, 기준점(baseline), 비교 가능한 출력이라는 네 가지를 갖춰야 합니다. 예측 프로젝트에서 먼저 중요한 일은 높은 점수를 내는 것이 아니라, 비교 가능한 방식으로 기준점과 모델을 나란히 놓는 데 있습니다.
비교 가능한 예측 기록¶
- 예측 모델 프로젝트는 어떤 구조로 시작하면 좋은가?
- 학습(train)과 평가(test)를 분리해 기록하는 이유는 무엇인가?
- baseline 없이 모델 정확도(accuracy)만 보면 왜 위험한가?
- NumPy만으로도 실제 운영형 분류 실습 흐름을 어떻게 확인할 수 있는가?
분류 프로젝트의 최소 기록 구조를 잡는 데 집중합니다. 즉, 문제 -> 데이터 분리 -> baseline -> 모델 -> 비교로 프로젝트 문서를 어떻게 시작할지까지를 먼저 닫습니다.
예측 모델 프로젝트는 여기서 문제 정의와 baseline 문서부터 출발합니다. train/test 분리와 비교 가능한 기록 뼈대를 먼저 고정합니다.
Part 7에서 기준점(baseline)을 단순한 임시 숫자가 아니라 비교 기준선으로 다시 잡아야 할 때는, 이 절과 개념사전으로 돌아와 뜻을 함께 다시 확인하면 됩니다.
판단 기준¶
- 예측 프로젝트를
문제 -> 데이터 분리 -> baseline -> 모델 -> 비교흐름으로 설명할 수 있습니다. - baseline과 모델 성능을 함께 기록해야 하는 이유를 말할 수 있습니다.
- 운영형 예측 사례에서 샘플별 예측과 실패 목록을 직접 읽을 수 있습니다.
프로젝트 질문 설정¶
이번 실습은 구독 고객의 이탈 위험(churn risk)을 예측할 수 있는가?라는 질문에서 시작합니다. 이 질문은 실제 서비스 운영과 가깝고, 최근 문의 수, 최근 미접속 일수, 최근 사용량처럼 서로 다른 스케일의 특징(feature)을 함께 다루게 해 주기 때문에 비교표와 오류 사례를 같이 읽기 좋습니다.
예측 프로젝트를 시작할 때 바로 필요한 판단 기준을 먼저 표로 고정하면 다음과 같습니다.
| 질문 | 짧은 답 |
|---|---|
| 이 프로젝트에서 먼저 정할 것은 무엇인가? | 입력 특징, 라벨, 분리 방식 |
| 왜 baseline이 먼저인가? | 모델 점수의 의미를 비교하기 위해 |
| 최소 산출물은 무엇인가? | baseline 예측, 모델 예측, test 결과 비교 |
프로젝트 흐름¶
flowchart TD
A["질문 정리<br/>고객 이탈 위험 예측"]
B["데이터 분리<br/>학습과 평가"]
C["기준점 준비<br/>다수 라벨 예측"]
D["모델 적용<br/>가장 가까운 이웃"]
E["결과 비교<br/>정확도와 실패 사례"]
A --> B --> C --> D --> E
이 흐름은 Part 3에서 반복해 본 머신러닝 공통 구조를 프로젝트 문서로 다시 옮긴 것입니다.
예제 데이터¶
구독 서비스 운영팀이 매일 보는 요약 지표처럼 데이터를 구성합니다.
- 특징 1: 최근 30일 미해결 문의 수
- 특징 2: 최근 접속 후 경과 일수
- 특징 3: 최근 30일 사용 시간(분)
- 라벨(label): 유지(0) / 이탈 위험(1)
학습용 데이터:
| 샘플 | 미해결 문의 수 | 최근 접속 후 경과 일수 | 최근 30일 사용 시간(분) | 정답 |
|---|---|---|---|---|
| 학습-01 | 2 | 3 | 4200 | 0 |
| 학습-02 | 1 | 5 | 3900 | 0 |
| 학습-03 | 2 | 7 | 3600 | 0 |
| 학습-04 | 3 | 9 | 3400 | 0 |
| 학습-05 | 1 | 4 | 3000 | 0 |
| 학습-06 | 2 | 6 | 2800 | 0 |
| 학습-07 | 3 | 8 | 2500 | 0 |
| 학습-08 | 6 | 20 | 3500 | 1 |
| 학습-09 | 7 | 24 | 2600 | 1 |
| 학습-10 | 8 | 28 | 2200 | 1 |
| 학습-11 | 5 | 18 | 3300 | 1 |
| 학습-12 | 6 | 22 | 2900 | 1 |
평가용 데이터:
| 샘플 | 미해결 문의 수 | 최근 접속 후 경과 일수 | 최근 30일 사용 시간(분) | 정답 |
|---|---|---|---|---|
| 평가-01 | 2 | 6 | 3700 | 0 |
| 평가-02 | 6 | 21 | 4050 | 1 |
| 평가-03 | 7 | 25 | 2550 | 1 |
| 평가-04 | 3 | 9 | 3200 | 0 |
| 평가-05 | 5 | 19 | 3350 | 1 |
| 평가-06 | 2 | 5 | 2950 | 0 |
이 데이터는 아주 작게 축약했지만, 실제 운영팀이 자주 보는 문의, 미접속, 사용량 축을 함께 둬서 무슨 특징이 예측에 기여했는가를 더 현실적으로 읽게 합니다.
baseline은 왜 먼저 두는가¶
baseline은 아주 단순합니다.
학습 데이터에서 더 자주 나온 라벨을 평가 데이터에도 그대로 예측한다.
이 baseline은 똑똑하지 않지만, 다음 질문에 답하게 해 줍니다.
내가 만든 모델이 최소한 이 단순한 기준보다 나은가?
이 기준이 없으면 모델 정확도가 0.67이든 0.90이든 그것이 얼마나 의미 있는지 판단하기 어렵습니다.
여기서 baseline은 모델 없는 기준선 역할을 합니다. 이 기준선이 있어야 개선이라는 말을 써도 과장이 줄어듭니다.
여기서 baseline은 꼭 가장 단순한 분류기 이름으로만 읽을 필요는 없습니다. 더 넓게 보면 baseline은 새 결과를 해석하기 위한 비교 기준선입니다. 즉, 지금 절에서는 다수 라벨 예측이 그 역할을 맡지만, 다른 프로젝트에서는 이전 버전 규칙, 최근 평균, 비슷한 조건의 평소 기준선처럼 비교를 가능하게 만드는 출발점이 baseline 자리에 올 수도 있습니다.
예를 들어 1-NN 정확도 0.667만 먼저 보면, 빠르게는 baseline 0.500보다 높으니 바로 쓸 만하다고 적고 싶어질 수 있습니다. 하지만 더 안전한 다음 판단은 점수 한 줄로 닫는 것이 아니라, baseline이 놓친 사례를 모델이 실제로 얼마나 회수했는가, 새로 만든 오답은 무엇인가, 가장 가까운 학습 샘플이 왜 그렇게 붙었는가를 함께 적는 것입니다. 그렇게 적어야 숫자가 조금 올랐다와 실제로 더 나은 판단 구조가 생겼다를 구분할 수 있습니다.
flowchart TD
A["문제 장면<br/>baseline 0.500, 1-NN 0.667"]
B["빠른 판단<br/>점수가 올랐으니 바로 사용"]
C["회수 사례 확인<br/>baseline 실패를 얼마나 잡았는가"]
D["새 오답 확인<br/>모델이 새로 틀린 샘플은 무엇인가"]
E["최근접 샘플 확인<br/>왜 그렇게 붙었는가"]
F["더 안전한 판단<br/>점수와 오류 사례를 같이 남긴다"]
A --> B
A --> C --> D --> E --> F
Python 예제¶
예제는 train/test 분리, baseline, 간단한 분류 모델 비교를 한 화면에서 보는 것입니다. 예제에서는 단순히 정확도 숫자만 출력하지 않고, 실제 프로젝트 메모처럼 샘플별 비교 결과와 틀린 사례 목록까지 함께 남겨 보겠습니다.
| 이 기록 종류 | 지금 남기는 이유 | 뒤에서 다시 쓰는 곳 |
|---|---|---|
| 실행 요약 | 실행 결과에서 baseline과 모델을 비교한 최소 결과를 한 번에 남기기 위해 | 이후 재실험 판단과 개선 여부 확인의 기준점이 된다 |
| 샘플별 비교 행 | 어떤 샘플에서 예측이 갈렸는지 숫자 뒤의 실제 사례를 남기기 위해 | 오류 사례 묶음, 회고 메모, 재평가 후보를 정리할 때 근거가 된다 |
- 문제 상황: 구독 고객의 이탈 위험을 예측한다.
- 입력: 미해결 문의 수, 최근 접속 후 경과 일수, 최근 30일 사용 시간
- 정답: 유지(0) / 이탈 위험(1)
- 확인할 개념:
- baseline과 모델을 나란히 비교해야 한다
- 평가 데이터는 따로 두어야 한다
- 작은 모델이어도 예측 결과를 직접 읽을 수 있어야 한다
- 나중에 회고할 수 있도록 샘플별 결과를 기록해야 한다
실습용 분류 데이터를 코드 안에 직접 쓰지 않고 p7-2-churn-dataset.csv에 둡니다. Python 코드는 split 열을 기준으로 학습(train)과 평가(test)를 나누는 단계부터 시작합니다.
입력 파일¶
- 파일 경로:
p7-2-churn-dataset.csv - 한 행의 의미:
한 명의 구독 고객에 대한 관측 기록 - 핵심 열:
split,sample_id,unresolved_tickets,days_since_login,usage_minutes_30d,label
입력 파일의 앞부분만 짧게 다시 보면 다음과 같습니다.
| split | sample_id | unresolved_tickets | days_since_login | usage_minutes_30d | label |
|---|---|---|---|---|---|
| train | 학습-01 | 2 | 3 | 4200 | 0 |
| train | 학습-02 | 1 | 5 | 3900 | 0 |
| train | 학습-03 | 2 | 7 | 3600 | 0 |
| train | 학습-04 | 3 | 9 | 3400 | 0 |
실행 기록 기준¶
- 입력 특징과 라벨을 먼저 적고, train/test가 어떤 행으로 나뉘는지 확인합니다.
- baseline이 어떤 라벨을 계속 예측하는지 표시합니다.
- baseline과 1-NN의 정확도를 같은 평가 셋에서 나란히 둡니다.
- 샘플별 비교에서 baseline이 놓친 사례, 1-NN이 회수한 사례, 1-NN이 새로 만든 오답을 따로 표시합니다.
실행 결과 예시는 다음과 같습니다.
결과를 어떻게 읽는가¶
이 결과에서 핵심은 0.667이라는 숫자 자체보다 비교 구조입니다.
- baseline은 모든 고객을
유지로만 봤기 때문에 이탈 위험 고객 세 건을 놓쳤습니다. - 1-NN 모델은 특징을 실제로 사용해
평가-03,평가-05같은 이탈 위험 고객을 잡아냈습니다. - 하지만
평가-02,평가-04에서는 raw 거리 계산이 사용 시간(분) 축에 크게 끌려 잘못된 최근접 이웃을 고른 흔적이 보입니다.
즉, 이번 실습은 모델이 baseline보다 낫다는 것과 그래도 입력 스케일 때문에 틀릴 수 있다는 것을 동시에 보여 줍니다.
| 비교 항목 | baseline | raw 1-NN | 읽어야 할 점 |
|---|---|---|---|
| 무엇을 보나 | 항상 유지로 예측 | 세 특징의 raw 거리를 그대로 사용 | 모델이 특징을 보기는 하지만, 스케일 차이에 약할 수 있다 |
| 정확도 | 0.500 | 0.667 | baseline보다는 낫지만 아직 불안정하다 |
| 대표 실패 | 이탈 위험 고객을 거의 못 잡음 | 평가-02, 평가-04에서 잘못된 최근접 이웃 선택 | 입력 스케일과 거리 기준을 다시 점검해야 한다 |
하지만 동시에 조심해야 할 점도 있습니다.
- 평가 샘플 수가 6개뿐이라 아직 작습니다.
- 우연히 쉬운 혹은 어려운 분할이 섞였을 수 있습니다.
- 다른 고객 구간에서는 같은 결과가 나오지 않을 수 있습니다.
즉, 프로젝트 문서에는 성과와 한계를 함께 남겨야 합니다.
실행 결과는 다음 세 줄로 요약할 수 있습니다.
- baseline은 모든 고객을 유지로 보는 단순 기준선이다.
- raw 1-NN은 baseline보다 낫지만, 사용 시간 스케일에 끌려 오판한 샘플이 남아 있다.
- 샘플별 비교와 실패 목록이 있어야 다음 전처리 검토로 자연스럽게 이어질 수 있다.
결과 해석 기준¶
| 관찰 | 읽어야 할 뜻 |
|---|---|
| baseline 정확도는 0.500이다 | 단순 다수 라벨 기준선만으로는 이탈 위험 고객을 놓친다 |
| raw 1-NN 정확도는 0.667이다 | 특징을 쓰면 일부 이탈 위험 고객을 회수한다 |
평가-03, 평가-05는 모델이 맞힌다 | baseline 대비 개선이 실제 사례에서 보인다 |
평가-02, 평가-04는 모델도 틀린다 | 다음 수정 질문은 입력 스케일과 경계 사례로 이어진다 |
프로젝트 기록 예시¶
직접 바꿔 보며 확인할 것¶
전처리 필요성을 실제 오류 사례로 느끼는 것이 중요하므로, 실행 뒤에는 입력 스케일을 일부러 흔들어 보는 편이 좋습니다.
-
feature_scales를np.array([1.0, 1.0, 60.0])으로 바꿔usage_minutes_30d를 시간 단위처럼 줄여 봅니다. 관찰할 점:평가-02,평가-04의 최근접 이웃이 바뀌는가? 정확도와 실패 샘플이 줄어드는가? -
평가-02와 비슷한 이탈 위험 고객 한 행을 CSV에 하나 더 추가해 봅니다. 관찰할 점: baseline은 그대로인데 1-NN 쪽 실패 패턴은 어떻게 달라지는가?
이 두 실험은 모델을 바꾸지 않아도 입력 스케일과 샘플 구성이 결과를 크게 흔든다는 점을 직접 보여 줍니다.
실무 감각으로 번역하면¶
이 작은 실습은 현실의 다음 질문과 연결됩니다.
- 단순 규칙보다 실제 특징을 쓰는 모델이 나은가?
- 그 개선이 어떤 샘플에서 나왔는가?
- 어떤 오답은 모델 구조보다 입력 스케일 문제에서 나온 것 아닌가?
- 전처리를 하면 그 오답이 줄어드는가?
이 감각은 이후 회고와 비교 문서를 쓸 때도 그대로 중요합니다.
즉, 핵심은 알고리즘 소개보다 프로젝트에서 baseline을 문서화하고 다음 비교 질문을 만드는 일에 있습니다.
체크리스트¶
| 확인할 것 | 스스로 답할 질문 |
|---|---|
| 문제 | 예측하려는 라벨과 입력 특징을 한 문장으로 고정했는가? |
| 분리 | train/test를 나누고, 평가 결과가 어떤 데이터에서 나온 것인지 적었는가? |
| baseline | 모델 점수를 baseline 대비 차이로 읽었는가? |
| 샘플별 비교 | 어떤 평가 샘플에서 baseline과 모델 예측이 갈렸는지 남겼는가? |
| 실패 목록 | 오답 샘플이 다음 전처리 검토 질문으로 이어지는가? |
이 다섯 칸이 비어 있으면 모델 종류를 더 늘려도 비교 기록은 강해지지 않습니다. 먼저 문제 -> 분리 -> baseline -> 샘플별 비교 -> 실패 목록 순서를 닫아야 다음 실험이 같은 기준 위에서 이어집니다.
출처와 참고 자료¶
- NumPy Developers,
NumPy documentation, 확인 날짜: 2026-06-29. https://numpy.org/doc/stable/
이 절의 데이터는 개인정보가 없는 실습용 구독 고객 요약 예시를 위해 직접 구성한 synthetic 데이터입니다.