查看原文
其他

NBA球员薪资分析——基于随机森林算法(二)

爬虫俱乐部 Stata and Python数据分析 2022-03-15

本文作者:宋   骁

文字编辑:钱梦璇

技术总编:张   邯

导读

上篇文章中我们将NBA球员的技术统计和薪资数据做了一些前期的清理和分析,现在我们就要使用机器学习模型进行薪资的预测了。但是在将数据放入算法之前,需要对数据进行进一步的特征工程处理。由于特征中有一些是类别变量,算法本身无法处理。这里需要自定义一个函数将类别变量处理成哑变量,并且默认将样本量最大的类别作为参照组。

def convert_dummy(df, feature,rank=0): ''' 将类别变量转换为哑变量 ''' pos = pd.get_dummies(df[feature], prefix = feature) mode = df[feature].value_counts().index[rank] biggest = feature + '_' + str(mode) pos.drop([biggest],axis = 1,inplace = True) df.drop([feature],axis = 1,inplace = True) df = df.join(pos) return df

变量转换


建模前需要进行变量标准化,同时对Y进行对数转换。

stats_salary0 = stats_salary.copy()stats_salary0.drop(['Player'],axis=1,inplace=True)Y = stats_salary0.iloc[:,10]X = stats_salary0.iloc[:,:10]X = convert_dummy(X,'Pos')
画直方图和QQ图观测因变量分布:
from sklearn.preprocessing import RobustScalerdef robust_transfer(df): Scaler = RobustScaler().fit(df) newdf = Scaler.transform(df) df0 = pd.DataFrame(newdf,columns = df.columns)    return df0X = robust_transfer(X)
from scipy.stats import normfrom scipy import statssns.distplot(Y, fit=norm);fig = plt.figure()res = stats.probplot(Y, plot=plt)Y = np.log1p(Y) # 对数转换

从因变量的直方图(为了便于比较,黑色为正态分布曲线,蓝色为密度估计曲线)中可以看出,球员薪资呈现右偏的特征,也就是说,大部分球员拿着较低的薪资,而只有一少部分球员能够拿到非常高的薪水(也就是所谓的“顶薪”)。但这种分布对于统计模型是不友好的,正态分布的因变量能够提升预测准确性。
QQ图是一种检验变量是否来自某种理论分布的方法。如果变量完全符合正态分布,所有蓝色数据点应当落在图中红色对角线上。但是从图中可以看出,薪资数据显然偏离了正态分布的理论分布直线,因此我们对数据进行对数转换:
sns.distplot(Y , fit=norm);fig = plt.figure()res = stats.probplot(Y, plot=plt)
对数据进行对数转换后,数据更加趋于正态分布,QQ图中散点更趋近于对角线。


建模 —交叉验证


k交叉验证是一种防止模型过拟合的方法,将数据集划分成k个相同大小的子样本,每次取出其中1份作为验证集,另k-1份作为训练集。这里,我们对数据人工划分训练集和测试集,并在训练集上进行10折交叉验证。

评价回归问题的度量指标通常为误差均方根(RMSE, root mean square error)与判定系数:


RMSE值越小,越大,说明回归结果越准确。我们使用随机森林模型进行回归,并使用以上两个指标进行评估。

from sklearn.model_selection import train_test_splitx_train, x_test, y_train, y_test = train_test_split(X, Y, test_size = 0.3) from sklearn.ensemble import RandomForestRegressorfrom sklearn.metrics import r2_scorefrom sklearn.model_selection import cross_val_score#model.fit(x_train, y_train)def print_r2(model,x,y,cv): # 模型, x, y, 交叉验证数 ''' 交叉验证分数打印 ''' cvscore = cross_val_score(model, x, y, cv = cv,scoring='r2')    print(cv,'折交叉验证R2为',round(cvscore.mean(),3))def print_rmse(model,x,y,cv): # 模型, x, y, 交叉验证数 ''' 交叉验证分数打印 ''' cvscore = cross_val_score(model, x, y, cv = cv, scoring = 'neg_mean_squared_error') nmse = cvscore.mean() rmse0 = np.sqrt(-nmse)    print(cv,'折交叉验证RMSE为',round(rmse0,3))rfr = RandomForestRegressor(n_estimators=100)print_r2(rfr,x_train, y_train,10)print_rmse(rfr,x_train, y_train,10)


同样,我们需要评估测试集的预测准确性。这里定义一个函数,用于输入模型和训练集测试集,并打印测试集的评估结果。

from sklearn.metrics import r2_scorefrom sklearn.metrics import mean_squared_error
def print_reg_metric(model,x_train,y_train,x_test,y_test,predict = False): ''' 打印测试集RMSE和R2 ''' rgf = model.fit(np.array(x_train),np.array(y_train)) ypred = rgf.predict(np.array(x_test)) rmse = np.sqrt(mean_squared_error(y_test, ypred)) r2 = r2_score(y_test, ypred) print('测试集R2为%.3f, 测试集RMSE为%.3f'%(r2,rmse)) if predict: name = stats_salary.iloc[x_test.index,0] example = pd.DataFrame({'姓名': name,'真实薪资':np.expm1(y_test), '预测薪资':np.expm1(ypred)}) return example.head(10)
print_reg_metric(rfr, x_train,y_train,x_test,y_test,predict = True)

总体来说,测试集的预测没有训练集内部的交叉验证效果好。这是正常现象,二者相差不大说明学习器没有过拟合数据。
注意,由于之前对因变量进行了对数转换,薪资绝对值预测需要使用指数转换。当我们自定义的print_reg_metric函数的predict参数设为True时,函数可以自动将变量转换为薪资的绝对值并打印测试集球员的薪资预测值。上方展示的著名球员包括达米安·利拉德,2017-2018赛季真实年薪2600万美元,算法预测值为2400万左右;克莱·汤普森真实年薪约1800万左右,而预测值为1700万,二者非常接近。


建模 —变量重要性统计


下面比较对薪资贡献较大的统计指标

dtree = rfr.fit(x_train, y_train)values = sorted(zip(x_train.columns, rfr.feature_importances_), key = lambda x: x[1] * -1)imp = pd.DataFrame(values,columns = ["Name", "Score"])imp.sort_values(by = 'Score',inplace = True)sns.scatterplot(x='Score',y='Name',linewidth=0, data=imp,s = 30, color='red').set( xlabel='Importance', ylabel='Variables')

随机森林算法的结果显示,平均出场时间和场均得分对薪资的影响最为重要,年龄排在第三位。对薪资影响最不重要的是球员所在的位置,如前锋、中锋、后卫等等,至此我们的数据分析就结束了。
本文细致地处理了NBA球员的球队更换问题,同时构建了一系列场均统计变量。在对数据进行统计变换后,使用经典的集成学习方法随机森林进行建模和预测,最后进行了变量影响的机制性解释。




对我们的推文累计打赏超过1000元,我们即可给您开具发票,发票类别为“咨询费”。用心做事,不负您的支持!
往期推文推荐

NBA球员薪资分析——基于随机森林算法(一)

高亮输出之唐诗作者

湖北省各市疫情数据爬取

古代诗人总去的这些地方你一定要知道!

DataFrame数组常用方法(二)

ftools命令——畅游大数据时代的加速器

卫健委的“糊涂账”

Pandas中数据的排序与切片

DataFrame数组常用方法

巧用局部宏扩展函数dir

过了14天潜伏期真的没事了?

Pandas基本数据类型介绍

NumPy数组基本介绍

“个性化”sortobs命令,教你实现排序自由

携手战疫,我们在行动

恭贺新春,平安顺遂|各省疫情关注度地图

过年观影指南(二)

过年观影指南(一)

关于我们



微信公众号“Stata and Python数据分析”分享实用的stata、python等软件的数据处理知识,欢迎转载、打赏。我们是由李春涛教授领导下的研究生及本科生组成的大数据处理和分析团队。

此外,欢迎大家踊跃投稿,介绍一些关于stata和python的数据处理和分析技巧。
投稿邮箱:statatraining@163.com
投稿要求:
1)必须原创,禁止抄袭;
2)必须准确,详细,有例子,有截图;
注意事项:
1)所有投稿都会经过本公众号运营团队成员的审核,审核通过才可录用,一经录用,会在该推文里为作者署名,并有赏金分成。
2)邮件请注明投稿,邮件名称为“投稿+推文名称”。
3)应广大读者要求,现开通有偿问答服务,如果大家遇到有关数据处理、分析等问题,可以在公众号中提出,只需支付少量赏金,我们会在后期的推文里给予解答。

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存