日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

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

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

這次我們用 NBA 球員賽季表現(xiàn)聚類來探討下 K-Means 算法,K-Means 是一個清晰明白的無監(jiān)督學(xué)習(xí)方法,和 KNN 有很多相似點(diǎn),例如都有超參數(shù) K,前者是 K 個類別,后者是 K 個鄰居。

聚類算法是不需要標(biāo)簽的,直接從數(shù)據(jù)的內(nèi)在性之中學(xué)習(xí)最優(yōu)的分類結(jié)果,或者說確定離散標(biāo)簽類型。K-Means 聚類算法是其中最簡單、最容易理解的。

簡單即高效。我們的目標(biāo)是學(xué)習(xí)一個東西,然后把它的思想應(yīng)用到我們想要探索的場景,以加深對算法的理解。

最優(yōu)的聚類結(jié)果需要滿足兩個假設(shè):

  • “簇中心點(diǎn)”(cluster center)是屬于該簇的所有的數(shù)據(jù)點(diǎn)坐標(biāo)的算術(shù)平均值

  • 一個簇的每個點(diǎn)到該簇中心點(diǎn)的距離,比到其他簇中心點(diǎn)的距離短

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

  • 隨機(jī)猜測一些簇中心點(diǎn)

  • 將樣本分配至離其最近的簇中心點(diǎn)上去

  • 將簇中心點(diǎn)設(shè)置為所有點(diǎn)坐標(biāo)的平均值

  • 重復(fù) 2 和 3 直至收斂

  • 我們會編碼實(shí)現(xiàn) K-Means 算法,并用于 NBA 控衛(wèi) 2020-21 常規(guī)賽季的表現(xiàn)分析中。

    我們知道過去剛剛結(jié)束的這個賽季得分王是萌神庫里,我愛他。我們這里只關(guān)注控衛(wèi),一是因?yàn)榭匦l(wèi)線上星光熠熠,二是數(shù)據(jù)分析要細(xì)分,這本身是一個原則。

    我們開始吧!

    01

    學(xué)習(xí)原理方法

    找到數(shù)據(jù)

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

    看看數(shù)據(jù)

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

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

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

    • TM(team):球隊(duì)

    • Lg(league):聯(lián)盟

    • Pos(position):位置

    • PG(Point Guard):組織后衛(wèi)

    • GS(Games Started):首發(fā)出場次數(shù)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    • ORB (Offensive Rebounds Per Game):場均進(jìn)攻籃板數(shù)

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

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

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

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

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

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

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

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

    處理數(shù)據(jù)

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

    處理后的數(shù)據(jù)變成了下面的樣子,我們剩下了 124 個控衛(wèi)數(shù)據(jù)。

    判斷一個控衛(wèi)優(yōu)不優(yōu)秀,最重要的兩個指標(biāo)是場均得分和場均助攻失誤比,也就是PTS和ATR。下面我們就用這兩個關(guān)鍵特征對球員聚類。

    探索數(shù)據(jù)

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

    #?改善下繪圖風(fēng)格 import?seaborn?as?sns sns.set()# nba聯(lián)盟控衛(wèi)場次得分與助攻失誤比散點(diǎn)圖 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 的你不用猜,就是這個男人。

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

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

    我們聚類吧

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

    STEP1:隨機(jī)認(rèn)定 5 個樣本點(diǎn)作為簇的中心點(diǎn)

    num_clusters?=?5 #?從樣本里隨機(jī)選5個出來作為5個簇的起始中心點(diǎn) random_initial_points?=?np.random.choice(point_guards.index,?size=num_clusters) centroids?=?point_guards.loc[random_initial_points] #?畫出散點(diǎn)圖,包括5個隨機(jī)選取的聚類中心點(diǎn) 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()

    隨后就是不斷迭代優(yōu)化簇中心點(diǎn)的過程,為了方便,我們將中心點(diǎn)的坐標(biāo)存在一個字典里。

    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)

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

    STEP2:將樣本分配至離其最近的簇中心點(diǎn)上去

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

    先定義好這兩個計(jì)算函數(shù),如下。

    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

    執(zhí)行這兩個函數(shù),我們就完成了 STEP2,我們可視化看下完成后的結(jié)果。

    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 個類別分別以不同的顏色標(biāo)識出來了,但顯然這是隨機(jī)簇的結(jié)果,劃分的 5 類結(jié)果并沒有太好。我們還需要 STEP3。

    STEP3:將簇中心點(diǎn)設(shè)置為所有點(diǎn)坐標(biāo)的平均值

    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:重復(fù) 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)

    最終的結(jié)果如上,我們看到效果已經(jīng)得到了很好的優(yōu)化。高得分的在一個簇,高助攻失誤比的在一個簇。

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

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

    sklearn 庫就包含了我們常用的機(jī)器學(xué)習(xí)算法實(shí)現(xiàn),可以直接用來建模。

    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)

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


    02

    風(fēng)控中的應(yīng)用

    如果學(xué)習(xí)了一項(xiàng)技能,但是不知道怎么用,那就毫無意義。

    想想風(fēng)控中聚類可以用來干什么呢?風(fēng)控中我們有什么數(shù)據(jù),關(guān)注什么結(jié)果呢?

    一個有意思的課題是,用戶手機(jī)安裝的 app 能不能區(qū)分用戶的風(fēng)險。答案顯然是肯定的,

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

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

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

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

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

    于是我們開始無監(jiān)督聚類。注意以下并未用到 party 這個標(biāo)簽。

    #?用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_

    我們需要用標(biāo)簽去對聚類結(jié)果做驗(yàn)證。

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

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

    推薦閱讀

    Pandas處理數(shù)據(jù)太慢,來試試Polars吧!

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

    絕!關(guān)于pip的15個使用小技巧

    介紹10個常用的Python內(nèi)置函數(shù),99.99%的人都在用!

    可能是全網(wǎng)最完整的 Python 操作 Excel庫總結(jié)!

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

    總結(jié)

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

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。