콘텐츠로 이동

P4-12.1 k-NN의 직관

Section ID: P4-12.1 Version: v2026.07.20

P4-11.2에서는 로지스틱 회귀(logistic regression)가 입력 공간에 경계를 그어 class를 나누는 방식을 보았습니다. 이제 질문을 바꿉니다.

직선을 먼저 만들지 않고, 주변의 비슷한 사례를 보고 판단할 수는 없을까?

이 질문이 k-NN(k-nearest neighbors)의 출발점입니다. k-NN은 식을 먼저 세우는 모델이라기보다 새 입력 주변의 비슷한 사례를 먼저 찾는 모델로 읽는 편이 더 정확합니다.

k-NN의 직관에서 닫을 질문

이 절은 다음 질문에 답합니다.

  • k-NN은 어떤 발상으로 판단하는가?
  • query, neighbor, label, k는 각각 어떤 역할을 하는가?
  • k를 바꾸면 판단의 성격이 어떻게 달라지는가?
  • k-NN에서 학습(training)은 무엇을 한다고 봐야 하는가?

이 절은 먼저 k-NN이 어떤 발상으로 주변 사례를 근거로 판단하는가를 닫습니다. 거리 함수와 스케일이 왜 결과를 바꾸는지는 P4-12.2 거리(distance)와 스케일(scale)에서, 적용 가이드는 P4-12.3 k-NN을 사용할 때 무엇을 먼저 점검할까에서 이어집니다.

k-NN의 직관에서 남길 판단 기준

  • k-NN을 가까운 사례를 모아 다수결 또는 평균으로 판단하는 방법이라고 설명할 수 있습니다.
  • query, training data, neighbor, label이 판단 안에서 무엇을 맡는지 설명할 수 있습니다.
  • k가 너무 작을 때와 너무 클 때 생기는 차이를 설명할 수 있습니다.
  • k-NN의 학습이 복잡한 식을 만드는 일보다 비교할 기준 사례를 준비하는 일에 가깝다는 점을 설명할 수 있습니다.

주요 학습내용

k-NN은 어떤 방식으로 판단하는가

k-NN은 먼저 새 입력(query)을 봅니다. 그다음 이미 label이 붙어 있는 학습 데이터(training data)에서 query와 가까운 사례들을 찾습니다. 마지막으로 그 이웃(neighbors)의 label을 모아 다수결이나 평균으로 판단을 만듭니다.

작게 정리하면 다음 순서입니다.

  1. 새 입력(query)이 들어온다.
  2. 기존 학습 데이터에서 가까운 사례를 찾는다.
  3. 가까운 사례들의 label을 모은다.
  4. 다수결이나 평균으로 결과를 정한다.

즉, k-NN은 새 점을 혼자 해석하지 않고 주변의 이미 알려진 사례와 비교해서 판단한다고 보면 됩니다.

판단 안에서 각 용어는 무엇을 맡는가

용어 판단 안에서 맡는 역할
query 지금 예측하고 싶은 새 입력입니다.
training data 이미 입력과 label이 함께 있는 기준 사례 모음입니다.
neighbor query와 가까워서 판단 근거로 뽑힌 사례입니다.
label 각 기준 사례가 이미 갖고 있는 정답 또는 범주입니다.
k 몇 개의 neighbor를 보고 판단할지 정하는 값입니다.

이 표가 중요한 이유는 k-NN이 모델 내부에서 식을 계산해 내는 방식보다 기준 사례를 어떻게 읽는가에 더 가깝기 때문입니다.

왜 가까운 사례를 근거로 삼는가

k-NN의 핵심 가정은 비슷한 입력은 비슷한 출력을 가질 가능성이 높다는 것입니다. 이 가정이 항상 맞는 것은 아니지만, 지역적 유사성(local similarity)이 실제로 의미를 갖는 문제에서는 강한 출발점이 됩니다.

예를 들면 다음과 같습니다.

  • 구매 패턴이 비슷한 고객은 비슷한 반응을 보일 수 있습니다.
  • 클릭 흐름이 비슷한 사용자는 비슷한 관심 상품 범주에 가까울 수 있습니다.
  • 시험 점수 패턴이 비슷한 학생은 비슷한 결과 범주로 묶일 수 있습니다.

이 직관을 계산 순서로 줄이면 다음과 같습니다.

flowchart TD
  A["새 입력(query)"]
  B["가까운 사례 찾기"]
  C["주변 레이블 모으기"]
  D["투표 또는 평균으로 판단"]

  A --> B --> C --> D

다만 가깝다가 곧 옳다는 뜻은 아닙니다. 무엇을 기준으로 가까움을 계산하는지에 따라 이웃 자체가 달라질 수 있기 때문입니다. 바로 그 지점을 다음 절에서 다룹니다.

k는 무엇을 바꾸는가

k는 몇 개의 이웃을 보고 판단할지를 정합니다.

  • k = 1이면 가장 가까운 한 개만 봅니다.
  • k = 3이면 가장 가까운 세 개를 봅니다.
  • k = 5이면 다섯 개를 보고 더 넓게 판단합니다.

같은 query라도 k를 바꾸면 판단 성격이 달라집니다.

k 보이는 성격
너무 작음 가까운 한두 사례에 민감해집니다.
적당함 지역 패턴을 살리면서 흔들림을 줄일 수 있습니다.
너무 큼 멀리 있는 사례까지 섞여 경계가 둔해질 수 있습니다.

작은 장난감 예로 보면 더 분명합니다.

query 주변 이웃 label k = 1 k = 3 k = 5
1, 0, 0, 0, 0 1 0 0

이 예시는 가장 가까운 한 개만 보면 1이지만, 세 개나 다섯 개로 넓히면 0 쪽이 많아져 결과가 바뀔 수 있음을 보여 줍니다. 즉, k는 단순 숫자가 아니라 얼마나 좁게 볼 것인가, 얼마나 넓게 볼 것인가를 정하는 손잡이입니다.

k-NN에서 학습은 무엇을 하는가

선형회귀나 로지스틱 회귀에서는 보통 계수를 학습한다고 말합니다. k-NN은 분위기가 다릅니다.

입문 수준에서 보면 k-NN의 학습은 대체로 다음에 가깝습니다.

  • 입력과 label을 저장한다.
  • 새 입력이 들어왔을 때 비교할 준비를 한다.
  • 필요하면 거리 계산을 빠르게 하기 위한 내부 구조를 쓴다.

즉, k-NN은 정교한 공식을 미리 만들어 두는 학습보다 나중에 비교할 기준 사례를 준비하는 학습으로 읽어야 맞습니다.

그래서 k-NN에는 두 특징이 함께 따라옵니다.

  • 데이터 정리와 표현 방식이 중요합니다.
  • 예측 시점(prediction time)에 비교 비용이 커질 수 있습니다.

예를 들어 학습 데이터가 100개일 때는 query 하나를 100번 비교하면 되지만, 10만 개일 때는 같은 query를 훨씬 더 많이 비교해야 합니다. 학습이 단순하다는 말은 준비가 덜 중요하다는 뜻이 아니라, 판단 비용이 훈련 때보다 예측 때 더 드러날 수 있다는 뜻에 가깝습니다.

선형 경계 모델과 무엇이 다른가

로지스틱 회귀는 하나의 식이나 경계로 전체 공간을 어떻게 나눌까를 먼저 묻습니다. 반면 k-NN은 이 점 주변에는 어떤 사례들이 모여 있는가를 먼저 묻습니다.

모델 관점 중심 질문
로지스틱 회귀 어떤 경계선을 그으면 class를 잘 나눌까?
k-NN 새 점 주변의 비슷한 사례는 어떤 class인가?

이 차이 때문에 k-NN은 전역적(global) 규칙보다 국소적(local) 이웃을 더 앞세웁니다.

사례 및 예시

사례 1. 새 고객을 비슷한 기존 고객으로 먼저 판단하고 싶을 때

구독 서비스 팀이 새 고객의 이탈 가능성을 판단하려고 합니다. 사람은 최근 방문 횟수, 문의 빈도, 결제 금액, 접속 시간대 같은 행동 신호를 먼저 봅니다.

그런데 팀은 아직 이탈 고객은 항상 이런 규칙을 따른다고 말할 만큼 단순한 식을 찾지 못했습니다. 대신 기존 고객 기록을 보면 비슷한 행동을 보였던 고객끼리는 결과도 비슷한 경우가 자주 보입니다. 이때 k-NN은 새 고객을 혼자 해석하지 않고, 주변에서 가장 비슷한 기존 고객 몇 명을 먼저 찾아 그들의 label을 참고합니다.

flowchart TD
  A["새 고객 질의"]
  B["가까운 고객을 찾는다"]
  C["이웃의 레이블을 비교한다"]
  D["현재 k로 투표한다"]
  E["예측"]
  F["이웃이 섞였는지 검토한다"]

  A --> B --> C --> D --> E
  C --> F

이 사례가 보여 주는 핵심은 세 가지입니다.

  • k-NN은 규칙을 먼저 세우는 모델보다 가까운 사례를 먼저 참조하는 모델에 가깝습니다.
  • k=1이면 한 사람의 예외 사례에 민감해질 수 있고, k=5면 더 안정적일 수 있지만 경계가 둔해질 수 있습니다.
  • 이웃 구성이 갈리면, 그것은 먼저 다시 볼 query를 알려 주는 신호입니다.

연습 및 예제

Python 예제로 작은 k-NN 보기

  • 문제 상황: 새 점이 기존 두 그룹 중 어느 쪽에 더 가까운지 봅니다.
  • 입력(input): 2차원 좌표처럼 읽을 수 있는 두 특징
  • 정답(label): class 0 / class 1
  • 확인할 개념:
  • 예측은 이웃 label을 보고 만들어집니다.
  • 같은 query라도 k가 바뀌면 결과가 실제로 달라질 수 있습니다.
  • 경계 근처 query는 해석이 쉽게 흔들릴 수 있습니다.
# 새 query와 기존 샘플 사이의 거리를 계산해 k-NN 이웃과 예측 label을 고르는 예제입니다.
from math import dist
from collections import Counter

train = [
    ((4.1, 4.1), 1),
    ((3.7, 4.0), 0),
    ((3.8, 4.3), 0),
    ((4.2, 3.8), 0),
    ((4.4, 4.0), 1),
]

query = (4.0, 4.2)

def knn_predict(train, query, k):
    ranked = sorted(
        [(dist(point, query), point, label) for point, label in train],
        key=lambda x: x[0],
    )
    neighbors = ranked[:k]
    labels = [label for _, _, label in neighbors]
    prediction = Counter(labels).most_common(1)[0][0]
    return prediction, neighbors

for k in [1, 3, 5]:
    prediction, neighbors = knn_predict(train, query, k)
    print(f"k={k}, prediction={prediction}")
    for d, point, label in neighbors:
        print(" ", point, "label=", label, "distance=", round(d, 3))
    print()

실행 결과 예시는 다음과 같습니다.

k=1, prediction=1
  (4.1, 4.1) label= 1 distance= 0.141

k=3, prediction=0
  (4.1, 4.1) label= 1 distance= 0.141
  (3.8, 4.3) label= 0 distance= 0.224
  (3.7, 4.0) label= 0 distance= 0.361

k=5, prediction=0
  (4.1, 4.1) label= 1 distance= 0.141
  (3.8, 4.3) label= 0 distance= 0.224
  (3.7, 4.0) label= 0 distance= 0.361
  (4.4, 4.0) label= 1 distance= 0.447
  (4.2, 3.8) label= 0 distance= 0.447

이 출력은 k가 단순 숫자가 아니라 판단 범위를 바꾸는 손잡이라는 점을 실제로 보여 줍니다.

  • k=1에서는 가장 가까운 한 점이 class 1이라서 예측도 1입니다.
  • 하지만 k=3으로 넓히면 가까운 세 점 중 두 점이 class 0이라서 예측이 0으로 바뀝니다.
  • k=5에서도 여전히 class 0이 더 많아 0으로 유지됩니다.

즉, 이 예제는 가장 가까운 한 점의 예외조금 더 넓게 본 지역 다수가 서로 다른 말을 할 수 있음을 닫아 줍니다. 여기서 먼저 읽어야 할 것은 점수보다 어떤 이웃이 포함되었고, 그 때문에 다수결이 어떻게 바뀌었는가입니다.

체크리스트

  • k-NN을 가까운 사례를 모아 판단하는 방식이라고 설명할 수 있는가?
  • query, neighbor, label, k가 판단 안에서 서로 다른 역할을 맡는다는 점을 이해했는가?
  • k가 단순 숫자가 아니라 판단 범위를 조절하는 손잡이라는 점을 설명할 수 있는가?
  • k가 너무 작을 때와 너무 클 때의 차이를 설명할 수 있는가?
  • k-NN의 학습이 식을 만드는 일보다 비교 기준 사례를 준비하는 일에 가깝다는 점을 이해했는가?
  • k-NN에서 예측 시 비교 비용이 커질 수 있다는 점을 알고 있는가?

출처와 참고 자료