文章目录
- 一、项目任务
- 二、代码实现及分析
- 1. 导入模块
- 2. 导入文件并对文件信息进行整体探测
- 3. 数据预处理
- 3.1 查看数据集信息
- 3.2 数据清洗与转换
- 3.3 数据去重
- 4. 数据可视化
- 4.1 数据相关性
- 4.2 球员数据分析
- 5. 基于逻辑回归的球员分类
- 5.1 数据重定义
- 5.2 划分数据集与验证集
- 5.3 定义模型
- 6. 基于随机森林回归模型的特征评分排序
一、项目任务
- 数据集共有342个NBA球员样本,包含38个特征,即342行×38列。对这些数据进行集成和预处理。
- 利用python语言,设计合适的机器学习算法。找出球员在场时对球队比赛获胜的贡献大小,最能反映球员的综合实力的特征。
- 算法过程及结果的设计合适的可视化图像,将所设计的算法的过程,以及最终结果展示出来。
二、代码实现及分析
1. 导入模块
import pandas as pd
import numpy as np
import plotly.express as px
import matplotlib.pyplot as plt
import seaborn as snsfrom sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error
from sklearn import metrics
from sklearn.ensemble import RandomForestRegressorplt.rcParams['font.sans-serif'] = ['Microsoft YaHei']
plt.rcParams['axes.unicode_minus'] = False
2. 导入文件并对文件信息进行整体探测
df = pd.read_csv("nba_2017_nba_players_with_salary.csv")
df.head()
df.describe()
查看关键字:
df.columns
专业名词字段含义说明:
- Rk:排名
- PLAYER:姓名
- POSITION:位置
- AGE:年龄
- MP:平均每场比赛进行的时间
- FG:场均投球命中次数
- FGA:场均投射次数
- FG%:命中率
- 3P:三分球命中次数
- 3PA:三分球投射次数
- 3P%:三分球命中率(命中次数/投射次数----3P/3PA=3P%)
- 2P:二分球命中次数
- 2PA:二分球投射次数
- 2P%:二分球命中率
- eFG%:有效命中率
- FT:罚球命中次数
- FTA:罚球投射次数
- FT%:罚球命中率(FT/FTA=FT%)
- ORB:进攻篮板数
- DRB:防守篮板数
- TRB:篮板球总数
篮板率=球员篮板数×(球队所有球员上场时间÷5)÷球员上场时间÷(球队总篮板+对手总篮板) - AST:助攻
助攻率=球员助攻数÷(球员上场时间÷(球队所有球员上场时间÷5)×(球队总进球数-球员进球数) - STL:抢断
抢断率=球员抢断数×(球队所有球员上场时间÷5)÷球员上场时间÷对手进攻次数 - BLK:盖帽
盖帽率=球员盖帽数×(球队所有球员上场时间÷5)÷球员上场时间÷对手两分球出手次数) - TOV:失误
失误率=球员失误数÷(球员两分球出手次数+0.44×球员罚球次数+球员失误数) - PF:犯规次数
- POINTS:得分
- TEAM:球队
- GP:比赛场数
- MPG:场均上场时间
- ORPM:进攻正负值
- DRPM:防守正负值
- RPM:正负值
- WINS_RPM:赢球正负值
- PIE:球员贡献度
加分项:得分、投篮命中数、罚篮命中数、篮板、助攻、抢断、盖帽
减分项:投篮出手、罚篮出手、个人犯规、失误 - PACE:每48分钟内大概会进行多少个回合
- W:胜利次数
- SALARY_MILLIONS:薪水
3. 数据预处理
3.1 查看数据集信息
df.info()
3.2 数据清洗与转换
为了便于理解,对列名称重命名
df.columns=['排名', '姓名', '位置', '年龄', '场均比赛时间', '场均投球命中数', '场均投射次数', '命中率', '三分球命中次数','三分球投射次数', '三分球命中率', '二分球命中次数', '二分球投射次数', '二分球命中率', '有效命中率', '罚球命中次数','罚球投射次数', '罚球命中率', '进攻篮板数','防守篮板数', '篮板球总数', '助攻', '抢断', '盖帽', '失误', '犯规次数','得分', '球队', '比赛场数','场均上场时间', '进攻正负值', '防守正负值', '正负值', '赢球正负值', '球员贡献度', '48分钟回合数', '胜利次数','薪水']
df.head()
df.isnull().sum()
由df.isnull().sum()结果可知,缺失值‘三分球命中率’有22项,‘罚球命中率’有5项,下面显示缺失值的所在行
三分球命中率_null =df[df["三分球命中率"].isnull()==True]
罚球命中率_null =df[df["罚球命中率"].isnull()==True]
- 3P%:三分球命中率——3P/3PA=3P%
- FT%:罚球命中率——FT/FTA=FT%
由上方数据显示,分析可得,3P%和FT%的数值空缺原因均是因为3P、3PA、FT和FTA数值为0导致,
为数据精准度,使用dropna()直接将所有含空缺值的数据行删除
df = df.dropna()
3.3 数据去重
根据数据探测可知,数据集中有多为球员姓名重复,删除重复项并保留第一次出现的项
df[df.duplicated(subset=['姓名']).values == True]
df=df.drop_duplicates(subset=['姓名'], keep='first', inplace=False)
根据所查资料知,效率值最能反应球员对比赛做出的贡献
- PER:效率值
效率值=[(得分+篮板球总数+助攻+抢断+盖帽)-(场均投射次数-场均投球命中次数)-(罚球投射次数-罚球命中次数)-失误)]/比赛场数
df['效率值']=((df['得分']+df['篮板球总数']+df['助攻']+df['抢断']+df['盖帽'])-(df['场均投射次数']-df['场均投球命中数'])-(df['罚球投射次数']-df['罚球命中次数'])-df['失误'])/df['比赛场数']
PER_array = np.array(df['效率值'])
PER_array
df = df.round(3) #保留3位小数
4. 数据可视化
4.1 数据相关性
找出判断球员贡献度相关的数据,得到其中的数据相关性,并用相关系数矩阵显示,并使用热力图进行可视化
df_cor = df.loc[:, [ '命中率', '三分球命中率', '二分球命中率', '有效命中率','罚球命中率', '篮板球总数', '助攻', '抢断', '盖帽', '失误', '犯规次数','得分', '比赛场数','场均上场时间', '赢球正负值', '球员贡献度','防守正负值', '胜利次数','薪水']]#调用corr()方法 获取两列数据之间的相关性
# 返回改数据类型的相关系数矩阵(即每两个类型直接的相关性)
corr = df_cor.corr()
corr.head()
使用热力图呈现:
plt.figure(figsize=(20,8),dpi=100)
sns.heatmap(corr,square=True,linewidths=0.1,annot=True,cmap='Accent')
4.2 球员数据分析
# 按照球员贡献度排名
df.loc[:, ["姓名", "球员贡献度","薪水", "年龄","比赛场数"]].sort_values(by="球员贡献度", ascending=False).head()
# 按照场均上场时间排名
df.loc[:, ["姓名", "球员贡献度","薪水", "年龄","场均上场时间"]].sort_values(by="场均上场时间", ascending=False).head()
位置 = pd.DataFrame(df[ "位置" ].value_counts()).reset_index()
位置名词解释:
- PG:控卫
- SG:分卫
- PF:大前
- SF:小前
- C:中锋
fig=px.pie(位置,names="index" ,values="位置")
fig.show ()
查看各个站位的球员薪水分布:
price = (df.groupby("位置")["薪水"].mean().reset_index().sort_values( "薪水").reset_index(drop=True))
fig =px.bar_polar(price,theta="位置",color='薪水',color_discrete_sequence=px.colors.sequential.Plasma_r,template='plotly_white')
fig.show()
fig = px.scatter(df,x='球员贡献度',y="排名",color='球员贡献度')
fig.show()
小结: 球员贡献度越高排名越高
查看排名和薪水的关系:
fig = px.scatter(df,x='排名',y="薪水",color='排名')
fig.show()
小结: 排名越低薪水越低
#用pairplot() 方法 进行数据对比
sns.pairplot(df,vars=['排名','球员贡献度','比赛场数','命中率','得分'], diag_kind="kde")
5. 基于逻辑回归的球员分类
5.1 数据重定义
根据数据可视化结果分析可知,球员贡献度是最能反映球员的综合实力的特征。
由df.describe()得到的数据,人为划分球员:
- 球员贡献度 <= 7.2 标记为0,记作表现不合格
- 球员贡献度 <= 9.31标记为1,记作表现合格
- 球员贡献度 <= 15 标记为2,记作表现良好
- 球员贡献度 <= 23 标记为3,记作表现优秀
自定义方法进行划分并为方便后续进行分类,将此项转化为一维数组
def 球员贡献度_cut(df):if df.球员贡献度 <= 7.2:return 0 #不合格elif df.球员贡献度 <=9.31:return 1 # 合格elif df.球员贡献度 <=15:return 2 # 良好else:return 3 # 优秀df['球员贡献度_cut']=df.apply(lambda x:球员贡献度_cut(x),axis=1)
print(df['球员贡献度_cut'])
Pie1_array = np.array(df['球员贡献度_cut'])
Pie1_array
5.2 划分数据集与验证集
df_new = df.drop(columns=["姓名", "位置","球队"]) # 去除非数值型数据
X_train,X_test,Y_train,Y_test=train_test_split(df_new,Pie1_array,test_size=0.2,random_state=180)
5.3 定义模型
# 定义模型
def basic_logosticregression(X_train,X_test,Y_train,Y_test):model=LogisticRegression(random_state=0, solver='lbfgs')model.fit(X_train,Y_train)Y_train_pre=model.predict(X_train)Y_test_pre=model.predict(X_test)train_predict_proba = model.predict_proba(X_train)test_predict_proba = model.predict_proba(X_test)confusion_matrix_result = metrics.confusion_matrix(Y_test_pre,Y_test)print('混淆矩阵结果:\n',confusion_matrix_result)plt.figure(figsize=(8, 6))sns.heatmap(confusion_matrix_result, annot=True, cmap='Blues')plt.xlabel('预测的标签')plt.ylabel('实际的标签')print("score_train: "+str(model.score(X_train, Y_train)))print("score_test: "+str(model.score(X_test,Y_test)))
调用:
basic_logosticregression(X_train,X_test,Y_train,Y_test)
6. 基于随机森林回归模型的特征评分排序
查看各个特征对球员贡献度的相关度,找出除了球员贡献度的其他影响因素
Pie_array = np.array(df['球员贡献度'])
df_new = df.drop(columns=["姓名", "位置","球队",'球员贡献度'])
data=df_new.values.tolist()X = data
Y = Pie_array
feature_names=['排名', '年龄', '场均比赛时间', '场均投球命中数', '场均投射次数', '命中率','三分球命中次数','三分球投射次数', '三分球命中率', '二分球命中次数', '二分球投射次数', '二分球命中率', '有效命中率','罚球命中次数','罚球投射次数', '罚球命中率', '进攻篮板数','防守篮板数', '篮板球总数', '助攻','抢断', '盖帽','失误', '犯规次数','得分', '比赛场数','场均上场时间','进攻正负值', '防守正负值','正负值', '赢球正负值', '48分钟回合数','胜利次数','薪水']names = feature_namesrf = RandomForestRegressor()
rf.fit(X, Y)
print("特征评分排序:")
print(sorted(zip(map(lambda x: round(x, 4), rf.feature_importances_), names),reverse=True))