이웃 성분 분석(NCA)이란? AI에서 정답 라벨로 가까움의 기준을 학습하는 방법
TL;DR
이웃 성분 분석(NCA)은 훈련 라벨을 이용해 같은 클래스의 사례가 이웃으로 선택될 가능성이 커지도록 선형 변환을 학습하는 방법입니다. 원래 거리에서 섞이던 사례를 다른 좌표로 옮겨 가까움의 기준을 바꿉니다. 낮은 차원의 표현을 만들 수도 있지만 NCA 자체의 출력은 분류 라벨이 아닌 좌표입니다. 별도의 KNN 분류기와 결합해 실제 성능을 확인하며 초기화·입력 척도·훈련 비용과 독립 평가를 함께 점검합니다.
핵심 3줄 요약
- 핵심 1
거리 계산의 표현을 학습합니다. 정답 라벨을 보고 입력 특징을 섞는 선형 변환을 맞춥니다. - 핵심 2
자기 자신은 이웃에서 뺍니다. 나머지 사례의 제곱 거리로 선택 확률을 구하고 같은 라벨의 확률을 더합니다. - 핵심 3
좌표와 예측 결과를 나눕니다. 새 좌표를 KNN에 넣어 검증하며 그림의 분리만으로 성능을 확정하지 않습니다.
이 글에서 다룰 내용
- 이웃 성분 분석의 한 문장 정의
- 네 점의 거리와 선택 확률을 비교하는 쉬운 예시
- 정답 라벨로 가까움의 기준을 학습하는 이유
- 선형 변환·자기 제외·확률 합의 작동 순서
- 성분 수·초기화·반복 설정과 출력 좌표의 뜻
- KNN·PCA·LDA·비지도 임베딩과의 차이
- 평가 누수·불균형·계산 비용의 주의점
이웃 성분 분석을 한 문장으로 정의하면 무엇인가요?
이웃 성분 분석은 각 훈련 표본을 자기 자신을 제외한 이웃으로 분류할 때 같은 라벨을 고를 확률의 합이 커지도록 선형 거리 변환을 학습하는 지도 거리 학습 방법입니다.
영문명은 Neighborhood Components Analysis이고 약어는 NCA입니다. 원 논문은 영국식 철자인 Neighbourhood를 사용합니다. 여기서는 scikit-learn의
NeighborhoodComponentsAnalysis
와 공식 구현을 기준으로 설명합니다. 한 행은 한 표본, 한 열은 수치 특징이며 학습에는 해당 행의 클래스 라벨이 필요합니다.
거리 학습은 어떤 사례를 가깝게 볼지 데이터에서 정하는 작업입니다. NCA는 원본 특징을 섞는 행렬을 배우고 그 변환 뒤의 유클리드 거리를 사용합니다. 정답 라벨을 쓰지 않는 PCA나 이웃 그래프만으로 좌표를 만드는 비지도 변환과 목적이 다릅니다.
한 줄 정리: 정해 둔 거리에서 이웃을 찾는 데 그치지 않고 라벨 구분에 맞는 거리의 표현을 먼저 학습합니다.
쉬운 예시로 이해해 볼까요?
감자나라ai님이 두 특징으로 두 종류의 사례를 구분한다고 가정해 보겠습니다. A 클래스의 점은
(0, 0)
과
(0, 3)
, B 클래스의 점은
(2, 0)
과
(2, 3)
입니다. 설명용 숫자로 직접 만든 자료이며 실제 고객이나 센서를 학습한 결과는 아닙니다.
첫 A 점에서 같은 A 점까지의 원래 거리는 3입니다. 다른 클래스인 첫 B 점까지는 2여서 가장 가까운 사례 하나만 고르면 B를 선택합니다. 둘째 특징의 차이가 이 예시의 클래스 구분을 방해합니다. 첫 특징만 남기는 고정 변환
L=(1, 0)
을 직접 정해 보겠습니다.
- 변환 후 A의 두 좌표는 모두 0, B의 두 좌표는 모두 2입니다. 첫 A 점과 같은 클래스의 다른 점 사이 거리는 0이 됩니다.
- NCA의 확률 규칙으로 첫 A 점이 같은 클래스의 이웃을 고를 확률을 계산하면 원래 공간에서 약 0.006692입니다.
- 고정 변환 후 같은 확률은 약 0.964663입니다. 자기 자신은 제외하고 세 이웃의 제곱 거리의 음수에 지수 함수를 적용한 뒤 합으로 나누어 계산했습니다.
위 값은 NumPy로 실제 계산한 고정 변환의 예시입니다. NCA 추정기를 학습해 얻은 행렬이나 별도 테스트의 분류 정확도로 소개하지 않습니다. 좋은 변환의 방향을 설명하는 숫자이며 어떤 자료에서나 첫 특징만 남기면 좋다는 추천도 아닙니다.
변환 후 첫 A 점의 같은 라벨 확률도 1은 아닙니다. 확률적 규칙은 다른 클래스의 이웃에도 작은 선택 확률을 남깁니다. 이 확률과 별도 KNN의 다수결 결과, 실제 새 표본의 정답률은 각각 다른 값입니다.
쉬운 예시: 입력 숫자를 바꾸면 이웃의 순서와 선택 확률이 달라집니다. NCA는 라벨을 이용해 그 숫자 변환을 학습합니다.
왜 AI에서 이웃 성분 분석이 중요한가요?
분류에 유용한 가까움을 찾습니다
모든 특징을 같은 기준으로 더한 원래 거리가 정답 구분에 좋은 것은 아닙니다. 관련 없는 변동이 큰 열 때문에 다른 클래스가 더 가까워질 수 있습니다. NCA는 라벨을 활용해 특징의 크기와 조합을 조정합니다. 전처리만 한 KNN과 같은 분할에서 비교하면 거리 학습의 효과를 확인할 근거가 생깁니다.
라벨을 반영한 적은 좌표를 만듭니다
출력 차원을 줄이면 사례를 그림으로 살피거나 낮은 차원의 입력으로 분류기를 비교합니다. 전체 분산을 많이 남기는 것보다 같은 라벨의 이웃 선택에 초점을 둡니다. 훈련 라벨을 사용했으므로 같은 자료의 그림에서 색깔이 나뉘었다는 사실은 독립적인 분류 성능의 증거가 아닙니다.
변환과 후속 분류를 따로 점검합니다
NCA는 좌표를 만들고 KNN은 그 좌표에 있는 이웃의 정답을 결합합니다. 변환 학습이 잘못됐는지, 이웃 수나 투표 방식이 맞지 않는지 단계를 나누어 조사합니다. 학습한 변환만 저장했다고 이웃 분류기에 필요한 훈련 사례까지 보관된 것은 아닙니다.
핵심 인사이트: 표현 학습의 목적함수, 변환 좌표, 실제 분류 지표를 각각 기록해야 가까움의 변화가 필요한 성능으로 이어졌는지 알 수 있습니다.
이웃 성분 분석은 어떤 순서로 작동하나요?
1. 훈련 특징과 클래스 라벨을 준비합니다
자료를 먼저 나누고 필요한 결측 처리와 척도 조정을 훈련에서 맞춥니다. 확인한 NCA 구현은 분류 라벨을 검사합니다. 새 좌표를 만든다는 이유로 라벨 없는 fit이 가능하다고 가정하지 않습니다. 모델 내부의 변환은 원본 열을 자동 표준화하는 단계도 아닙니다.
2. 변환된 거리에서 자기 제외 확률을 구합니다
변환 행렬을 L이라고 하면 각 입력을 L로 옮긴 뒤 모든 훈련 표본 쌍의 제곱 거리를 구합니다. 각 거리의 음수에 지수 함수를 적용하고 자기 자신을 뺀 이웃들의 합으로 나누어 선택 확률을 만듭니다. 가까운 사례의 확률이 크며 자기 선택 확률은 0입니다.
이 단계는 사용자가 정한 k개만 자르는 일반 KNN 투표가 아닙니다. 이 구현은 모든 다른 훈련 표본을 대상으로 확률을 계산합니다. NCA 생성자에는 이웃 수를 정하는
n_neighbors
인자가 없습니다.
3. 같은 클래스의 선택 확률 합을 높입니다
한 표본에서 같은 라벨인 다른 표본들의 선택 확률을 더합니다. 그 값을 전체 훈련 표본에 걸쳐 합친 목적을 크게 만드는 방향으로 L을 갱신합니다. 확인한 구현은 L-BFGS-B 최적화를 사용하며 계산에서는 부호를 바꿔 최소화 문제로 풉니다.
자기 표본을 제외한 학습 목표라도 별도 테스트 자료는 아닙니다. 변환 행렬 자체를 같은 훈련 라벨로 최적화하기 때문입니다. 이 목적함수의 합을 후속 KNN의 테스트 정확도나 확률 캘리브레이션으로 바꾸어 읽지 않습니다.
4. 저장한 행렬로 새 입력을 변환합니다
components_
는 출력 성분 수 × 원본 특징 수 모양입니다. 행 단위 입력 X의 변환은
X @ components_.T
이며 결과는 표본 수 × 출력 성분 수입니다. 새 입력의 라벨은 transform에 필요하지 않습니다. 앞단 전처리가 있다면 같은 저장된 처리를 먼저 적용합니다.
주요 설정과 결과는 어떻게 읽나요?
성분 수는 출력 차원의 수입니다
n_components
를 생략하면 원본 특징 수를 사용합니다. 기본 호출이 자동 차원 축소를 뜻하지는 않습니다. 확인한 구현에서 정한 성분 수는 원본 특징 수를 넘을 수 없습니다. 더 적은 차원을 원하면 직접 정하고 후속 분류 품질과 비용을 비교합니다.
LDA의 클래스 수에서 하나를 뺀 상한을 NCA 전체의 출력 차원 상한으로 옮기지 않습니다. 다만 LDA로 초기화하는 경로에는 해당 초기화의 제약이 있습니다. 명목 출력 차원과 학습 행렬의 실제 랭크도 구별합니다.
초기화는 학습의 출발점입니다
init="auto"
는 자료와 요청한 차원에 따라 LDA·PCA·단위행렬 초기화 중 하나를 고릅니다. 이 선택이 최종 결과를 해당 LDA나 PCA 결과로 고정하지는 않습니다. 이후 NCA의 목적함수를 최적화합니다. 명시적인 초기화 방식이나 행렬을 줄 때는 모양과 지원 범위를 확인합니다.
목적함수는 초기화에 따라 다른 해에 도달할 수 있습니다.
random_state
는 무작위 초기화와 일부 PCA 초기화의 재현을 돕는 설정입니다. 같은 시드를 썼다고 모든 환경의 결과와 미래 성능까지 동일하다는 뜻은 아닙니다.
반복 종료와 분류 성능을 분리합니다
max_iter
의 기본값은 50이고
tol
은 최적화의 종료 허용오차입니다. tol을 업무의 허용 오분류율로 해석하지 않습니다. 반복 기록
n_iter_
와 설정을 남기며 한도에 도달한 모델의 성능은 따로 평가합니다.
확인한 구현은 최적화 실패 경고가
verbose
가 켜진 경로에 있습니다. 기본 출력에서 경고를 못 봤다는 사실만으로 수렴을 확정하지 않습니다. NCA 자체에는 분류용 predict나 정확도 score가 없으므로 결합한 KNN 또는 전체 파이프라인의 점수를 확인합니다.
이웃 성분 분석과 헷갈리는 용어는 무엇이 다른가요?
KNN·표준화와의 차이
K-최근접 이웃(KNN)은 정한 거리로 이웃을 고르고 라벨을 결합합니다. NCA는 그 앞에서 거리의 표현을 학습합니다. 표준화는 특징별 평균과 표준편차로 단위를 맞추며 정답을 쓰지 않습니다. NCA는 라벨로 특징의 조합까지 맞추므로 표준화와 같은 변환이 아닙니다.
PCA·선형 판별 분석과의 차이
주성분 분석(PCA)는 라벨 없이 분산이 큰 축을 찾습니다. 선형 판별 분석(LDA)는 클래스별 분포와 공통 공분산을 가정한 분류 및 판별 축을 다룹니다. NCA는 같은 클래스의 확률적 이웃 선택을 목표로 하며 LDA와 같은 클래스 분포 모양을 가정하지 않습니다. 기본 선형 변환의 표현 한계까지 사라지는 것은 아닙니다.
마할라노비스 거리·비지도 임베딩과의 차이
NCA의 제곱 거리는 변환 행렬에서
M = L.T @ L
을 만든 마할라노비스 형태로 쓸 수 있습니다. 이 M은 대칭 양의 준정부호이며 일반 공분산의 역행렬을 그대로 대입한 것과 같다고 가정하지 않습니다. 차원을 줄이면 서로 다른 원본 점이 거리 0인 좌표로 겹칠 수도 있습니다.
UMAP·LLE 같은 비지도 변환의 기본 목표와도 다릅니다. 기본 NCA는 클래스 라벨과 선형 변환을 사용합니다. 감독 정보를 쓰는 다른 변형이나 딥 NCA를 이름만 같다는 이유로 이 API의 기능으로 소개하지 않습니다.
비교 정리: KNN은 이웃의 정답 결합, 표준화는 단위 조정, PCA는 분산 축, LDA는 판별 분석, NCA는 라벨을 활용한 거리 변환 학습입니다.
실전에서는 어디에 쓰이나요?
손글씨와 수치 특징의 분류 표현을 비교합니다
공식 숫자 이미지 예제는 PCA·LDA·NCA를 같은 훈련·테스트 분할에 적용하고 표준화 뒤 두 좌표를 만듭니다. 각 변환의 훈련 좌표로 KNN을 맞추고 테스트 좌표로 정확도를 평가합니다. 그 예제의 순위를 자기 이미지나 센서 자료의 성능으로 대신하지 않습니다.
라벨이 섞인 사례의 원본을 검토합니다
새 좌표의 이웃을 원본 ID와 연결하면 서로 다른 라벨이 왜 가까운지 조사할 단서가 생깁니다. 측정 오류나 애매한 라벨을 검토하되 이웃 관계를 원인 설명으로 단정하지 않습니다. 모든 클래스의 의미 유사도를 복원하는 범용 임베딩이라고 부르지도 않습니다.
이웃 성분 분석을 적용할 때 어떤 순서로 확인하나요?
1. 자료 분리와 기준 모델을 고정합니다
같은 사람·장비의 반복 기록과 복사본이 훈련·평가 양쪽에 섞이지 않게 나눕니다. 표준화만 한 KNN을 기준으로 두고 출력 차원과 후속 이웃 수를 검증에서 선택합니다. 테스트 라벨을 목적함수에 넣거나 결과 그림을 본 뒤 좋은 테스트만 고르지 않습니다.
2. 변환 학습까지 각 훈련 폴드에 넣습니다
결측 처리·스케일러·NCA·KNN 전체를 파이프라인으로 평가합니다. 교차 검증의 각 훈련 폴드에서 NCA도 다시 학습합니다. 전체 자료와 라벨로 NCA를 먼저 맞춘 뒤 KNN만 교차 검증하면 검증 정답이 좌표에 반영됩니다.
3. 클래스별 오류와 총비용을 확인합니다
전체 정확도 외에 드문 클래스의 재현율과 혼동 사례를 확인합니다. 훈련 쌍 거리 행렬은 표본 수의 제곱에 따라 커지므로 차원을 줄여도 큰 표본의 학습 메모리는 별도 문제입니다. 변환 시간과 후속 이웃 검색·훈련 사례 보관까지 포함해 측정합니다.
4. 운영에서 동일한 변환을 적용합니다
열 이름과 순서, 전처리, NCA 행렬과 KNN의 훈련 자료, 버전을 함께 보관합니다. 새 자료에는 저장된 transform만 적용합니다.
warm_start=True
는 이전 행렬에서 다음 fit을 시작하는 기능이며 새 표본을 부분 학습하는 partial_fit과 같지 않습니다.
실전 팁: 같은 분할에서 기준 KNN과 NCA를 앞에 둔 KNN의 오류 사례를 나란히 확인하세요. 좌표의 분리와 실제 분류의 개선을 구별하기 쉽습니다.
사용할 때 무엇을 주의해야 하나요?
첫째, 잘못된 라벨도 변환 학습에 반영됩니다. 같은 라벨의 선택 확률을 높이는 목표이므로 라벨 오류와 수집 편향을 먼저 확인합니다. 훈련에서 같은 클래스의 다른 사례가 없는 표본은 같은 라벨 이웃의 확률 합이 0입니다. 드문 클래스가 충분히 관찰됐는지 살핍니다.
둘째, 목적함수의 확률을 보장으로 읽지 않습니다. 계산한 확률은 훈련 표본 중 이웃을 선택하는 규칙의 값입니다. 새 사례의 정답 확률이 검증됐다는 뜻은 아닙니다. 후속 분류기의 확률도 필요하다면 별도 보류 자료에서 점검합니다.
셋째, 직교 축이나 완전 복원을 기대하지 않습니다. 학습 행렬은 PCA처럼 직교성과 설명 분산 순서를 보장하는 출력이 아닙니다. 줄인 좌표에서 원본의 모든 차이를 복구할 수 없으며 좌표의 부호나 각 성분 계수에 인과 의미를 붙이지 않습니다.
넷째, 모든 초기화와 차원에서 개선을 약속하지 않습니다. 기본 NCA는 선형 변환입니다. 클래스 구조에 따라 한 행렬로 좋은 거리를 얻기 어려울 수 있습니다. 여러 초기화와 출력 차원을 훈련·검증 경계 안에서 비교하고 개선되지 않은 결과도 함께 남깁니다.
주의: 훈련 이웃의 확률 합, 그림의 분리, 최적화 종료와 새 자료의 성능은 서로 다른 점검 항목입니다.
자주 묻는 질문
Q1. NCA는 정답 없이 학습하는 차원 축소인가요?
이 글의 기본 NCA는 클래스 라벨을 사용하는 지도 방법입니다. 새 입력을 transform할 때는 그 입력의 정답을 요구하지 않지만 학습 단계의 라벨은 필요합니다.
Q2. NCA만 호출하면 분류 라벨이 나오나요?
아닙니다. 이 scikit-learn 클래스는 변환 좌표를 반환합니다. 분류하려면 KNeighborsClassifier 같은 후속 분류기를 학습하고 같은 변환을 거친 새 입력에 적용합니다.
Q3. n_components를 생략하면 차원이 줄어드나요?
기본값 None은 원본 특징 수를 사용합니다. 더 적은 좌표가 필요하면 성분 수를 직접 정합니다. 클래스 수에 따른 LDA 상한을 NCA 전체에 그대로 적용하지 않습니다.
Q4. n_neighbors는 NCA의 이웃 수인가요?
이 구현의 NCA 생성자에는 해당 인자가 없습니다. 학습 목표는 모든 다른 훈련 표본에 대한 확률로 계산하며 후속 KNN의 n_neighbors는 예측에 참여할 이웃 수입니다.
Q5. 자기 자신을 빼면 테스트 평가를 생략해도 되나요?
안 됩니다. 같은 훈련 라벨로 변환 행렬을 최적화합니다. 자기 제외는 학습 목적함수의 규칙이며 실제 독립 평가는 처음부터 분리한 자료에서 전체 파이프라인으로 수행합니다.
Q6. warm_start로 계속 들어오는 표본을 부분 학습하나요?
warm_start는 이전 변환을 다음 fit의 출발점으로 쓰는 설정입니다. 이 클래스의 부분 학습 API를 의미하지 않습니다. 새 데이터로 다시 학습한 변환과 후속 분류기를 함께 재검증합니다.
출처
마무리
이웃 성분 분석은 라벨을 이용해 같은 클래스의 사례가 이웃으로 선택되기 좋은 선형 표현을 학습하는 방법입니다. 원래 거리를 그대로 쓰는 KNN과 달리 가까움의 기준부터 조정하며 필요하면 출력 차원도 줄입니다. 학습한 좌표와 후속 분류의 정답은 구별해서 읽습니다.
처음 적용한다면 자기 제외 확률과 성분 행렬의 역할부터 확인하세요. 이후 자료 분리와 폴드 안 변환 학습, 성분 수·초기화·계산 비용, 클래스별 테스트 오류를 함께 비교합니다. 운영에서 같은 전처리와 변환·분류기를 사용해야 실험에서 확인한 입력 표현을 유지할 수 있습니다.
