AI/ML

kNN(k-Nearest Neighbors) 알고리즘 - 농구선수 포지션 예측(2)

어른이프로그래머 2022. 1. 3. 04:00
이 포스트는 허민석님의 유튜브 머신러닝 내용을 정리한 글입니다. 실습 코드는 도서 나의 첫 머신러닝/딥러닝에서 발췌해왔습니다. 실습 코드와 자료는 링크의 Github에서 볼 수 있습니다.

이전 포스트에서는 2020-21 시즌 NBA 농구 선수의 실제 데이터를 담은 사이트에서 크롤링하여 판다스의 데이터 프레임의 형식으로 가공한 다음, csv 파일을 생성해봤습니다. 이번에는 데이터 시각화 및 분석 이후 kNN 모델을 생성한 다음 예측 및 평가를 진행해보겠습니다. 실습 환경은 Google Colab에서 진행하였으며, 실습 코드 및 데이터는 위 링크의 Github에서 받아볼 수 있습니다.

 

그렇다면 이제 코드를 보겠습니다. 필요한 라이브러리들을 임포트 한 다음, 먼저 만들어 둔 csv 파일을 읽어 판다스 데이터 프레임 형태로 생성합니다. kNN은 scikit-learn에 이미 구현되어 있으므로 단순히 sklearn 라이브러리를 임포트 해서 쓰면 됩니다. 먼저 데이터 구성을 살펴보겠습니다. 실제 사이트에서는 28개의 속성이 있지만, 우리는 이미 학습에 필요할 것으로 예상되는 속성들만 크롤링해왔기 때문에 당장은 더 이상 데이터를 가공하지 않아도 될 것으로 보입니다. 학습 레이블의 수를 확인한 다음, matplotlib를 이용해 속성들을 2차원에 표현해보겠습니다. 

필요한 라이브러리들을 임포트한 다음, 깃허브에 있는 csv 파일을 읽어들여 판다스 데이터 프레임 형태로 만듭니다.
수집된 데이터의 상위 5개 샘플과 학습 레이블(포지션)의 분포를 확인합니다.

아래 사진처럼 2차원 좌표에 속성들을 묶어 표현해봤습니다. O는 C(센터), X는 SG(슈팅 가드)이며, 데이터 시각화의 목적은 학습에 불필요한 속성을 제거하는 것에 있습니다. 스틸 횟수와 2점슛, 어시스트 횟수와 2점 슛을 그린 아래 두 사진의 그래프를 보면, 센터 포지션과 슈팅 가드 포지션이 비슷한 수준으로 분포되어 있어 두 포지션을 구별하는 변별력이 떨어지는 것으로 보이는 반면, 블로킹과 3점 슛, 리바운드와 3점 슛의 분포를 그린 그래프에서는 두 포지션이 나름의 구별되는 군집을 이루고 있습니다. 실제 농구에서 2점 슛은 센터 포지션과 슈팅 가드 포지션 모두 득점을 많이 하지만, 3점 슛은 슈팅 가드의 주요 역할 중 하나로, 페인트존 내에서 플레이를 주로 하는 센터에 비해 더 많습니다. 반면 리바운드는 센터 포지션이 훨씬 많습니다. 이렇게 우리는 데이터를 시각화하여 필요한 속성이 무엇인지, 불필요한 속성이 무엇인지 구별해낼 수 있었습니다. 사실 속성별 필요/불필요 구분은 직접 그래프를 그려보며 확인해봐도 되지만, 미리 가설을 세운 다음 가설이 맞는지 검증해보는 것도 좋은 방법입니다. 예를 들면 "센터 포지션은 페인트존 내에서 주로 활동하므로 리바운드 횟수가 슈팅 가드에 비해 많을 것이다"는 가설을 세운 다음 두 속성을 그려본 다음, 두 속성은 학습에 필요한 속성인 것을 확인하는 것과 같습니다.

포지션 별 스틸과 2점슛의 분포
포지션 별 어시스트와 2점슛의 분포
포지션 별 블로킹과 3점슛의 분포
포지션 별 리바운드와 3점슛의 분포

그렇다면 분별력이 떨어져 학습에 불필요한 속성인 2점슛과 어시스트, 스틸을 데이터 프레임에서 삭제한 다음, 다시 데이터 프레임을 확인해보면, 이제 우리는 3점 슛, 리바운드, 블로킹의 속성으로 모델을 학습할 것임을 알 수 있습니다. 그다음 학습 데이터와 테스트 데이터를 8:2의 비율로 분리하겠습니다. 데이터를 분리하는 작업도 이미 sklearn 내 train_test_split()의 함수로 구현되어 있습니다. 테스트 데이터 사이즈를 결정짓는 test_size를 0.2로 설정한 다음 실행하면, train에는 전체 데이터의 80%, test에는 전체 데이터의 20%로 분리되어 저장되어 있음을 알 수 있습니다.

2점슛, 어시스트, 스틸 속성을 데이터 프레임에서 삭제한 다음 학습 데이터와 테스트 데이터를 분리합니다.

이제 kNN 알고리즘을 적용하여 모델을 생성하기 위해, 가장 중요한 작업인 최적의 K를 찾는 작업을 진행하겠습니다. 최적의 K를 찾는 방법으로 가장 많이 사용되는 것은 검증 데이터를 사용해 가장 예측율이 높은 K를 찾는 것입니다. 위에서 분리한 테스트 데이터(test)와 sklearn의 cross_val_score를 사용하여 kNN 모델의 k-fold 교차 검증을 진행할 것입니다. k-fold 교차 검증에 대해 잠시 알아보면, 머신러닝의 모델을 테스트 하기 이전, 검증 단계에서 모델의 성능을 짐작해볼 수 있습니다. 실제 모델을 생성 시에는 오랜 시간과 큰 비용이 소모되므로, 매번 함수 인자 값을 변경하며 모델 성능을 직접 테스트하는 것은 굉장히 비효율적입니다. 일반적으로 모델 검증에는 검증 데이터를 활용하는데, 예를 들어 위에서처럼 전체 데이터를 20%의 테스트 데이터와 80%의 학습 데이터로 나눈 이후, 학습 데이터에서 다시 90%를 실제 학습 데이터, 10%를 검증 데이터로 활용합니다. 이처럼 검증 데이터는 전체 데이터에 비해 굉장히 작은 비율이기 때문에, 전체 데이터가 크지 않다면 검증 데이터를 한 번 사용하여 모델 성능을 평가 시에는 지엽적이거나 한쪽에 편증된 데이터가 사용될 수 있다는 측면에서 검증 정확도를 신뢰하기 어렵습니다. 이때 사용할 수 있는 방법이 k-fold 교차 검증으로, 학습 데이터의 일정 부분을 검증 데이터로 활용하되 n번의 검증 과정으로 모든 학습 데이터를 한 번씩 검증 데이터로 사용할 수 있게끔 하는 방법입니다. k = 10이라고 한다면 k-fold 교차 검증에서는 학습 데이터를 비반복으로 10%씩 분리하여 검증 데이터로 활용하여 검증 결과를 낸 다음, 이들을 평균 낸 값을 사용합니다. 이렇게 되면 학습 데이터는 전체 데이터의 80%에 해당하는 만큼, 충분한 검증이 이루어졌다고 볼 수 있으며 한쪽으로 편증된 데이터들 또한 평균값으로 회귀되기 때문에 전반적으로 신뢰할 수 있는 검증 결과를 얻을 수 있습니다. 다시 돌아와 최적의 k를 찾기 위해 k의 범위를 3부터 학습 데이터의 절반까지로 지정한 다음 k=10의 k-fold 교차 검증을 수행하여 검증 결과를 저장한 다음, k 값에 따른 정확도를 그래프로 그려보겠습니다.

k의 범위를 정한 다음 최적의 k를 찾는 k-fold 교차 검증을 수행합니다.
가장 높은 검증 정확도를 보이는 k를 찾습니다.

그래프를 그려 확인해보니 k = 5일 때 검증 정확도가 가장 높은 것을 알 수 있습니다. 이제 최적의 k를 찾은 다음, 모델을 학습하고 미리 분리해둔 테스트 데이터로 모델을 검증하는 일만 남았습니다. 미리 짚고 넘어가자면 학습 데이터와 테스트 데이터는 무작위로 분리되기 때문에 실행마다 최적의 k 값이 달라질 수 있습니다.

모델을 학습하고 테스트하여 예측 정확도를 출력합니다.

sklearn에 구현되어 있는 kNeighborsClassifier()의 n_neighbors를 미리 찾은 최적의 k값을 넣은 다음 3P, BLK, TRB 속성과 Pos 레이블로 모델을 학습하여 테스트한 다음 정확도를 출력하니 0.85(85%)의 정확도를 보입니다. 테스트 데이터 선수의 3P, BLK, TRB 값을 토대로 포지션을 예측한 결과와 실제 포지션을 비교해본 결과가 100개 중 85개 수준으로 일치했다는 것은 모델 생성에 힘들지 않았음에도 유의미하고 괜찮은 정확도를 보였다고 볼 수 있습니다. 실제로 예측값과 실제값을 비교한 데이터 프레임을 확인해보면 20명 중 3명의 포지션 예측만 틀렸음을 알 수 있습니다. 모든 센터 포지션 선수들이 3점슛에 약하거나 모든 슈팅가드 포지션 선수들이 리바운드가 적은 것은 아닐 것이므로, 실제로 kNN 알고리즘 모델은 훨씬 더 좋은 평가를 받을 수 있을 것입니다.

이번 포스트에서는 데이터를 시각화하여 불필요한 속성을 제거하여 kNN 알고리즘 모델을 생성하고 학습하는 과정에서, k-fold 교차 검증까지 알아보았습니다. 사실 kNN 알고리즘은 기존 데이터와의 거리를 계산하여 예측하기 때문에, 연산 과정이 많아 예측 속도가 느리지만 별도의 모델 학습이 필요없습니다. 따라서 게으른 학습(lazy learning)으로도 불리며, 실시간 데이터를 사용할 때 유용하게 사용됩니다. 이처럼 kNN 알고리즘의 장단점을 확실히 알고서 모델을 적절히 사용한다면 쉬운 과정으로도 높은 예측율을 얻을 수 있습니다.