当前位置:首页 > 球星经典时刻

【机器学习--实战篇】足球运动员身价估计---XGBoost

admin 2025-08-22 22:58:27 9177

完整代码 练习入口 补充一个画图工具 xgboost与lightgbm比较, 我也要测一次 据说stacking得分会更高 https://blog.csdn.net/zhouwenyuan1015/article/details/77372863 首先说下总的mae:19.7 但是gridSearch的best_csore_并不高,是个负数,这一点我还没搞懂,希望网友帮解惑。 我敢提交是因为测试结果mae是20.XXX,觉得结果还不错。

-------------------------------------------------------------分割线-------------------------------------------------------

首先看下所有的特征介绍

特征解释类型id行编号没有实际意义club该球员所属的俱乐部该信息已经被编码league该球员所在的联赛已被编码birth_date生日格式为月/日/年height_cm身高(厘米)数值变量weight_kg体重(公斤)数值变量nationality国籍已被编码potential球员的潜力数值变量pac球员速度数值变量sho射门(能力值)数值变量pas传球(能力值)数值变量dri带球(能力值)数值变量def防守(能力值)数值变量phy身体对抗(能力值)数值变量international_reputation国际知名度数值变量skill_moves技巧动作数值变量weak_foot非惯用脚的能力值数值变量work_rate_att球员进攻的倾向分类变量,Low,Medium,Highwork_rate_def球员防守的倾向分类变量,Low,Medium,Highpreferred_foot惯用脚1表示右脚、2表示左脚crossing传中(能力值)数值变量finishing完成射门(能力值)数值变量heading_accuracy头球精度(能力值)数值变量short_passing短传(能力值)数值变量volleys凌空球(能力值)数值变量dribbling盘带(能力值)数值变量curve弧线(能力值)数值变量free_kick_accuracy定位球精度(能力值)数值变量long_passing长传(能力值)数值变量ball_control控球(能力值)数值变量acceleration加速度(能力值)数值变量sprint_speed冲刺速度(能力值)数值变量agility灵活性(能力值)数值变量reactions反应(能力值)数值变量balance身体协调(能力值)数值变量shot_power射门力量(能力值)数值变量jumping弹跳(能力值)数值变量stamina体能(能力值)数值变量strength力量(能力值)数值变量long_shots远射(能力值)数值变量aggression侵略性(能力值)数值变量interceptions拦截(能力值)数值变量positioning位置感(能力值)数值变量vision视野(能力值)数值变量penalties罚点球(能力值)数值变量marking卡位(能力值)数值变量standing_tackle断球(能力值)数值变量sliding_tackle铲球(能力值)数值变量gk_diving门将扑救(能力值)数值变量gk_handling门将控球(能力值)数值变量gk_kicking门将开球(能力值)数值变量gk_positioning门将位置感(能力值)数值变量gk_reflexes门将反应(能力值)数值变量rw球员在右边锋位置的能力值数值变量rb球员在右后卫位置的能力值数值变量st球员在射手位置的能力值数值变量lw球员在左边锋位置的能力值数值变量cf球员在锋线位置的能力值数值变量cam球员在前腰位置的能力值数值变量cm球员在中场位置的能力值数值变量cdm球员在后腰位置的能力值数值变量cb球员在中后卫的能力值数值变量lb球员在左后卫置的能力值数值变量gk球员在守门员的能力值数值变量y该球员的市场价值(单位为万欧元)这是要被预测的数值

1、预处理

函数功能full_birthDate原表中的年份数据是2位,比如格式是这样的,09/10/89,因为计算年龄,所以补为完整的09/10/1989trans把csv中的非数值字符换为数值judgecsv中有一些数据是空的,需要去除空数据

def full_birthDate(x):

if(x[-2:] == '00'):

return x[:-2]+'20'+x[-2:]

else:

return x[:-2]+'19'+x[-2:]

def trans(x):

if(x == 'Medium'):

return 1

elif(x == 'High'):

return 2

else:

return 0

def judge(x):

if(x > 0):

return 1

else:

return 0

2、读取数据,并新增初步的特征

增加的特征有:age、BMI、is_gk 这部分是看网站的标杆做的,自己本身没研究更多的特征工程

# 读取数据

def getData():

train = pd.read_csv('./data/train.csv')

test = pd.read_csv('./data/test.csv')

train['birth_date_'] = train['birth_date'].apply(lambda x: full_birthDate(x))

test['birth_date_'] = test['birth_date'].apply(lambda x: full_birthDate(x))

train['birth_date'] = pd.to_datetime(train['birth_date_'])

train['age'] = ((pd.Timestamp.now() - train['birth_date']).apply(lambda x: x.days) / 365).apply(lambda t: int(t))

test['birth_date'] = pd.to_datetime(test['birth_date_'],format='%m/%d/%Y', errors='coerce')

test['age'] = ((pd.Timestamp.now() - test['birth_date']).apply(lambda x: x.days) / 365).apply(lambda t: int(t))

train['work_rate_att_'] = train['work_rate_att'].apply(lambda x: trans(x)).apply(lambda t: int(t))

train['work_rate_def_'] = train['work_rate_def'].apply(lambda x: trans(x)).apply(lambda t: int(t))

test['work_rate_att_'] = test['work_rate_att'].apply(lambda x: trans(x)).apply(lambda t: int(t))

test['work_rate_def_'] = test['work_rate_def'].apply(lambda x: trans(x)).apply(lambda t: int(t))

train = train.drop('id',axis=1)

train = train.drop('birth_date',axis=1)

train = train.drop('birth_date_',axis=1)

train = train.drop('work_rate_att',axis=1)

train = train.drop('work_rate_def',axis=1)

test = test.drop('id',axis=1)

test = test.drop('birth_date',axis=1)

test = test.drop('birth_date_',axis=1)

test = test.drop('work_rate_att',axis=1)

test = test.drop('work_rate_def',axis=1)

return train,test

3、数据分析

新增一个特征:best_pos(最佳位置)是通过对[‘rw’, ‘rb’, ‘st’, ‘lw’, ‘cf’, ‘cam’, ‘cm’, ‘cdm’, ‘cb’, ‘lb’, ‘gk’]这11个特征的汇总。

特征解释类型rw球员在右边锋位置的能力值数值变量rb球员在右后卫位置的能力值数值变量st球员在射手位置的能力值数值变量lw球员在左边锋位置的能力值数值变量cf球员在锋线位置的能力值数值变量cam球员在前腰位置的能力值数值变量cm球员在中场位置的能力值数值变量cdm球员在后腰位置的能力值数值变量cb球员在中后卫的能力值数值变量lb球员在左后卫置的能力值数值变量gk球员在守门员的能力值数值变量

盒图是用来观测离群点的,目前还没用到,等下一步用到在更新…

def data_ana(train, test):

# 获得球员最擅长位置上的评分

positions = ['rw', 'rb', 'st', 'lw', 'cf', 'cam', 'cm', 'cdm', 'cb', 'lb', 'gk']

train['best_pos'] = train[positions].max(axis=1)

test['best_pos'] = test[positions].max(axis=1)

# 计算球员的身体质量指数(BMI)

train['BMI'] = 10000. * train['weight_kg'] / (train['height_cm'] ** 2)

test['BMI'] = 10000. * test['weight_kg'] / (test['height_cm'] ** 2)

# 判断一个球员是否是守门员

train['is_gk'] = train['gk'].apply(lambda x: judge(x))

test['is_gk'] = test['gk'].apply(lambda x: judge(x))

return train,test

def view_filter(train):

# 可视化盒图

# # 统计输出信息

percentile_result = np.percentile(train['y'], [25, 50, 75])

num = 0

for i in list(train['y']):

if(i > percentile_result[2] * 1.5):

num+=1

print(i)

# print('离群点个数:',num,'\n四分位数Q3:',percentile_result[2])

# print(num/len(list(train['y'])))

# 显示图例

plt.boxplot(x=train['y'],showmeans=True,meanline=True,whis=1.5)

plt.legend()

savefig('盒图.jpg')

# 显示图形

plt.show()

plt.close()

4、训练

4.1 特征选择

注意n_estimators一定初始化大一点,因为会自动在收敛的地方自己停 选择特征,顺便确定n_estimators

def xgboost_select_feature(data_, labels_,cols,target):# # 特征选择

xgb1 = XGBRegressor(learning_rate =0.1,max_depth=5,min_child_weight=1,n_estimators=1000,

gamma=0,subsample=0.8,colsample_bytree=0.8,objective= 'reg:logistic',

nthread=4,scale_pos_weight=1,seed=27)

feature_ = list(modelfit(xgb1, data_.values,labels_.values,cols,target)) # 特征选择

return feature_

def modelfit(alg, data, labels_, cols, target, useTrainCV=True, cv_folds=7, early_stopping_rounds=50):

# 可以返回n_estimates的最佳数目,为什么呢, 哪里返回?

if useTrainCV:

xgb_param = alg.get_xgb_params()

xgtrain = xgb.DMatrix(data, label=labels_)

cvresult = xgb.cv(xgb_param, xgtrain, num_boost_round=alg.get_params()['n_estimators'], nfold=cv_folds,

metrics='mae', early_stopping_rounds=early_stopping_rounds)

alg.set_params(n_estimators=cvresult.shape[0])

#Fit the algorithm on the data

seed = 20

# seed=20从0.97升为了0.98

# Model Report

# r2_score : 0.9845

# MAE: 0.4723899992310908 %

test_size = 0.3

x_train,x_test,y_train,y_test = train_test_split(data, labels_, test_size=test_size,random_state=seed)

print(x_train.shape[1],y_train.shape[1])

eval_set = [(x_test,y_test)]

alg.fit(x_train, y_train, early_stopping_rounds=early_stopping_rounds, eval_metric='mae',eval_set=eval_set,verbose=True)

#Predict training set:

dtrain_predictions = alg.predict(x_test)

# print(type(dtrain_predictions),type(labels_))

y_true = list(y_test)

y_pred = list(dtrain_predictions)

print(type(y_pred),type(y_true))

#Print model report:

print("\nModel Report")

print("r2_score : %.4g" % metrics.r2_score(y_true, y_pred))

mae_y = 0.00

for i in range(len(y_true)):

mae_y += np.abs(np.float(y_true[i])-y_pred[i])

print("MAE: ", (mae_y*4799+6)/len(y_true))

# Model Report

# r2_score : 0.9673

# MAE: 0.636517748270864 %

feat_imp = pd.Series(alg.get_booster().get_fscore()).sort_values(ascending=False)

# feat_imp.plot(kind='bar', title='Feature Importances')

# plt.ylabel('Feature Importance Score')

fig, ax = plt.subplots(1, 1, figsize=(8, 13))

plot_importance(alg, max_num_features=25, height=0.5, ax=ax)

plt.show()

# 重要性筛选

feat_sel = list(feat_imp.index)

feat_val = list(feat_imp.values)

featur = []

for i in range(len(feat_sel)):

featur.append([cols[int(feat_sel[i][1:])],feat_val[i]])

print('所有特征的score:\n',featur)

feat_sel2 = list(feat_imp[feat_imp.values > target].index)

featur2 = []

for i in range(len(feat_sel2)):

featur2.append(cols[int(feat_sel2[i][1:])])

return featur2

def MAE_(xgb1,train_x,train_y):

y_pre = list(xgb1.predict(train_x))

train_y = train_y.as_matrix()

num = 0

for i in range(len(y_pre)):

num += np.abs(y_pre[i] - train_y[i])

print((num*4799+6)/len(y_pre))

4.2训练

根据上一步获得特征排序,选择前11个作为训练的特征,选择好特征,就可以进行训练了。

def xgboost_train(train_x, train_y):

# # 半手动调参-------------------是个过程------调参成功需要注释掉---------------------------------------------------

# param_test1 = {

# 'max_depth':range(22,27)

# }

# gsearch1 = GridSearchCV(estimator = XGBRegressor(learning_rate=0.1, n_estimators=366, min_child_weight=1,subsample=0.85,colsample_bytree=0.8,

# gamma=0,objective= 'reg:logistic', nthread=4, seed=27),

# param_grid = param_test1,scoring='neg_median_absolute_error',n_jobs=4, iid=False, cv=5)

#gsearch1.fit(train_x,train_y)

# print(gsearch1.best_params_,gsearch1.best_score_)

# 半手动调参---结果太差了-----------------------------------------------------------------------------------------

# 20个特征,mae=19

# {'max_depth': 19} -0.000962098801735801

# {'max_depth': 20} -0.0009953797204438424

# {'max_depth': 24} -0.0009504750202941337

# 15个特征

# {'max_depth': 25} -0.0010135409208229943

# 24个特征

# {'max_depth': 18} -0.0009839476411412358

# 22个特征 结果不如19,mae=20

# {'max_depth': 23} -0.0009574992929236896

# 虽然是负数,最后的mae还是可以的19

train_x = train_x.as_matrix()

xgb1 = XGBRegressor(learning_rate=0.1, n_estimators=366, max_depth=23, min_child_weight=1,subsample=0.8,colsample_bytree=0.8,

gamma=0,objective= 'reg:logistic', nthread=4, scale_pos_weight=1, seed=27)

xgb1.fit(train_x,train_y)

MAE_(xgb1,train_x,train_y)

return xgb1