日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

秀,用NBA球员数据学透K-Means聚类

發布時間:2024/9/15 91 豆豆
生活随笔 收集整理的這篇文章主要介紹了 秀,用NBA球员数据学透K-Means聚类 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

這次我們用 NBA 球員賽季表現聚類來探討下 K-Means 算法,K-Means 是一個清晰明白的無監督學習方法,和 KNN 有很多相似點,例如都有超參數 K,前者是 K 個類別,后者是 K 個鄰居。

聚類算法是不需要標簽的,直接從數據的內在性之中學習最優的分類結果,或者說確定離散標簽類型。K-Means 聚類算法是其中最簡單、最容易理解的。

簡單即高效。我們的目標是學習一個東西,然后把它的思想應用到我們想要探索的場景,以加深對算法的理解。

最優的聚類結果需要滿足兩個假設:

  • “簇中心點”(cluster center)是屬于該簇的所有的數據點坐標的算術平均值

  • 一個簇的每個點到該簇中心點的距離,比到其他簇中心點的距離短

  • 于是 K-Means 聚類的工作流為

  • 隨機猜測一些簇中心點

  • 將樣本分配至離其最近的簇中心點上去

  • 將簇中心點設置為所有點坐標的平均值

  • 重復 2 和 3 直至收斂

  • 我們會編碼實現 K-Means 算法,并用于 NBA 控衛 2020-21 常規賽季的表現分析中。

    我們知道過去剛剛結束的這個賽季得分王是萌神庫里,我愛他。我們這里只關注控衛,一是因為控衛線上星光熠熠,二是數據分析要細分,這本身是一個原則。

    我們開始吧!

    01

    學習原理方法

    找到數據

    我們可以從https://www.basketball-reference.com找到我們想要的數據,那就是NBA球員在過去一個賽季的統計數據。數據獲取流程如下

    看看數據

    #?三劍客來一遍 import?pandas?as?pd import?numpy?as?np import?matplotlib.pyplot?as?pltnba?=?pd.read_csv("nba_2020.csv") nba.head()

    我們發現姓名列有個\,后面跟著不知道是什么的簡稱,可以處理掉。另外字段名全是簡寫,我一個球迷有很多都看不懂,尷尬。整理了下字段含義,我們看一遍,這樣就大概了解了這個數據集有什么了。

    • Age:年齡(別告訴我你知不知道)

    • TM(team):球隊

    • Lg(league):聯盟

    • Pos(position):位置

    • PG(Point Guard):組織后衛

    • GS(Games Started):首發出場次數

    • MP(Minutes Played Per Game):場均上場時間

    • FG(Field Goals Per Game):場均命中數

    • FGA(Field Goal Attempts Per Game):場均投籃數

    • FG%(Field Goal Percentage):命中率

    • 3P(3-Point Field Goals Per Game):三分球命中率

    • 3PA (3-Point Field Goal Attempts Per Game):場均三分球投籃數

    • 3P% (3-Point Field Goal Percentage):三分球命中率

    • 2P (2-Point Field Goals Per Game):兩分球命中數

    • 2PA (2-Point Field Goal Attempts Per Game):場均兩分投籃數

    • 2P% (2-Point Field Goal Percentage):兩分球命中率

    • eFG% (Effective Field Goal Percentage):有效命中率

    • FT (Free Throws Per Game):場均罰球命中數

    • FTA (Free Throw Attempts Per Game):場均罰球數

    • FT% (Free Throw Percentage):罰球命中率

    • ORB (Offensive Rebounds Per Game):場均進攻籃板數

    • DRB (Defensive Rebounds Per Game):場均防守籃板數

    • TRB (Total Rebounds Per Game):總籃板數

    • AST (Assists Per Game):場均助攻

    • STL (Steals Per Game):場均搶斷

    • BLK (Blocks Per Game):場均蓋帽

    • TOV (Turnovers Per Game):場均失誤

    • PF (Personal Fouls Per Game):場均個人犯規

    • PTS (Points Per Game):場均得分

    處理數據

    #?球員名字取\前面的字符 nba['Player']?=?nba['Player'].apply(lambda?x:?x.split('\\')[0]) #?取控衛PG的樣本進行分析 point_guards?=?nba[nba['Pos']?==?'PG'] #?剔除0失誤的控衛數據,0tov意味著場次太少,且0不能被除 point_guards?=?point_guards[point_guards['TOV']?!=?0] #?定義ATR為助攻失誤比,并計算出來 point_guards['ATR']?=?point_guards['AST']?/?point_guards['TOV']

    處理后的數據變成了下面的樣子,我們剩下了 124 個控衛數據。

    判斷一個控衛優不優秀,最重要的兩個指標是場均得分和場均助攻失誤比,也就是PTS和ATR。下面我們就用這兩個關鍵特征對球員聚類。

    探索數據

    看下這些球員的場次得分與助攻失誤比散點圖,這往往是數據分析和建模的第一步。

    #?改善下繪圖風格 import?seaborn?as?sns sns.set()# nba聯盟控衛場次得分與助攻失誤比散點圖 plt.scatter(point_guards['PTS'],?point_guards['ATR'],?c='y') plt.title("Point?Guards") plt.xlabel('Points?Per?Game',?fontsize=13) plt.ylabel('Assist?Turnover?Ratio',?fontsize=13) plt.show()

    最右邊得分超過 30 的你不用猜,就是這個男人。

    確認下數據,場均得分大于 25 的過濾出來看下,果然是庫里,東契奇、歐文、利拉德等人赫然在列。這些超巨得分是高,但看起來助攻失誤比差不多都在平均線上下。這是合理的。其實有點干的越多錯的越多的意思,工作上亦是如此。

    看了下助攻失誤比超高或超低的,我都不認識就不說了。

    我們聚類吧

    從散點圖來看,其實并沒有明顯的簇,但我們可以人為定義任意個簇。我們還是分成 5 類。于是我們開始做聚類的第一步。

    STEP1:隨機認定 5 個樣本點作為簇的中心點

    num_clusters?=?5 #?從樣本里隨機選5個出來作為5個簇的起始中心點 random_initial_points?=?np.random.choice(point_guards.index,?size=num_clusters) centroids?=?point_guards.loc[random_initial_points] #?畫出散點圖,包括5個隨機選取的聚類中心點 plt.scatter(point_guards['PTS'],?point_guards['ATR'],?c='y') plt.scatter(centroids['PTS'],?centroids['ATR'],?c='red') plt.title("Centroids") plt.xlabel('Points?Per?Game',?fontsize=13) plt.ylabel('Assist?Turnover?Ratio',?fontsize=13) plt.show()

    隨后就是不斷迭代優化簇中心點的過程,為了方便,我們將中心點的坐標存在一個字典里。

    def?centroids_to_dict(centroids):dictionary?=?dict()#?iterating?counter?we?use?to?generate?a?cluster_idcounter?=?0#?iterate?a?pandas?data?frame?row-wise?using?.iterrows()for?index,?row?in?centroids.iterrows():coordinates?=?[row['PTS'],?row['ATR']]dictionary[counter]?=?coordinatescounter?+=?1return?dictionarycentroids_dict?=?centroids_to_dict(centroids)

    上圖我們看到,隨機選出來的centroids,我們把它存在了一個centroids_dict里面。

    STEP2:將樣本分配至離其最近的簇中心點上去

    這里涉及兩個計算,一個是距離的度量,一個是最小元素的查找。前者我們采用歐拉距離,后者是選擇排序的精髓。

    先定義好這兩個計算函數,如下。

    import?mathdef?calculate_distance(centroid,?player_values):root_distance?=?0for?x?in?range(0,?len(centroid)):difference?=?centroid[x]?-?player_values[x]squared_difference?=?difference**2root_distance?+=?squared_differenceeuclid_distance?=?math.sqrt(root_distance)return?euclid_distancedef?assign_to_cluster(row):lowest_distance?=?-1closest_cluster?=?-1for?cluster_id,?centroid?in?centroids_dict.items():df_row?=?[row['PTS'],?row['ATR']]euclidean_distance?=?calculate_distance(centroid,?df_row)if?lowest_distance?==?-1:lowest_distance?=?euclidean_distanceclosest_cluster?=?cluster_idelif?euclidean_distance?<?lowest_distance:lowest_distance?=?euclidean_distanceclosest_cluster?=?cluster_idreturn?closest_cluster

    執行這兩個函數,我們就完成了 STEP2,我們可視化看下完成后的結果。

    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['PTS'],?clustered_df['ATR'],?c=colors[n-1])plt.xlabel('Points?Per?Game',?fontsize=13)plt.ylabel('Assist?Turnover?Ratio',?fontsize=13)plt.show()visualize_clusters(point_guards,?5)

    以上,5 個類別分別以不同的顏色標識出來了,但顯然這是隨機簇的結果,劃分的 5 類結果并沒有太好。我們還需要 STEP3。

    STEP3:將簇中心點設置為所有點坐標的平均值

    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?clusternew_centroid?=?[np.average(values_in_cluster['PTS']),?np.average(values_in_cluster['ATR'])]new_centroids_dict[cluster_id]?=?new_centroidreturn?new_centroids_dict

    STEP4:重復 2 和 3

    #?多次迭代,試試100輪吧 for?_?in?range(0,100):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)

    最終的結果如上,我們看到效果已經得到了很好的優化。高得分的在一個簇,高助攻失誤比的在一個簇。

    以上,我們寫了很多代碼。

    手寫算法是為了學習和理解。工程上,我們要充分利用工具和資源。

    sklearn 庫就包含了我們常用的機器學習算法實現,可以直接用來建模。

    from?sklearn.cluster?import?KMeanskmeans?=?KMeans(n_clusters=num_clusters) kmeans.fit(point_guards[['PTS',?'ATR']]) point_guards['cluster']?=?kmeans.labels_visualize_clusters(point_guards,?num_clusters)

    短短五行代碼就完成了我們從零開始寫的百來行代碼,效果看起來也很合理。值得說明的是,聚類受起始點的影響,可能不會達到全局最優結果。細心的朋友一定看出來了,上面兩個最終聚類結果是有差異的。


    02

    風控中的應用

    如果學習了一項技能,但是不知道怎么用,那就毫無意義。

    想想風控中聚類可以用來干什么呢?風控中我們有什么數據,關注什么結果呢?

    一個有意思的課題是,用戶手機安裝的 app 能不能區分用戶的風險。答案顯然是肯定的,

    除了必要的社交、支付、生活和工具類 app 外,那些差異化的 app 偏好顯然刻畫不同類型的用戶。安裝了很多小貸平臺的用戶,就很可能是一個多頭客戶,在想著辦法擼口子。

    于是我們可以用 app 的安裝情況來給用戶聚類,假設采集了用戶在 100 個 app 的安裝情況,就可以對這 100 個 0、1 變量聚類。

    聚成兩類后,我們可以采用其中有標簽的用戶進行驗證,如果好壞用戶絕大部分都正確地被劃分開了,那么有理由相信那些沒有標簽的用戶大概率就等于簇的標簽。

    我沒有對應的數據可以舉例,但有類似的數據來說明問題。下面是美國國會的數據,party 代表了議員的黨派,R 是共和黨 Republican,D 是民主黨 Democratic,I 是中間黨派。其余數據均為 0、1 變量。這里的 party 就類似風控中的好壞用戶。

    import?pandas?as?pd votes?=?pd.read_csv("114_congress.csv") votes.head()

    于是我們開始無監督聚類。注意以下并未用到 party 這個標簽。

    #?用k-means?clustering方法 from?sklearn.cluster?import?KMeanskmeans_model?=?KMeans(n_clusters=2,?random_state=1) senator_distances?=?kmeans_model.fit_transform(votes.iloc[:,?3:])labels?=?kmeans_model.labels_

    我們需要用標簽去對聚類結果做驗證。

    可以看到,分成了 0 和 1 兩個簇中,0 簇中 43 個議員有 41 個都是民主黨,2 是無黨派人士;1 簇中 57 個議員有 54 個都是共和黨,3 個是民主黨。數據總有異常,或者用戶總有一部分比較奇怪,我們不追求 100%準確。

    不完美才是人生的最完美。

    推薦閱讀

    Pandas處理數據太慢,來試試Polars吧!

    懶人必備!只需一行代碼,就能導入所有的Python庫

    絕!關于pip的15個使用小技巧

    介紹10個常用的Python內置函數,99.99%的人都在用!

    可能是全網最完整的 Python 操作 Excel庫總結!

    與50位技術專家面對面20年技術見證,附贈技術全景圖

    總結

    以上是生活随笔為你收集整理的秀,用NBA球员数据学透K-Means聚类的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。