데이터사이언스/머신러닝

NBA 농구 강팀이 연승하는 이유는?

ghtis1798 2021. 1. 5. 00:57

NBA Game Dataset

🛒데이터 수집 및 전처리

데이터는 캐글에 있는 NBA Regular Season Data를 사용하였습니다.

https://www.kaggle.com/michaelmcfarlane/20172018-nba-regular-season-game-data

사용할 라이브러리와 파일을 불러오겠습니다.

import pandas as pd
import numpy as np

import plotly.express as px
import plotly.graph_objects as go
import matplotlib.pyplot as plt
import seaborn as sns

from sklearn.cluster import KMeans
from sklearn.preprocessing import MinMaxScaler
from sklearn.decomposition import PCA 

import warnings

pd.set_option('display.max_rows', 100)
warnings.filterwarnings('ignore')

data = pd.read_csv('rawdata.csv')
data.head()

보시다시피 Column의 수가 꽤 많고 농구 용어로 이루어져 있습니다.

data.info()

1230개의 경기에 대한 정보가 있고 Null값은 없습니다.

농구 용어를 먼저 이해할 필요가 있어 보입니다.

중점적으로 사용할 데이터는 다음과 같습니다.

FGM(야투득점), 3PM(3점슛득점), REB(리바운드), FGA(야투시도횟수), PF(파울횟수), FTM(자유투득점)입니다.

농구를 즐겨보지 않아 야투라는 말이 낯설었습니다.

야투는 쟈유투를 제외한 필드에서의 득점을 의미합니다.

자세한 정보는 아래 링크에서 확인할 수 있습니다.

https://www.ichanggo.blogspot.com/2017/05/nba-glossary.html

이제 TEAM과 W/L 데이터는 문자열이므로 삭제해 준 뒤, PCA를 적용하겠습니다.

그 전에 표준화를 시켜주겠습니다.

이유는 PTS 득점점수 같이 높은 값들과 AST나 FTM같은 낮은 값들간 차이가 크기 때문입니다.

# 표준화
scaler = MinMaxScaler()
scaler.fit(win)
scaled = scaler.transform(win)
print(scaled)

각 값들간의 차이가 줄어들었습니다.

다음은 PCA 적용 결과입니다.

PCA란 Principal Component Analasis로 해석하면 주성분 분석이라는 뜻입니다.

차원 축소 기법 중 하나로 Column의 개수가 많을 때 Dimemsion을 낮추는 역할을 합니다.

여기서는 각 주성분 별로 크게 작용하는 Column들이 어떤 것인지 파악만 해두도록 하겠습니다.

주성분별로 강한 영향력을 보이는 Column들만 보는 것이 목적이므로,

주성분의 개수는 임의로 4개 정도로 설정하였습니다.

# PCA 설정
pca = PCA(n_components = 4)
pca.fit(scaled)

# PCA 적용
pca_result = pca.transform(scaled)
pca_result = pd.DataFrame(data=pca_result, columns = ['PCA1','PCA2','PCA3','PCA4'])

pca_value = pd.DataFrame(data = pca.components_.T, index=win.columns)
print(pca_value)

PCA 결과 큰 절대값을 갖는 값으로는 PTS, FGM, 3PM, FGA, REB, PF, FTA 정도입니다.

원래는 각 Feature들의 영향력을 바탕으로 주성분별로 해석한 뒤,

Labeling을 한 값을 클러스터링에 적용해야 합니다.

예시)
# PCA1: 득점률 : PTS, FGM, 3PM
# PCA2: 적극성 : FGA, OREB, REB
# PCA3: 수비기술 : PF, FTA
# PCA4: 3점슛 : 3PA, 3PM 

하지만 간단히 클러스터링을 실시하는 것이 목적이므로 특정 Feature들만 추출하도록 하겠습니다.

# FGM, 3PM, REB, FGA, PF, FTM  추출
win_ = win[['FGM', '3PM', 'REB', 'FGA' , 'PF', 'FTM']]
win_.head()

FGM: 야투 득점, 3PM: 3점슛 득점, REB: 리바운드, FGA: 야투 시도 횟수, PF: 파울 횟수, FTM: 자유투 득점

위 6개 Column들만 추출하였습니다.

이를 바탕으로 클러스터링을 진행하겠습니다.

우선 몇 개의 클러스터로 나눌지 Scree plot을 그려서 확인해보겠습니다.

elbow method라고도 불리는 방법은 군집 수를 늘려가면서,

각 그룹내에 요소들이 얼마나 가까이 뭉쳐 있는지를 파악하는 방법입니다.

Scree plot을 기준으로 급격한 기울기로 꺾이는 지점을 elbow point라고 하며 이 때의 군집 수를 사용합니다.

# 표준화
scaler = MinMaxScaler()
scaler.fit(win_)
scaled = scaler.transform(win_)

def elbow(X):
  sse = []

  for i in range(1, 11):
    km = KMeans(n_clusters=i, init='k-means++', random_state=0)
    km.fit(X)
    sse.append(km.inertia_)

  plt.plot(range(1,11), sse, marker='o')
  plt.xlabel('Number of Clusters')
  plt.ylabel('Within Group Sum of Squares')
  plt.show()

elbow(scaled)

4이후로는 완만하게 감소하므로 클러스터 수는 3개로 정했습니다.

📌Clustering

이제 직접 클러스터링을 해보겠습니다.

# 클러스터링 실시
km = KMeans(n_clusters=3).fit(scaled)

result = pd.DataFrame(data=scaled)
result.columns = ['FGM', '3PM', 'REB', 'FGA' , 'PF', 'FTM']

3개의 클러스터들이 각 Column 별로 어떤 값을 갖고 있는지 살펴보겠습니다.

cluster_result = km.cluster_centers_
cluster_result = pd.DataFrame(data=cluster_result,
                              columns=['FGM', '3PM', 'REB', 'FGA' , 'PF', 'FTM'])
cluster_result.head()

값으로만 보았을 때는 어떤 클러스터가 무슨 특징이 있는지 한 눈에 보기 어렵습니다.

따라서 시각화 한 뒤 각 클러스터 별로 적절한 이름을 붙여보겠습니다.

📊결과 해석 및 시각화

클러스터링 된 결과값을 강팀, 약팀과 함께 시각화해보겠습니다.

강팀은 어떤 클러스터에 가까운지, 약팀은 어떤 점이 부족한지 파악해보겠습니다.

2017-2018 강팀의 예로 Houston Rockets와 Golden State Warriors를 뽑아보았습니다.

약팀의 예로는 리그 성적이 저조했던 Portland와 Dallas를 뽑아 보았습니다.

# 휴스턴 로키츠 팀 정보 추출
HOU = result[result['TEAM']=='HOU']
HOU = HOU.mean()
HOU = pd.DataFrame(data=[HOU[:-1]], columns=['FGM', '3PM', 'REB', 'FGA' , 'PF', 'FTM'])
# 골든 스테이트 워리어스 팀 정보 추출
GSW = result[result['TEAM']=='GSW']
GSW = GSW.mean()
GSW = pd.DataFrame(data=[GSW[:-1]], columns=['FGM', '3PM', 'REB', 'FGA' , 'PF', 'FTM'])

# 포틀란드 팀 정보 추출
POR = result[result['TEAM']=='POR']
POR = POR.mean()
POR = pd.DataFrame(data=[POR[:-1]], columns=['FGM', '3PM', 'REB', 'FGA' , 'PF', 'FTM'])
# 달라스 팀 정보 추출
DAL = result[result['TEAM']=='DAL']
DAL = DAL.mean()
DAL = pd.DataFrame(data=[DAL[:-1]], columns=['FGM', '3PM', 'REB', 'FGA' , 'PF', 'FTM'])

다음은 시각화를 진행하는 함수를 만들었습니다.

result 값과 team 정보, team_name을 입력하면 클러스터링 결과를 시각화합니다.

def Visualization(cluster, team, team_name):
  categories = cluster.columns

  fig = go.Figure()

  fig.add_trace(go.Scatterpolar(
      r = cluster.values[0],
      theta = categories,
      fill='toself',
      name='강한 수비형'
  ))

  fig.add_trace(go.Scatterpolar(
      r = cluster.values[1],
      theta = categories,
      fill='toself',
      name='적극적인 리바운드형'
  ))

  fig.add_trace(go.Scatterpolar(
      r = cluster.values[2],
      theta = categories,
      fill='toself',
      name='정확한 슈팅형'
  ))

  fig.add_trace(go.Scatterpolar(
      r = team.values[0],
      theta = categories,
      fill='toself',
      name=team_name
  ))

  fig.update_layout(
    polar=dict(
      radialaxis=dict(
        visible=True,
        range=[0, 0.7]
      )),
  )

  fig.show()

시각화 결과입니다.

Visualization(cluster_result, HOU, 'HOU')
Visualization(cluster_result, GSW, 'GSW')
Visualization(cluster_result, POR, 'POR')
Visualization(cluster_result, DAL, 'DAL')

🙂강팀 특징 파악하기

우선 3개의 클러스터 먼저 살펴보겠습니다.

첫 번째 클러스터(파랑)의 경우 파울과 자유투득점이 높습니다.

위험한 상황에 적절한 파울을 만들어 흐름을 끊거나,

공격시 파울을 유도해내며 차곡차곡 득점을 쌓아가는 유형이라고 볼 수 있습니다.

따라서 '강한 수비형' 이라고 이름 붙였습니다.

두 번째 클러스터(빨강)의 경우 야투 시도 횟수와 리바운드가 뛰어납니다.

적극적인 슈팅과 리바운드를 바탕으로 승리하는 팀이 여기에 해당하므로 '적극적인 리바운드형'이라고 명명했습니다.

세 번째 클러스터(초록)은 3점슛에 강점이 있는 팀입니다.

야투 시도 횟수와 득점률도 좋은 편이므로 '정확한 슈팅형'이라고 이름 붙였습니다.

HOU, GSW, POR, DAL는 각각 어느 클러스터에 가까운 지 살펴보겠습니다.

휴스턴 로키츠는 '정확한 슈팅형'에 가깝네요.

특히 3점슛 득점률이 압도적으로 높습니다.

추가적으로 파울과 FTM(자유투득점)도 높은 걸 보니 '강한 수비형'의 성향도 보입니다.

휴스턴 로키츠는 79.3% 승률로 해당 정규시즌 우승을 차지했습니다.

이번엔 GSW(골든 스테이트 워리어스)를 보겠습니다.

GSW 역시 '정확한 슈팅형'에 가깝습니다.

3점슛 득점 능력과 야투 득점을 바탕으로 정규 시즌 2위를 차지하였습니다.

😢약팀 특징 파악하기

이번엔 약팀을 보도록 하겠습니다.

포틀란드의 경우 정육면체에 가까운 모양이네요.

3점슛이 특화되지도, 그렇다고 파울과 자유투를 바탕으로 한 수비 성향도 약합니다.

적극적인 리바운드와 야투시도횟수도 떨어지는 편입니다.

그나마 가깝다면 적극적인 리바운드 형에 가깝습니다.

따라서 리바운드와 야투 시도횟수, 야투 득점률을 올리는 것이 승리에 도움이 될 것으로 보입니다.

혹은 파울을 통한 자유투 득점을 바탕으로 수비형 전술을 강화하는 방법도 있을 것 같습니다.

달라스의 경우 '정확한 슈팅형'에 가깝습니다.

3점슛과 FGM이 다른 능력에 비해 뛰어난 편이나 강팀에 비하면 그 정도가 약합니다.

추가적인 득점률을 올릴 필요가 있어 보입니다.

다른 능력보다는 3PM과 FGM에 집중하면 승률이 상승할 것으로 기대됩니다.

 

이상으로 2017-2018 NBA 정규 시즌 데이터를 바탕으로 클러스터링 및 시각화를 진행해 보았습니다. 🙂

데이터 분석을 할 때마다 느끼는 거지만, 해당 분야에 대한 도메인 지식이 필수적인 것 같습니다.

저는 농구를 즐겨 보지 않아 분석 후, 결과를 해석하는 데 어려움이 있었습니다. 😢

데이터 분석을 직업으로 삼는다면, 특정 분야를 정해서 커리어를 쌓는 것이 효율적일 것 같습니다. 😀