NBA控衛聚類——K-Means詳解

來源:互聯網
上載者:User

標籤:

Dataset

在NBA的媒體報道,體育記者通常集中在少數幾個球員。由於我們的資料科學的帽子,我們不禁感到一陣懷疑為什麼這個球員與其他球員不一樣。那麼就使用資料科學進一步探索該這個問題。 本文的資料集nba_2013.csv是2013 - 2014賽季的NBA球員的表現。

  • player – name of the player(名字)
  • pos – the position of the player(位置)
  • g – number of games the player was in(參賽場數)
  • pts – total points the player scored(總得分)
  • fg. – field goal percentage(投籃命中率)
  • ft. – free throw percentage(罰球命中率)
import pandas as pdimport numpy as npnba = pd.read_csv("nba_2013.csv")nba.head(3)‘‘‘         player pos  age bref_team_id   g  gs    mp   fg  fga    fg.  \0    Quincy Acy  SF   23          TOT  63   0   847   66  141  0.468   1  Steven Adams   C   20          OKC  81  20  1197   93  185  0.503   2   Jeff Adrien  PF   27          TOT  53  12   961  143  275  0.520         ...      drb  trb  ast  stl  blk  tov   pf  pts     season  season_end  0     ...      144  216   28   23   26   30  122  171  2013-2014        2013  1     ...      190  332   43   40   57   71  203  265  2013-2014        2013  2     ...      204  306   38   24   36   39  108  362  2013-2014        2013  [3 rows x 31 columns]‘‘‘
Point Guards

控球後衛(Point Guards)往往是全隊進攻的召集人,並通過對球的控制來決定在恰當的時間傳球給適合的球員,是球場上拿球機會最多的人。他要把球從後場安全地帶到前場,再把球傳給其他隊友,這才有讓其他人得分的機會。 一個合格的控球後衛必須要能夠在只有一個人防守他的情況下,毫無問題地將球帶過半場。然後,他還要有很好的傳球能力,能夠在大多數的時間裡,將球傳到球應該要到的地方:有時候是一個可以投籃的空檔,有時候是一個更好的導球位置。

  • 先提取出所有控衛的球員資訊:
point_guards = nba[nba[‘pos‘] == ‘PG‘]
Points Per Game
  • 由於我們的資料集給出的是球員的總得分(pts)以及參賽場數(g),沒有直接給出每場球賽的平均得分(Points Per Game),但是可以根據前兩個值計算:
point_guards[‘ppg‘] = point_guards[‘pts‘] / point_guards[‘g‘]# Sanity check, make sure ppg = pts/gpoint_guards[[‘pts‘, ‘g‘, ‘ppg‘]].head(5)‘‘‘    pts   g        ppg24  930  71  13.09859229  150  20   7.50000030  660  79   8.35443038  666  72   9.25000050  378  55   6.872727‘‘‘
Assist Turnover Ratio

NBA中專門有一項資料統計叫assist/turnover,是用這個隊員助攻數比上他的失誤數,這項統計能準確的反映一個控衛是否稱職。

  • 助攻失誤比的計算公式如下,其中Assists表示總助攻(ast),Turnovers表示總失誤(tov)。

  • 計算之前要將那些失誤率為0的球員去掉,一是因為他可能參賽數很少,分析他沒有意義,而來作為除數不能為0.
point_guards = point_guards[point_guards[‘tov‘] != 0]point_guards[‘atr‘] = point_guards[‘ast‘] / point_guards[‘tov‘]
Visualizing The Point Guards
  • 可視化控衛的資訊,X軸表示的是個平均每場球賽的得分,Y軸是助攻失誤比。
plt.scatter(point_guards[‘ppg‘], point_guards[‘atr‘], c=‘y‘)plt.title("Point Guards")plt.xlabel(‘Points Per Game‘, fontsize=13)plt.ylabel(‘Assist Turnover Ratio‘, fontsize=13)

Clustering Players
  • 粗略看一下上面的圖,大約有五簇比較集中。可以利用聚類技術將相同的控衛聚集在一組。KMeans是比較常用的聚類演算法,是基於質心的聚類(簇是一個圓圈,質心是這個簇的平均向量)。將K設定為5.在美國議員黨派——K均值聚類
    這篇文章中我們也用到KMeans這個演算法,當時我們是直接調用sklearn中的包(from sklearn.cluster import KMeans),然後直接計算。但是在本文,我們想要研究KMeans的具體步驟,因此一步步迭代。
kmeans_model = KMeans(n_clusters=2, random_state=1)senator_distances = kmeans_model.fit_transform(votes.iloc[:, 3:])
Step 1
  • 首先隨機產生5個中心點:
num_clusters = 5# Use numpy‘s random function to generate a list, length: num_clusters, of indicesrandom_initial_points = np.random.choice(point_guards.index, size=num_clusters)# Use the random indices to create the centroidscentroids = point_guards.ix[random_initial_points]
  • 可視化初始聚類中心,其中中心點用紅色標識,其他的點用黃色標識:
plt.scatter(point_guards[‘ppg‘], point_guards[‘atr‘], c=‘yellow‘)plt.scatter(centroids[‘ppg‘], centroids[‘atr‘], c=‘red‘)plt.title("Centroids")plt.xlabel(‘Points Per Game‘, fontsize=13)plt.ylabel(‘Assist Turnover Ratio‘, fontsize=13)

  • 然後將中心點轉化為一個字典格式,字典的鍵是這個簇的名稱,字典的值是這個中心點的資訊(”ppg”,”atr”)。
def centroids_to_dict(centroids):    dictionary = dict()    # iterating counter we use to generate a cluster_id    counter = 0    # iterate a pandas data frame row-wise using .iterrows()    for index, row in centroids.iterrows():        coordinates = [row[‘ppg‘], row[‘atr‘]] #list對象        dictionary[counter] = coordinates        counter += 1    return dictionarycentroids_dict = centroids_to_dict(centroids)
  • 再然後就是計算每個點到聚類中心的距離然後將每個點的聚類中心修改為離其最近的那個簇。
import math# 計算兩個點距離的函數def calculate_distance(centroid, player_values): # 參數都是list對象    root_distance = 0        for x in range(0, len(centroid)):        difference = centroid[x] - player_values[x]        squared_difference = difference**2        root_distance += squared_difference    euclid_distance = math.sqrt(root_distance)    return euclid_distance# 返回離每個點最近的簇的鍵def assign_to_cluster(row):    lowest_distance = -1    closest_cluster = -1      for cluster_id, centroid in centroids_dict.items():        df_row = [row[‘ppg‘], row[‘atr‘]]        euclidean_distance = calculate_distance(centroid, df_row)        if lowest_distance == -1:            lowest_distance = euclidean_distance            closest_cluster = cluster_id         elif euclidean_distance < lowest_distance:            lowest_distance = euclidean_distance            closest_cluster = cluster_id    return closest_cluster# 產生一個新的屬性:儲存每個節點的簇號point_guards[‘cluster‘] = point_guards.apply(lambda row: assign_to_cluster(row), axis=1)
  • 可視化第一次迭代的聚類圖,將不同的簇用不同的顏色表示出來:
def visualize_clusters(df, num_clusters):    colors = [‘b‘, ‘g‘, ‘r‘, ‘c‘, ‘m‘, ‘y‘, ‘k‘]    for n in range(num_clusters):        clustered_df = df[df[‘cluster‘] == n]        plt.scatter(clustered_df[‘ppg‘], clustered_df[‘atr‘], c=colors[n-1])        plt.xlabel(‘Points Per Game‘, fontsize=13)        plt.ylabel(‘Assist Turnover Ratio‘, fontsize=13)visualize_clusters(point_guards, 5)

Step 2
  • 將所有節點聚集後,開始重新計算每個簇的質點:
def recalculate_centroids(df):    new_centroids_dict = dict()    for cluster_id in range(0, num_clusters):        values_in_cluster = df[df[‘cluster‘] == cluster_id]        # Calculate new centroid using mean of values in the cluster        new_centroid = [np.average(values_in_cluster[‘ppg‘]), np.average(values_in_cluster[‘atr‘])]        new_centroids_dict[cluster_id] = new_centroid    return new_centroids_dictcentroids_dict = recalculate_centroids(point_guards)
Repeat Step 1
  • 然後重複第一步中的,將所有節點重新分給離其最近的那個簇中(跟1相差不大):
point_guards[‘cluster‘] = point_guards.apply(lambda row: assign_to_cluster(row), axis=1)visualize_clusters(point_guards, num_clusters)

Repeat Step 2 And Step 1
centroids_dict = recalculate_centroids(point_guards)point_guards[‘cluster‘] = point_guards.apply(lambda row: assign_to_cluster(row), axis=1)visualize_clusters(point_guards, num_clusters)

Challenges Of K-Means

觀察前幾次迭代,每次節點改變都不是很大,主要是因為:

  • K-Means演算法在迭代的過程中,對於每個簇不會引起很大的變化,因此這個演算法總是收斂的並且很穩定。
  • 由於K-Means演算法迭代得很保守,因此最終結果與選取的初始質點有很大關係。

為瞭解決這些問題,sklearn包中的K-Means實現中做了一些智能的功能,比如重複聚類,每次隨機選取質心,這比只採用一次質心選取所帶來的偏差要少很多。

from sklearn.cluster import KMeanskmeans = KMeans(n_clusters=num_clusters)kmeans.fit(point_guards[[‘ppg‘, ‘atr‘]])point_guards[‘cluster‘] = kmeans.labels_visualize_clusters(point_guards, num_clusters)

NBA控衛聚類——K-Means詳解

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.