足球是世界上最火爆的運動之一,世界盃期間也每每是球迷們最亢奮的時刻。比賽狂歡季除了炸出了熬夜看球的鐵桿粉絲,也讓足球競猜也成了你們茶餘飯後最熱衷的話題。甚至連原來不怎麼看足球的人,也是暗中努力惡補了不少足球相關知識,想經過賽事競猜先賺一個小目標。今天咱們將介紹如何用機器學習來預測足球比賽結果!php
本 Chat 採用 Python 編程語言,使用 人工智能建模平臺 Mo 做爲在線開發環境進行編程,經過獲取 2000 年到 2018 年共 19 年英超的比賽數據,而後基於監督學習中邏輯迴歸模型、支持向量機模型和 XGBoost 模型,對英超比賽結果進行預測。html
下面咱們一塊兒來看看預測英超比賽結果的機器學習步驟:前端
首先咱們進入 Mo 工做臺,建立一個空白項目,點擊 開始開發 進入內嵌 JupyterLab 的 Notebook 開發環境。python
接着咱們須要在項目中上傳數據集。算法
英超每一年舉辦一個賽季,在每一年的 8 月到第二年的 5 月進行,共有 20 支球隊,實行主客場雙循環賽制,每一個賽季共 38 輪比賽(其中 19 場主場比賽,19 場客場比賽),每輪比賽共計 10 場比賽,因此每一個賽季,英超共有 380 場比賽。apache
若是您已經在 MO 平臺新建項目,能夠在平臺直接導入數據集,流程以下:編程
讀取 csv 數據通常採用 pandas.read_csv():
pandas.read_csv(filepath_or_buffer, sep =',' , delimiter = None)api
# 導入必須的包 import warnings warnings.filterwarnings('ignore') # 防止警告文件的包 import pandas as pd # 數據分析包 import os import matplotlib.pyplot as plt # 可視化包 import matplotlib %matplotlib inline import seaborn as sns # 可視化包 from time import time from sklearn.preprocessing import scale # 標準化操做 from sklearn.model_selection import train_test_split # 將數據集分紅測試集和訓練集 from sklearn.metrics import f1_score # F1得分 import xgboost as xgb # XGBoost模型 from sklearn.svm import SVC ## 支持向量機分類模型 from sklearn.linear_model import LogisticRegression # 邏輯迴歸模型 from sklearn.model_selection import GridSearchCV # 超參數調參模塊 from sklearn.metrics import make_scorer # 模型評估 import joblib # 模型的保存與加載模塊
下面開始咱們的表演:數組
# 獲取地址中的全部文件 loc = './/football//' # 存放數據的路徑 res_name = [] # 存放數據名的列表 filecsv_list = [] # 獲取數據名後存放的列表 def file_name(file_name): # root:當前目錄路徑 dirs:當前目錄下全部子目錄 files:當前路徑下全部非目錄文件 for root,dirs,files in os.walk(file_name): files.sort() # 排序,讓列表裏面的元素有順序 for i,file in enumerate(files): if os.path.splitext(file)[1] == '.csv': filecsv_list.append(file) res_name.append('raw_data_'+str(i+1)) print(res_name) print(filecsv_list) file_name(loc)
['raw_data_1', 'raw_data_2', 'raw_data_3', 'raw_data_4', 'raw_data_5', 'raw_data_6', 'raw_data_7', 'raw_data_8', 'raw_data_9', 'raw_data_10', 'raw_data_11', 'raw_data_12', 'raw_data_13', 'raw_data_14', 'raw_data_15', 'raw_data_16', 'raw_data_17', 'raw_data_18', 'raw_data_19'] ['2000-01.csv', '2001-02.csv', '2002-03.csv', '2003-04.csv', '2004-05.csv', '2005-06.csv', '2006-07.csv', '2007-08.csv', '2008-09.csv', '2009-10.csv', '2010-11.csv', '2011-12.csv', '2012-13.csv', '2013-14.csv', '2014-15.csv', '2015-16.csv', '2016-17.csv', '2017-18.csv', '2018-19.csv']
獲取每年的數據後,將每年的年份放入到 time_list 列表中:app
time_list = [filecsv_list[i][0:4] for i in range(len(filecsv_list))] time_list
['2000','2001','2002','2003','2004','2005','2006','2007','2008','2009','2010','2011','2012','2013','2014','2015','2016','2017','2018']
讀取時將數據與 res_name 中的元素名一一對應。
for i in range(len(res_name)): res_name[i] = pd.read_csv(loc+filecsv_list[i],error_bad_lines=False) print('第%2s個文件是%s,數據大小爲%s'%(i+1,filecsv_list[i],res_name[i].shape))
第 1個文件是2000-01.csv,數據大小爲(380, 45) 第 2個文件是2001-02.csv,數據大小爲(380, 48) 第 3個文件是2002-03.csv,數據大小爲(316, 48) 第 4個文件是2003-04.csv,數據大小爲(335, 57) 第 5個文件是2004-05.csv,數據大小爲(335, 57) 第 6個文件是2005-06.csv,數據大小爲(380, 68) 第 7個文件是2006-07.csv,數據大小爲(380, 68) 第 8個文件是2007-08.csv,數據大小爲(380, 71) 第 9個文件是2008-09.csv,數據大小爲(380, 71) 第10個文件是2009-10.csv,數據大小爲(380, 71) 第11個文件是2010-11.csv,數據大小爲(380, 71) 第12個文件是2011-12.csv,數據大小爲(380, 71) 第13個文件是2012-13.csv,數據大小爲(380, 74) 第14個文件是2013-14.csv,數據大小爲(380, 68) 第15個文件是2014-15.csv,數據大小爲(381, 68) 第16個文件是2015-16.csv,數據大小爲(380, 65) 第17個文件是2016-17.csv,數據大小爲(380, 65) 第18個文件是2017-18.csv,數據大小爲(380, 65) 第19個文件是2018-19.csv,數據大小爲(304, 62)
通過查看第 15 個文件讀取的第 381 行爲空值,故採起刪除行空值操做。
Pandas.dropna(axis=0,how='any')
res_name[14] = res_name[14].dropna(axis=0,how='all') res_name[14].tail()
Div | Date | HomeTeam | AwayTeam | FTHG | FTAG | FTR | HTHG | HTAG | HTR | ... | BbAv<2.5 | BbAH | BbAHh | BbMxAHH | BbAvAHH | BbMxAHA | BbAvAHA | PSCH | PSCD | PSCA | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
375 | E0 | 24/05/15 | Hull | Man United | 0.0 | 0.0 | D | 0.0 | 0.0 | D | ... | 1.99 | 25.0 | 0.50 | 1.76 | 1.71 | 2.27 | 2.19 | 3.20 | 3.76 | 2.27 |
376 | E0 | 24/05/15 | Leicester | QPR | 5.0 | 1.0 | H | 2.0 | 0.0 | H | ... | 2.41 | 28.0 | -1.00 | 1.98 | 1.93 | 1.98 | 1.93 | 1.53 | 4.94 | 6.13 |
377 | E0 | 24/05/15 | Man City | Southampton | 2.0 | 0.0 | H | 1.0 | 0.0 | H | ... | 2.66 | 28.0 | -1.00 | 2.00 | 1.94 | 2.03 | 1.93 | 1.60 | 4.35 | 6.00 |
378 | E0 | 24/05/15 | Newcastle | West Ham | 2.0 | 0.0 | H | 0.0 | 0.0 | D | ... | 2.25 | 25.0 | -0.50 | 1.82 | 1.78 | 2.20 | 2.10 | 1.76 | 4.01 | 4.98 |
379 | E0 | 24/05/15 | Stoke | Liverpool | 6.0 | 1.0 | H | 5.0 | 0.0 | H | ... | 1.99 | 25.0 | 0.25 | 2.07 | 2.02 | 1.88 | 1.85 | 3.56 | 3.60 | 2.17 |
5 rows × 68 columns
考慮到英超通常是 19 個球隊,每一個球隊須要打 20 場球,故把行數不是 380 的數據刪除掉,並找到器原 CSV 文件一一對應。
for i in range(len(res_name),0,-1): # 採用從大到小的遍歷方式,而後進行刪除不知足條件的。 if res_name[i-1].shape[0] != 380: key = 'res_name[' + str(i) + ']' print('刪除的數據是:%s年的數據,文件名:%s大小是:%s'%(time_list[i-1],key,res_name[i-1].shape)) res_name.pop(i-1) time_list.pop(i-1) continue
刪除的數據是:2018年的數據,文件名:res_name[19]大小是:(304, 62) 刪除的數據是:2004年的數據,文件名:res_name[5]大小是:(335, 57) 刪除的數據是:2003年的數據,文件名:res_name[4]大小是:(335, 57) 刪除的數據是:2002年的數據,文件名:res_name[3]大小是:(316, 48)
文件名.head(n)
讀取數據前五行操做:
res_name[0].head()
Div | Date | HomeTeam | AwayTeam | FTHG | FTAG | FTR | HTHG | HTAG | HTR | ... | IWA | LBH | LBD | LBA | SBH | SBD | SBA | WHH | WHD | WHA | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | E0 | 19/08/00 | Charlton | Man City | 4 | 0 | H | 2 | 0 | H | ... | 2.7 | 2.20 | 3.25 | 2.75 | 2.20 | 3.25 | 2.88 | 2.10 | 3.2 | 3.10 |
1 | E0 | 19/08/00 | Chelsea | West Ham | 4 | 2 | H | 1 | 0 | H | ... | 4.2 | 1.50 | 3.40 | 6.00 | 1.50 | 3.60 | 6.00 | 1.44 | 3.6 | 6.50 |
2 | E0 | 19/08/00 | Coventry | Middlesbrough | 1 | 3 | A | 1 | 1 | D | ... | 2.7 | 2.25 | 3.20 | 2.75 | 2.30 | 3.20 | 2.75 | 2.30 | 3.2 | 2.62 |
3 | E0 | 19/08/00 | Derby | Southampton | 2 | 2 | D | 1 | 2 | A | ... | 3.5 | 2.20 | 3.25 | 2.75 | 2.05 | 3.20 | 3.20 | 2.00 | 3.2 | 3.20 |
4 | E0 | 19/08/00 | Leeds | Everton | 2 | 0 | H | 2 | 0 | H | ... | 4.5 | 1.55 | 3.50 | 5.00 | 1.57 | 3.60 | 5.00 | 1.61 | 3.5 | 4.50 |
5 rows × 45 columns
讀取數據前10行:
res_name[0].head(10)
Div | Date | HomeTeam | AwayTeam | FTHG | FTAG | FTR | HTHG | HTAG | HTR | ... | IWA | LBH | LBD | LBA | SBH | SBD | SBA | WHH | WHD | WHA | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | E0 | 19/08/00 | Charlton | Man City | 4 | 0 | H | 2 | 0 | H | ... | 2.7 | 2.20 | 3.25 | 2.75 | 2.20 | 3.25 | 2.88 | 2.10 | 3.20 | 3.10 |
1 | E0 | 19/08/00 | Chelsea | West Ham | 4 | 2 | H | 1 | 0 | H | ... | 4.2 | 1.50 | 3.40 | 6.00 | 1.50 | 3.60 | 6.00 | 1.44 | 3.60 | 6.50 |
2 | E0 | 19/08/00 | Coventry | Middlesbrough | 1 | 3 | A | 1 | 1 | D | ... | 2.7 | 2.25 | 3.20 | 2.75 | 2.30 | 3.20 | 2.75 | 2.30 | 3.20 | 2.62 |
3 | E0 | 19/08/00 | Derby | Southampton | 2 | 2 | D | 1 | 2 | A | ... | 3.5 | 2.20 | 3.25 | 2.75 | 2.05 | 3.20 | 3.20 | 2.00 | 3.20 | 3.20 |
4 | E0 | 19/08/00 | Leeds | Everton | 2 | 0 | H | 2 | 0 | H | ... | 4.5 | 1.55 | 3.50 | 5.00 | 1.57 | 3.60 | 5.00 | 1.61 | 3.50 | 4.50 |
5 | E0 | 19/08/00 | Leicester | Aston Villa | 0 | 0 | D | 0 | 0 | D | ... | 2.5 | 2.35 | 3.20 | 2.60 | 2.25 | 3.25 | 2.75 | 2.40 | 3.25 | 2.50 |
6 | E0 | 19/08/00 | Liverpool | Bradford | 1 | 0 | H | 0 | 0 | D | ... | 8.0 | 1.35 | 4.00 | 8.00 | 1.36 | 4.00 | 8.00 | 1.33 | 4.00 | 8.00 |
7 | E0 | 19/08/00 | Sunderland | Arsenal | 1 | 0 | H | 0 | 0 | D | ... | 2.1 | 4.30 | 3.20 | 1.70 | 3.30 | 3.10 | 2.05 | 3.75 | 3.00 | 1.90 |
8 | E0 | 19/08/00 | Tottenham | Ipswich | 3 | 1 | H | 2 | 1 | H | ... | 4.7 | 1.45 | 3.60 | 6.50 | 1.50 | 3.50 | 6.50 | 1.44 | 3.60 | 6.50 |
9 | E0 | 20/08/00 | Man United | Newcastle | 2 | 0 | H | 1 | 0 | H | ... | 5.0 | 1.40 | 3.75 | 7.00 | 1.40 | 3.75 | 7.50 | 1.40 | 3.75 | 7.00 |
10 rows × 45 columns
讀取最後 5 行操做:
res_name[0].tail()
Div | Date | HomeTeam | AwayTeam | FTHG | FTAG | FTR | HTHG | HTAG | HTR | ... | IWA | LBH | LBD | LBA | SBH | SBD | SBA | WHH | WHD | WHA | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
375 | E0 | 19/05/01 | Man City | Chelsea | 1 | 2 | A | 1 | 1 | D | ... | 1.65 | 4.0 | 3.60 | 1.67 | 4.20 | 3.40 | 1.70 | 4.00 | 3.1 | 1.80 |
376 | E0 | 19/05/01 | Middlesbrough | West Ham | 2 | 1 | H | 2 | 1 | H | ... | 3.20 | 1.8 | 3.25 | 3.75 | 1.90 | 3.20 | 3.50 | 1.83 | 3.4 | 3.50 |
377 | E0 | 19/05/01 | Newcastle | Aston Villa | 3 | 0 | H | 2 | 0 | H | ... | 2.90 | 2.4 | 3.25 | 2.50 | 2.38 | 3.30 | 2.50 | 2.25 | 3.4 | 2.60 |
378 | E0 | 19/05/01 | Southampton | Arsenal | 3 | 2 | H | 0 | 1 | A | ... | 2.35 | 2.5 | 3.25 | 2.37 | 2.63 | 3.25 | 2.30 | 2.62 | 3.5 | 2.20 |
379 | E0 | 19/05/01 | Tottenham | Man United | 3 | 1 | H | 1 | 1 | D | ... | 2.10 | 2.6 | 3.20 | 2.37 | 2.60 | 3.25 | 2.35 | 2.62 | 3.3 | 2.25 |
5 rows × 45 columns
讀取最後 4 行操做:
res_name[0].tail(4)
Div | Date | HomeTeam | AwayTeam | FTHG | FTAG | FTR | HTHG | HTAG | HTR | ... | IWA | LBH | LBD | LBA | SBH | SBD | SBA | WHH | WHD | WHA | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
376 | E0 | 19/05/01 | Middlesbrough | West Ham | 2 | 1 | H | 2 | 1 | H | ... | 3.20 | 1.8 | 3.25 | 3.75 | 1.90 | 3.20 | 3.50 | 1.83 | 3.4 | 3.50 |
377 | E0 | 19/05/01 | Newcastle | Aston Villa | 3 | 0 | H | 2 | 0 | H | ... | 2.90 | 2.4 | 3.25 | 2.50 | 2.38 | 3.30 | 2.50 | 2.25 | 3.4 | 2.60 |
378 | E0 | 19/05/01 | Southampton | Arsenal | 3 | 2 | H | 0 | 1 | A | ... | 2.35 | 2.5 | 3.25 | 2.37 | 2.63 | 3.25 | 2.30 | 2.62 | 3.5 | 2.20 |
379 | E0 | 19/05/01 | Tottenham | Man United | 3 | 1 | H | 1 | 1 | D | ... | 2.10 | 2.6 | 3.20 | 2.37 | 2.60 | 3.25 | 2.35 | 2.62 | 3.3 | 2.25 |
4 rows × 45 columns
res_name[0]['HomeTeam'].unique()
array(['Charlton', 'Chelsea', 'Coventry', 'Derby', 'Leeds', 'Leicester', 'Liverpool', 'Sunderland', 'Tottenham', 'Man United', 'Arsenal', 'Bradford', 'Ipswich', 'Middlesbrough', 'Everton', 'Man City', 'Newcastle', 'Southampton', 'West Ham', 'Aston Villa'], dtype=object)
數據集行數已經固定,通常都是 380 行,而列數可能每一年統計指標有變化,不必定相等,並且咱們也比較關心列數表表頭。因爲比較小,能夠直接看數據集列數,這樣比較快,也能夠代碼實現,找到最大的列數,而後獲取列數的表頭進行通常性介紹解釋。
# 獲取列表頭最大的列數,而後獲取器參數 shape_list = [res_name[i].shape[1] for i in range(len(res_name))] for i in range(len(res_name)): if res_name[i].shape[1] == max(shape_list): print('%s年數據是有最大列數:%s,列元素表頭:\n %s'%(time_list[i],max(shape_list),res_name[i].columns))
2012年數據是有最大列數:74,列元素表頭: Index(['Div', 'Date', 'HomeTeam', 'AwayTeam', 'FTHG', 'FTAG', 'FTR', 'HTHG', 'HTAG', 'HTR', 'Referee', 'HS', 'AS', 'HST', 'AST', 'HF', 'AF', 'HC', 'AC', 'HY', 'AY', 'HR', 'AR', 'B365H', 'B365D', 'B365A', 'BWH', 'BWD', 'BWA', 'GBH', 'GBD', 'GBA', 'IWH', 'IWD', 'IWA', 'LBH', 'LBD', 'LBA', 'PSH', 'PSD', 'PSA', 'WHH', 'WHD', 'WHA', 'SJH', 'SJD', 'SJA', 'VCH', 'VCD', 'VCA', 'BSH', 'BSD', 'BSA', 'Bb1X2', 'BbMxH', 'BbAvH', 'BbMxD', 'BbAvD', 'BbMxA', 'BbAvA', 'BbOU', 'BbMx>2.5', 'BbAv>2.5', 'BbMx<2.5', 'BbAv<2.5', 'BbAH', 'BbAHh', 'BbMxAHH', 'BbAvAHH', 'BbMxAHA', 'BbAvAHA', 'PSCH', 'PSCD', 'PSCA'], dtype='object')
咱們看到數據包括 Date(比賽的時間),Hometeam(主場隊伍名),Awayteam(客場隊伍名),FTHG(主場球隊全場進球數),HTHG(主場球隊半場進球數),FTR(全場比賽結果)等等,更多關於數據集中特徵信息能夠參考數據集特徵說明文檔 。
咱們挑選 Hometeam,Awayteam,FTHG,FTAG,FTR 這五列數據,做爲咱們的原始的特徵數據,後面基於這些原始特徵,咱們再構造一些新的特徵。
# 將挑選的信息放在一個新的列表中 columns_req = ['HomeTeam','AwayTeam','FTHG','FTAG','FTR'] playing_statistics = [] # 創造處理後數據名存放處 playing_data = {} # 鍵值對存儲數據 for i in range(len(res_name)): playing_statistics.append('playing_statistics_'+str(i+1)) playing_statistics[i] = res_name[i][columns_req] print(time_list[i],'playing_statistics['+str(i)+']',playing_statistics[i].shape)
2000 playing_statistics[0] (380, 5) 2001 playing_statistics[1] (380, 5) 2005 playing_statistics[2] (380, 5) 2006 playing_statistics[3] (380, 5) 2007 playing_statistics[4] (380, 5) 2008 playing_statistics[5] (380, 5) 2009 playing_statistics[6] (380, 5) 2010 playing_statistics[7] (380, 5) 2011 playing_statistics[8] (380, 5) 2012 playing_statistics[9] (380, 5) 2013 playing_statistics[10] (380, 5) 2014 playing_statistics[11] (380, 5) 2015 playing_statistics[12] (380, 5) 2016 playing_statistics[13] (380, 5) 2017 playing_statistics[14] (380, 5)
咱們首先預測全部主場球隊全都勝利,而後預測全部的客場都會勝利,對結果進行對比分析:
def predictions_0(data): """ 當咱們統計全部主場球隊都贏,那麼咱們預測的結果是什麼 返回值是預測值和實際值 """ predictions = [] for _, game in data.iterrows(): if game['FTR']=='H': predictions.append(1) else: predictions.append(0) # 返回預測結果 return pd.Series(predictions) # 那咱們對19年所有主場球隊都贏的結果進行預測,獲取預測的準確率。 avg_acc_sum = 0 for i in range(len(playing_statistics)): predictions = predictions_0(playing_statistics[i]) acc=sum(predictions)/len(playing_statistics[i]) avg_acc_sum += acc print("%s年數據主場全勝預測的準確率是%s"%(time_list[i],acc)) print('共%s年的平均準確率是:%s'%(len(playing_statistics),avg_acc_sum/len(playing_statistics)))
2000年數據主場全勝預測的準確率是0.4842105263157895 2001年數據主場全勝預測的準確率是0.4342105263157895 2005年數據主場全勝預測的準確率是0.5052631578947369 2006年數據主場全勝預測的準確率是0.4789473684210526 2007年數據主場全勝預測的準確率是0.4631578947368421 2008年數據主場全勝預測的準確率是0.45526315789473687 2009年數據主場全勝預測的準確率是0.5078947368421053 2010年數據主場全勝預測的準確率是0.4710526315789474 2011年數據主場全勝預測的準確率是0.45 2012年數據主場全勝預測的準確率是0.4368421052631579 2013年數據主場全勝預測的準確率是0.4710526315789474 2014年數據主場全勝預測的準確率是0.45263157894736844 2015年數據主場全勝預測的準確率是0.4131578947368421 2016年數據主場全勝預測的準確率是0.4921052631578947 2017年數據主場全勝預測的準確率是0.45526315789473687 共15年的平均準確率是:0.46473684210526317
def predictions_1(data): """ 當咱們統計全部客場球隊都贏,那麼咱們預測的結果是什麼 返回值是預測值和實際值 """ predictions = [] for _, game in data.iterrows(): if game['FTR']=='A': predictions.append(1) else: predictions.append(0) # 返回預測結果 return pd.Series(predictions) # 那咱們對19年客場球隊都贏的結果進行預測,獲取預測的準確率。 for i in range(len(playing_statistics)): predictions = predictions_1(playing_statistics[i]) acc=sum(predictions)/len(playing_statistics[i]) print("%s年數據客場全勝預測的準確率是%s"%(time_list[i],acc))
2000年數據客場全勝預測的準確率是0.25 2001年數據客場全勝預測的準確率是0.3 2005年數據客場全勝預測的準確率是0.29210526315789476 2006年數據客場全勝預測的準確率是0.2631578947368421 2007年數據客場全勝預測的準確率是0.2736842105263158 2008年數據客場全勝預測的準確率是0.2894736842105263 2009年數據客場全勝預測的準確率是0.2394736842105263 2010年數據客場全勝預測的準確率是0.23684210526315788 2011年數據客場全勝預測的準確率是0.30526315789473685 2012年數據客場全勝預測的準確率是0.2789473684210526 2013年數據客場全勝預測的準確率是0.3236842105263158 2014年數據客場全勝預測的準確率是0.3026315789473684 2015年數據客場全勝預測的準確率是0.30526315789473685 2016年數據客場全勝預測的準確率是0.2868421052631579 2017年數據客場全勝預測的準確率是0.28421052631578947
綜上比較:咱們能夠看出主場勝利的機率相對於輸和平局來講,確實機率要大。
咱們知道 2005-06 年數據在 playing_statistics[2] 中:
def score(data): """ Arsenal做爲主場隊伍時,累計進球數 """ scores=[] for _,game in data.iterrows(): if game['HomeTeam']=='Arsenal': scores.append(game['FTHG']) return np.sum(scores) Arsenal_score=score(playing_statistics[2]) print("Arsenal做爲主場隊伍在2005年時,累計進球數:%s"%(Arsenal_score))
Arsenal 做爲主場隊伍在2005年時,累計進球數:48
先試試求 2005-06 全部比賽各個球隊累計進球數。
print(playing_statistics[5].groupby('HomeTeam').sum()['FTHG'])
HomeTeam Arsenal 31 Aston Villa 27 Blackburn 22 Bolton 21 Chelsea 33 Everton 31 Fulham 28 Hull 18 Liverpool 41 Man City 40 Man United 43 Middlesbrough 17 Newcastle 24 Portsmouth 26 Stoke 22 Sunderland 21 Tottenham 21 West Brom 26 West Ham 23 Wigan 17 Name: FTHG, dtype: int64
特徵工程指的是把原始數據轉變爲模型的訓練數據的過程,它的目的就是獲取更好的訓練數據特徵,獲得更好的訓練模型。特徵工程能使得模型的性能獲得提高,有時甚至在簡單的模型上也能取得不錯的效果。特徵工程在機器學習中佔有很是重要的做用,通常認爲括特徵構建、特徵提取、特徵選擇三大部分。
由於這個比賽是一年一個賽季,是有前後順序的,那咱們就能夠統計到截止到本場比賽以前,整個賽季內,主客場隊伍的淨勝球的數量。那麼對於每個賽季的每一週,都統計出每一個球隊到本週爲止累計的進球數和丟球數之差,也就是淨勝球的數量。
處理後的數據,咱們能夠經過看某一年的某幾條數據來體現,好比:05-06 年的後五條數據
def get_goals_diff(playing_stat): # 建立一個字典,每一個 team 的 name 做爲 key teams = {} for i in playing_stat.groupby('HomeTeam').mean().T.columns: teams[i] = [] # 對於每一場比賽 for i in range(len(playing_stat)): # 全場比賽,主場隊伍的進球數 HTGS = playing_stat.iloc[i]['FTHG'] # 全場比賽,客場隊伍的進球數 ATGS = playing_stat.iloc[i]['FTAG'] # 把主場隊伍的淨勝球數添加到 team 這個 字典中對應的主場隊伍下 teams[playing_stat.iloc[i].HomeTeam].append(HTGS-ATGS) # 把客場隊伍的淨勝球數添加到 team 這個 字典中對應的客場隊伍下 teams[playing_stat.iloc[i].AwayTeam].append(ATGS-HTGS) # 建立一個 GoalsDifference 的 dataframe # 行是 team 列是 matchweek, # 39解釋:19個球隊,每一個球隊分主場客場2次,共38個賽次,可是range取不到最後一個值,故38+1=39 GoalsDifference = pd.DataFrame(data=teams, index = [i for i in range(1,39)]).T GoalsDifference[0] = 0 # 累加每一個隊的周比賽的淨勝球數 for i in range(2,39): GoalsDifference[i] = GoalsDifference[i] + GoalsDifference[i-1] return GoalsDifference def get_gss(playing_stat): # 獲得淨勝球數統計 GD = get_goals_diff(playing_stat) j = 0 # 主客場的淨勝球數 HTGD = [] ATGD = [] # 整年一共380場比賽 for i in range(380): ht = playing_stat.iloc[i].HomeTeam at = playing_stat.iloc[i].AwayTeam HTGD.append(GD.loc[ht][j]) ATGD.append(GD.loc[at][j]) if ((i + 1)% 10) == 0: j = j + 1 # 把每一個隊的 HTGD ATGD 信息補充到 dataframe 中 playing_stat.loc[:,'HTGD'] = HTGD playing_stat.loc[:,'ATGD'] = ATGD return playing_stat for i in range(len(playing_statistics)): playing_statistics[i] = get_gss(playing_statistics[i]) #### 查看構造特徵後的05-06年的後五條數據 playing_statistics[2].tail()
HomeTeam | AwayTeam | FTHG | FTAG | FTR | HTGD | ATGD | |
---|---|---|---|---|---|---|---|
375 | Fulham | Middlesbrough | 1 | 0 | H | -11 | -9 |
376 | Man United | Charlton | 4 | 0 | H | 34 | -10 |
377 | Newcastle | Chelsea | 1 | 0 | H | 4 | 51 |
378 | Portsmouth | Liverpool | 1 | 3 | A | -23 | 30 |
379 | West Ham | Tottenham | 2 | 1 | H | -4 | 16 |
經過以上數據:咱們發現 376 行數據的特色, 截止到這一場比賽以前,本賽季主場曼聯隊的淨勝球數是 34 , 客場查爾頓隊的淨勝球數是 -10 。
統計整個賽季主客場隊伍截止到當前比賽周的累計得分。一場比賽勝利計 3 分, 平局計 1 分,輸了計 0 分。咱們根據本賽季本週以前的比賽結果來統計這個值。咱們繼續觀看 05-06 年的後五條數據:
# 把比賽結果轉換爲得分,贏得三分,平局得一分,輸不得分 def get_points(result): if result == 'W': return 3 elif result == 'D': return 1 else: return 0 def get_cuml_points(matchres): matchres_points = matchres.applymap(get_points) for i in range(2,39): matchres_points[i] = matchres_points[i] + matchres_points[i-1] matchres_points.insert(column =0, loc = 0, value = [0*i for i in range(20)]) return matchres_points def get_matchres(playing_stat): # 建立一個字典,每一個 team 的 name 做爲 key teams = {} for i in playing_stat.groupby('HomeTeam').mean().T.columns: teams[i] = [] # 把比賽結果分別記錄在主場隊伍和客場隊伍中 # H:表明 主場 贏 # A:表明 客場 贏 # D:表明 平局 for i in range(len(playing_stat)): if playing_stat.iloc[i].FTR == 'H': # 主場 贏,則主場記爲贏,客場記爲輸 teams[playing_stat.iloc[i].HomeTeam].append('W') teams[playing_stat.iloc[i].AwayTeam].append('L') elif playing_stat.iloc[i].FTR == 'A': # 客場 贏,則主場記爲輸,客場記爲贏 teams[playing_stat.iloc[i].AwayTeam].append('W') teams[playing_stat.iloc[i].HomeTeam].append('L') else: # 平局 teams[playing_stat.iloc[i].AwayTeam].append('D') teams[playing_stat.iloc[i].HomeTeam].append('D') return pd.DataFrame(data=teams, index = [i for i in range(1,39)]).T def get_agg_points(playing_stat): matchres = get_matchres(playing_stat) cum_pts = get_cuml_points(matchres) HTP = [] ATP = [] j = 0 for i in range(380): ht = playing_stat.iloc[i].HomeTeam at = playing_stat.iloc[i].AwayTeam HTP.append(cum_pts.loc[ht][j]) ATP.append(cum_pts.loc[at][j]) if ((i + 1)% 10) == 0: j = j + 1 # 主場累計得分 playing_stat.loc[:,'HTP'] = HTP # 客場累計得分 playing_stat.loc[:,'ATP'] = ATP return playing_stat for i in range(len(playing_statistics)): playing_statistics[i] = get_agg_points(playing_statistics[i]) #查看構造特徵後的05-06年的後五條數據 playing_statistics[2].tail()
HomeTeam | AwayTeam | FTHG | FTAG | FTR | HTGD | ATGD | HTP | ATP | |
---|---|---|---|---|---|---|---|---|---|
375 | Fulham | Middlesbrough | 1 | 0 | H | -11 | -9 | 45 | 45 |
376 | Man United | Charlton | 4 | 0 | H | 34 | -10 | 80 | 47 |
377 | Newcastle | Chelsea | 1 | 0 | H | 4 | 51 | 55 | 91 |
378 | Portsmouth | Liverpool | 1 | 3 | A | -23 | 30 | 38 | 79 |
379 | West Ham | Tottenham | 2 | 1 | H | -4 | 16 | 52 | 65 |
咱們處理獲得 HTP (本賽季主場球隊截止到本週的累計得分), ATP (本賽季客場球隊截止到本週的累計得分)。
咱們再看 376 行,截止到這一場比賽,本賽季,曼聯隊一共積了80分, 查爾頓隊積了 47 分。
前面咱們構造的特徵反映了一隻隊伍本賽季的歷史總表現,咱們看看隊伍在最近三場比賽的表現。
咱們用:
HM1 表明主場球隊上一次比賽的輸贏,
AM1 表明客場球隊上一次比賽是輸贏。
同理,HM2 AM2 就是上上次比賽的輸贏, HM3 AM3 就是上上上次比賽的輸贏。
咱們繼續觀看處理後 05-06 年的後 5 五條數據:
def get_form(playing_stat,num): form = get_matchres(playing_stat) form_final = form.copy() for i in range(num,39): form_final[i] = '' j = 0 while j < num: form_final[i] += form[i-j] j += 1 return form_final def add_form(playing_stat,num): form = get_form(playing_stat,num) # M 表明 unknown, 由於沒有那麼多歷史 h = ['M' for i in range(num * 10)] a = ['M' for i in range(num * 10)] j = num for i in range((num*10),380): ht = playing_stat.iloc[i].HomeTeam at = playing_stat.iloc[i].AwayTeam past = form.loc[ht][j] h.append(past[num-1]) past = form.loc[at][j] a.append(past[num-1]) if ((i + 1)% 10) == 0: j = j + 1 playing_stat['HM' + str(num)] = h playing_stat['AM' + str(num)] = a return playing_stat def add_form_df(playing_statistics): playing_statistics = add_form(playing_statistics,1) playing_statistics = add_form(playing_statistics,2) playing_statistics = add_form(playing_statistics,3) return playing_statistics for i in range(len(playing_statistics)): playing_statistics[i] = add_form_df(playing_statistics[i]) #查看構造特徵後的05-06年的後5五條數據 playing_statistics[2].tail()
HomeTeam | AwayTeam | FTHG | FTAG | FTR | HTGD | ATGD | HTP | ATP | HM1 | AM1 | HM2 | AM2 | HM3 | AM3 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
375 | Fulham | Middlesbrough | 1 | 0 | H | -11 | -9 | 45 | 45 | L | D | W | D | W | L |
376 | Man United | Charlton | 4 | 0 | H | 34 | -10 | 80 | 47 | D | L | L | L | W | W |
377 | Newcastle | Chelsea | 1 | 0 | H | 4 | 51 | 55 | 91 | D | L | W | W | W | W |
378 | Portsmouth | Liverpool | 1 | 3 | A | -23 | 30 | 38 | 79 | W | W | W | W | L | W |
379 | West Ham | Tottenham | 2 | 1 | H | -4 | 16 | 52 | 65 | W | W | L | D | L | L |
而後咱們把比賽周的信息也放在裏面,也就是這一場比賽發生在第幾個比賽周。
特徵構造後的結果,咱們能夠直接查看 05-06 年的後 5 條數據:
def get_mw(playing_stat): j = 1 MatchWeek = [] for i in range(380): MatchWeek.append(j) if ((i + 1)% 10) == 0: j = j + 1 playing_stat['MW'] = MatchWeek return playing_stat for i in range(len(playing_statistics)): playing_statistics[i] = get_mw(playing_statistics[i]) #查看構造特徵後的05-06年的後五條數據 playing_statistics[2].tail()
HomeTeam | AwayTeam | FTHG | FTAG | FTR | HTGD | ATGD | HTP | ATP | HM1 | AM1 | HM2 | AM2 | HM3 | AM3 | MW | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
375 | Fulham | Middlesbrough | 1 | 0 | H | -11 | -9 | 45 | 45 | L | D | W | D | W | L | 38 |
376 | Man United | Charlton | 4 | 0 | H | 34 | -10 | 80 | 47 | D | L | L | L | W | W | 38 |
377 | Newcastle | Chelsea | 1 | 0 | H | 4 | 51 | 55 | 91 | D | L | W | W | W | W | 38 |
378 | Portsmouth | Liverpool | 1 | 3 | A | -23 | 30 | 38 | 79 | W | W | W | W | L | W | 38 |
379 | West Ham | Tottenham | 2 | 1 | H | -4 | 16 | 52 | 65 | W | W | L | D | L | L | 38 |
咱們打算把數據集比賽的信息都合併到一個表裏面,而後咱們把咱們剛纔計算獲得的這些得分數據,淨勝球數據除以週數,就獲得了周平均後的值。結果就能夠經過查看構造特徵後數據集的後 5 條數據。
# 將各個DataFrame表合併在一張表中 playing_stat = pd.concat(playing_statistics, ignore_index=True) # HTGD, ATGD ,HTP, ATP的值 除以 week 數,獲得平均分 cols = ['HTGD','ATGD','HTP','ATP'] playing_stat.MW = playing_stat.MW.astype(float) for col in cols: playing_stat[col] = playing_stat[col] / playing_stat.MW #查看構造特徵後數據集的後5五條數據 playing_stat.tail()
HomeTeam | AwayTeam | FTHG | FTAG | FTR | HTGD | ATGD | HTP | ATP | HM1 | AM1 | HM2 | AM2 | HM3 | AM3 | MW | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
5695 | Newcastle | Chelsea | 3.0 | 0.0 | H | -0.289474 | 0.710526 | 1.078947 | 1.842105 | L | D | L | W | L | W | 38.0 |
5696 | Southampton | Man City | 0.0 | 1.0 | A | -0.473684 | 2.052632 | 0.947368 | 2.552632 | W | W | D | D | W | W | 38.0 |
5697 | Swansea | Stoke | 1.0 | 2.0 | A | -0.710526 | -0.894737 | 0.868421 | 0.789474 | L | L | L | D | L | D | 38.0 |
5698 | Tottenham | Leicester | 5.0 | 4.0 | H | 0.973684 | -0.078947 | 1.947368 | 1.236842 | W | W | L | L | W | L | 38.0 |
5699 | West Ham | Everton | 3.0 | 1.0 | H | -0.578947 | -0.315789 | 1.026316 | 1.289474 | D | D | W | W | L | W | 38.0 |
咱們看到數據集最後一行的行數是 5699 ,加上第一行爲 0 行,則一共 5700 條數據;咱們總共統計了 15 年的數據,每年有 380 條數據,計算後發現咱們統計後的數據集大小是準確的。
前面咱們根據初始的特徵構造出了不少的特徵。這其中有一部分是中間的特徵,咱們須要把這些中間特徵拋棄掉。由於前三週的比賽,每一個隊的歷史勝負信息不足,因此咱們打算棄掉前三週的數據。
# 拋棄前三週的比賽 playing_stat = playing_stat[playing_stat.MW > 3] playing_stat.drop(['HomeTeam', 'AwayTeam', 'FTHG', 'FTAG', 'MW'],1, inplace=True) #咱們查看下此時的數據的特徵 playing_stat.keys()
Index(['FTR', 'HTGD', 'ATGD', 'HTP', 'ATP', 'HM1', 'AM1', 'HM2', 'AM2', 'HM3','AM3'], dtype='object')
在前面,咱們計算了每一的年主客場的勝率,如今咱們看看有效數據中,是主場勝利的多呢,仍是客場勝利的多呢?
# 比賽總數 n_matches = playing_stat.shape[0] # 特徵數 n_features = playing_stat.shape[1] - 1 # 主場獲勝的數目 n_homewins = len(playing_stat[playing_stat.FTR == 'H']) # 主場獲勝的比例 win_rate = (float(n_homewins) / (n_matches)) * 100 # Print the results print("比賽總數: {}".format(n_matches)) print("總特徵數: {}".format(n_features)) print("主場勝利數: {}".format(n_homewins)) print("主場勝率: {:.2f}%".format(win_rate))
比賽總數: 5250 總特徵數: 10 主場勝利數: 2451 主場勝率: 46.69%
經過統計結果看到:咱們主場勝率 46.69% 與咱們第 2.2.1 小節原始數據分析的結果是一致的,說明咱們前面構造的特徵是有效的,比較貼近實際的。
經過構造特徵以後,發現主場獲勝的比例接近 50% ,因此對於這個三分類的問題,標籤比例是不均衡的。
咱們把它簡化爲二分類問題,也就是主場球隊會不會勝利,這也是一種解決標籤比例不均衡的問題的方法。
# 定義 target ,也就是否 主場贏 def only_hw(string): if string == 'H': return 'H' else: return 'NH' playing_stat['FTR'] = playing_stat.FTR.apply(only_hw)
# 把數據分爲特徵值和標籤值 X_all = playing_stat.drop(['FTR'],1) y_all = playing_stat['FTR'] # 特徵值的長度 len(X_all)
5250
咱們對全部比賽的特徵 HTP 進行最大最小值歸一化。
def convert_1(data): max=data.max() min=data.min() return (data-min)/(max-min) r_data=convert_1(X_all['HTGD'])
# 數據標準化 from sklearn.preprocessing import scale cols = [['HTGD','ATGD','HTP','ATP']] for col in cols: X_all[col] = scale(X_all[col])
# 把這些特徵轉換成字符串類型 X_all.HM1 = X_all.HM1.astype('str') X_all.HM2 = X_all.HM2.astype('str') X_all.HM3 = X_all.HM3.astype('str') X_all.AM1 = X_all.AM1.astype('str') X_all.AM2 = X_all.AM2.astype('str') X_all.AM3 = X_all.AM3.astype('str') def preprocess_features(X): '''把離散的類型特徵轉爲啞編碼特徵 ''' output = pd.DataFrame(index = X.index) for col, col_data in X.iteritems(): if col_data.dtype == object: col_data = pd.get_dummies(col_data, prefix = col) output = output.join(col_data) return output X_all = preprocess_features(X_all) print("Processed feature columns ({} total features):\n{}".format(len(X_all.columns), list(X_all.columns)))
Processed feature columns (22 total features): ['HTGD', 'ATGD', 'HTP', 'ATP', 'HM1_D', 'HM1_L', 'HM1_W', 'AM1_D', 'AM1_L', 'AM1_W', 'HM2_D', 'HM2_L', 'HM2_W', 'AM2_D', 'AM2_L', 'AM2_W', 'HM3_D', 'HM3_L', 'HM3_W', 'AM3_D', 'AM3_L', 'AM3_W']
# 預覽處理好的數據 print("\nFeature values:") display(X_all.head())
Feature values:
HTGD | ATGD | HTP | ATP | HM1_D | HM1_L | HM1_W | AM1_D | AM1_L | AM1_W | ... | HM2_W | AM2_D | AM2_L | AM2_W | HM3_D | HM3_L | HM3_W | AM3_D | AM3_L | AM3_W | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
30 | 0.724821 | 0.339985 | -0.043566 | -0.603098 | 1 | 0 | 0 | 1 | 0 | 0 | ... | 0 | 0 | 0 | 1 | 0 | 0 | 1 | 0 | 1 | 0 |
31 | -0.702311 | -1.088217 | -1.097731 | -2.192828 | 0 | 1 | 0 | 1 | 0 | 0 | ... | 0 | 0 | 1 | 0 | 0 | 0 | 1 | 0 | 1 | 0 |
32 | 0.011255 | 0.339985 | -0.570649 | -0.603098 | 0 | 1 | 0 | 1 | 0 | 0 | ... | 0 | 0 | 0 | 1 | 0 | 0 | 1 | 0 | 1 | 0 |
33 | -0.345528 | -0.374116 | -1.097731 | -1.662918 | 0 | 1 | 0 | 1 | 0 | 0 | ... | 0 | 0 | 1 | 0 | 0 | 0 | 1 | 1 | 0 | 0 |
34 | 0.011255 | 1.054086 | -0.570649 | 0.456723 | 1 | 0 | 0 | 0 | 0 | 1 | ... | 0 | 0 | 0 | 1 | 0 | 0 | 1 | 0 | 1 | 0 |
5 rows × 22 columns
咱們生成一些特徵的相關圖,以查看特徵與特徵之間的相關性。 爲此,咱們將利用 Seaborn 繪圖軟件包,使咱們可以很是方便地繪製熱力圖,以下所示:
import matplotlib.pyplot as plt import seaborn as sns # 防止中文出現錯誤 plt.rcParams['font.sans-serif']=['SimHei'] plt.rcParams['axes.unicode_minus']=False #製成皮爾森熱圖 #把標籤映射爲0和1 y_all=y_all.map({'NH':0,'H':1}) #合併特徵集和標籤 train_data=pd.concat([X_all,y_all],axis=1) colormap = plt.cm.RdBu plt.figure(figsize=(21,18)) plt.title('Pearson Correlation of Features', y=1.05, size=15) sns.heatmap(train_data.astype(float).corr(),linewidths=0.1,vmax=1.0, square=True, cmap=colormap, linecolor='white', annot=True)
<matplotlib.axes._subplots.AxesSubplot at 0x211ffda5860>
經過上圖咱們能夠看出特徵 HTP 特徵和 HTGD 特徵相關性很強,一樣 ATP 特徵和 ATGD 特徵相關性很強,能夠代表多重共線性的狀況。這個咱們也很容易理解,主場周平均得分數越高,那麼主場周平均淨勝球數也一樣越高。若是咱們考慮這些變量,咱們能夠得出結論,它們給出了幾乎相同的信息,所以實際上發生了多重共線性,這裏咱們會考慮刪除 HTP 和 'ATP' 這兩個特徵,保留 HTGD 和 ATGD 這兩個特徵。皮爾森熱圖很是適合檢測這種狀況,而且在特徵工程中,它們是必不可少的工具。同時,咱們也能夠看出上上上次球隊的比賽結果對目前比賽的結果影響較小,這裏咱們考慮保留這些特徵。
X_all=X_all.drop(['HTP','ATP'],axis=1)
#FTR correlation matrix plt.figure(figsize=(14,12)) k = 10 # number of variables for heatmap cols = abs(train_data.astype(float).corr()).nlargest(k, 'FTR')['FTR'].index cm = np.corrcoef(train_data[cols].values.T) sns.set(font_scale=1.25) hm = sns.heatmap(cm, cbar=True, annot=True, square=True, fmt='.2f', annot_kws={'size': 10}, yticklabels=cols.values, xticklabels=cols.values) plt.show()
咱們能夠看出最相關的特徵是 HTGD ,代表一個球隊主場周平均淨勝球數越高,他們贏的機率也就越大。
將數據集隨機分紅爲訓練集和測試集,並返回劃分好的訓練集測試集樣本和訓練集測試集標籤。咱們直接採用 train_test_split
接口進行處理。
參數解釋:
返回值解釋:
隨機數種子:其實就是該組隨機數的編號,在須要重複試驗的時候,保證獲得一組同樣的隨機數。好比你每次都填1,其餘參數同樣的狀況下你獲得的隨機數組是同樣的。但填0或不填,每次都會不同。隨機數的產生取決於種子,隨機數和種子之間的關係聽從如下兩個規則:種子不一樣,產生不一樣的隨機數;種子相同,即便實例不一樣也產生相同的隨機數。
from sklearn.model_selection import train_test_split X_train, X_test, y_train, y_test = train_test_split(X_all, y_all,test_size = 0.3,random_state = 2,stratify = y_all)
下面咱們分別使用邏輯迴歸、支持向量機和 XGBoost 這三種不一樣的模型,來看看他們的表現。咱們先定義一些輔助函數,記錄模型的訓練時長和評估時長,計算模型的準確率和 f1 分數。咱們首先介紹一下這三個模型聯繫與區別和相關的接口:
邏輯迴歸模型是:假設數據服從伯努利分佈,經過極大化似然函數的方法,運用梯度降低來求解參數,來達到將數據二分類的目的。該模型的主要優勢是解釋性比較好;若是特徵工程作得好,模型效果也很是不錯;訓練速度也比較快;輸出結果也很容易調整。可是該模型的缺點也很突出,好比:準確率不是很高,比較難處理數據不均衡問題等。
API:sklearn.linear_model.LogisticRegression(penalty='l2', dual=False, tol=0.0001, C=1.0,fit_intercept=True, intercept_scaling=1, class_weight=None, random_state=None,solver='liblinear', max_iter=100, multi_class='ovr', verbose=0,warm_start=False, n_jobs=1)
主要參數解析:
以上是主要參數的簡單解析,若是你們想深刻了解,能夠參看官方網址 。
SVM(Support Vector Machine) 是一種二類分類模型。它的基本模型是在特徵空間中尋找間隔最大化的分離超平面的線性分類器。
(1)當訓練樣本線性可分時,經過硬間隔最大化,學習一個線性分類器,即線性可分支持向量機;
(2)當訓練數據近似線性可分時,引入鬆弛變量,經過軟間隔最大化,學習一個線性分類器,即線性支持向量機;
(3)當訓練數據線性不可分時,經過使用核技巧及軟間隔最大化,學習非線性支持向量機。
sklearn.svm.SVC(C=1.0,kernel='rbf',degree=3,gamma='auto',coef0=0.0,shrinking=True,probability=False,tol=0.001,cache_size=200,class_weight=None,verbose=False,max_iter=-1,decision_function_shape=None,random_state=None)
主要參數解析:
kernel :核函數,默認是rbf,能夠是‘linear’, ‘poly’, ‘rbf’, ‘sigmoid’, ‘precomputed’
主要調節的參數有:C、kernel、degree、gamma、coef0;參數詳解請參考官網。
XGBoost 是 Boosting算法的其中一種, Boosting 算法的思想是許多弱分類器集成在一塊兒,造成一個強分類器,基本原理是下一棵決策樹輸入樣本會與前面決策樹的訓練和預測相關。覺得 XGBoost 是一種提高樹模型,因此他是將許多樹模型集成在一塊兒,造成一個很強的分類器。而所用到的樹模型則是 CART 迴歸樹模型。
XGBoost.XGBRegressor(max_depth=3, learning_rate=0.1, n_estimators=100, silent=True, objective='reg:linear', booster='gbtree', n_jobs=1, nthread=None, gamma=0, min_child_weight=1, max_delta_step=0, subsample=1, colsample_bytree=1, colsample_bylevel=1, reg_alpha=0, reg_lambda=1, scale_pos_weight=1, base_score=0.5, random_state=0, seed=None, missing=None, **kwargs)
主要參數解析:
如想詳細學習該 API ,能夠參考官網網址 。
from time import time from sklearn.metrics import f1_score def train_classifier(clf, X_train, y_train): ''' 訓練模型 ''' # 記錄訓練時長 start = time() clf.fit(X_train, y_train) end = time() print("訓練時間 {:.4f} 秒".format(end - start)) def predict_labels(clf, features, target): ''' 使用模型進行預測 ''' # 記錄預測時長 start = time() y_pred = clf.predict(features) end = time() print("預測時間 in {:.4f} 秒".format(end - start)) return f1_score(target, y_pred, pos_label=1), sum(target == y_pred) / float(len(y_pred)) def train_predict(clf, X_train, y_train, X_test, y_test): ''' 訓練並評估模型 ''' # Indicate the classifier and the training set size print("訓練 {} 模型,樣本數量 {}。".format(clf.__class__.__name__, len(X_train))) # 訓練模型 train_classifier(clf, X_train, y_train) # 在測試集上評估模型 f1, acc = predict_labels(clf, X_train, y_train) print("訓練集上的 F1 分數和準確率爲: {:.4f} , {:.4f}。".format(f1 , acc)) f1, acc = predict_labels(clf, X_test, y_test) print("測試集上的 F1 分數和準確率爲: {:.4f} , {:.4f}。".format(f1 , acc))
import xgboost as xgb from sklearn.linear_model import LogisticRegression from sklearn.svm import SVC # 分別創建三個模型 clf_A = LogisticRegression(random_state = 42) clf_B = SVC(random_state = 42, kernel='rbf',gamma='auto') clf_C = xgb.XGBClassifier(seed = 42) train_predict(clf_A, X_train, y_train, X_test, y_test) print('') train_predict(clf_B, X_train, y_train, X_test, y_test) print('') train_predict(clf_C, X_train, y_train, X_test, y_test) print('')
訓練 LogisticRegression 模型,樣本數量 3675。 訓練時間 0.0050 秒 預測時間 in 0.0010 秒 訓練集上的 F1 分數和準確率爲: 0.6232 , 0.6648。 預測時間 in 0.0010 秒 測試集上的 F1 分數和準確率爲: 0.6120 , 0.6457。 訓練 SVC 模型,樣本數量 3675。 訓練時間 0.5755 秒 預測時間 in 0.3620 秒 訓練集上的 F1 分數和準確率爲: 0.6152 , 0.6746。 預測時間 in 0.1486 秒 測試集上的 F1 分數和準確率爲: 0.5858 , 0.6400. 訓練 XGBClassifier 模型,樣本數量 3675. . . 訓練時間 0.4079 秒 預測時間 in 0.0110 秒 訓練集上的 F1 分數和準確率爲: 0.6652 , 0.7067. 預測時間 in 0.0060 秒 測試集上的 F1 分數和準確率爲: 0.5844 , 0.6279。
經過運行結果,咱們發現:
咱們使用 sklearn 的 GridSearch 來進行超參數調參。
from sklearn.model_selection import GridSearchCV from sklearn.metrics import make_scorer import xgboost as xgb # 設置想要自動調參的參數 parameters = { 'n_estimators':[90,100,110], 'max_depth': [5,6,7], } # 初始化模型 clf = xgb.XGBClassifier(seed=42) f1_scorer = make_scorer(f1_score,pos_label=1) # 使用 grdi search 自動調參 grid_obj = GridSearchCV(clf, scoring=f1_scorer, param_grid=parameters, cv=5) grid_obj = grid_obj.fit(X_train,y_train) # 獲得最佳的模型 clf = grid_obj.best_estimator_ # print(clf) # 查看最終的模型效果 f1, acc = predict_labels(clf, X_train, y_train) print("F1 score and accuracy score for training set: {:.4f} , {:.4f}。".format(f1 , acc)) f1, acc = predict_labels(clf, X_test, y_test) print("F1 score and accuracy score for test set: {:.4f} , {:.4f}。".format(f1 , acc))
預測時間 in 0.0368 秒 F1 score and accuracy score for training set: 0.7991 , 0.8201。 預測時間 in 0.0149 秒 F1 score and accuracy score for test set: 0.5702 , 0.6133。
而後咱們能夠把模型保存下來,以供之後使用。
import joblib #保存模型 joblib.dump(clf, 'xgboost_model.model') #讀取模型 xgb = joblib.load('xgboost_model.model')
# 而後咱們嘗試來進行一個預測 sample1 = X_test.sample(n=5, random_state=2) y_test_1 = y_test.sample(n=5, random_state=2) print(sample1) # 進行預測 y_pred = xgb.predict(sample1) print("實際值:%s \n預測值:%s"%(y_test_1.values,y_pred))
HTGD ATGD HM1_D HM1_L HM1_W AM1_D AM1_L AM1_W HM2_D \ 70 0.189646 -1.088217 0 0 1 0 1 0 0 5529 -0.668332 -0.901190 0 1 0 1 0 0 0 4297 -0.702311 -0.136082 0 1 0 0 1 0 0 5230 -0.654740 -1.302447 0 0 1 0 1 0 0 1307 1.438387 -0.269101 1 0 0 0 0 1 0 HM2_L HM2_W AM2_D AM2_L AM2_W HM3_D HM3_L HM3_W AM3_D AM3_L \ 70 0 1 0 1 0 1 0 0 1 0 5529 0 1 0 1 0 1 0 0 0 1 4297 1 0 0 1 0 1 0 0 1 0 5230 1 0 1 0 0 0 1 0 0 1 1307 0 1 0 0 1 1 0 0 0 0 AM3_W 70 0 5529 0 4297 0 5230 0 1307 1 實際值:[0 0 1 1 1] 預測值:[1 0 1 1 1]
經過以上,咱們從 test 數據集中隨機挑選5個,預測值跟實際值相同的有 4 個,考慮到咱們準確率不高,可以獲得這個結果來講仍是比較幸運的。
經過該文章,您應該初步熟悉數據挖掘與分析和機器學習的流程,瞭解監督學習中邏輯迴歸模型,支持向量機模型和 XGBoost 模型的基本思想,熟悉機器學習庫 Pandas、Scikit-Learn、Searbon、XGBoost、joblib 的基本使用。須要注意的是:若是您未使用 MO 平臺,可能還須要安裝 XGBoost、SKlearn 等第三方庫,目前 Mo 平臺已安裝經常使用的機器學習相關的庫,能夠省去您安裝開發平臺的時間;另外,數據集也已在平臺公開,能夠直接導入。目前對於主流的機器學習庫的相關資料,咱們總結以下:
Python安裝
機器學習工具資料:
目前咱們模型的準確率還不是很高,還能夠進一步的改進咱們的模型,這裏咱們提供一下解決思路:
咱們已經將以上內容整理成機器學習實戰相關課程,您能夠在網站 訓練營實戰教程 中選擇 監督學習-分析和預測足球比賽結果 進行實操學習。您在學習的過程當中,發現咱們的錯誤或者遇到難題,能夠隨時聯繫咱們。
Mo(網址:momodel.cn)是一個支持 Python 的人工智能在線建模平臺,能幫助你快速開發、訓練並部署模型。
Mo 人工智能俱樂部 是由網站的研發與產品設計團隊發起、致力於下降人工智能開發與使用門檻的俱樂部。團隊具有大數據處理分析、可視化與數據建模經驗,已承擔多領域智能項目,具有從底層到前端的全線設計開發能力。主要研究方向爲大數據管理分析與人工智能技術,並以此來促進數據驅動的科學研究。
目前俱樂部每週六在杭州舉辦以機器學習爲主題的線下技術沙龍活動,不按期進行論文分享與學術交流。但願能匯聚來自各行各業對人工智能感興趣的朋友,不斷交流共同成長,推進人工智能民主化、應用普及化。