国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

采用 Python 機器學習預測足球比賽結果

FrancisSoung / 2170人閱讀

摘要:采用機器學習預測足球比賽結果足球是世界上最火爆的運動之一,世界杯期間也往往是球迷們最亢奮的時刻。特征工程在機器學習中占有非常重要的作用,一般認為括特征構建特征提取特征選擇三大部分。

采用 Python 機器學習預測足球比賽結果

足球是世界上最火爆的運動之一,世界杯期間也往往是球迷們最亢奮的時刻。比賽狂歡季除了炸出了熬夜看球的鐵桿粉絲,也讓足球競猜也成了大家茶余飯后最熱衷的話題。甚至連原來不怎么看足球的人,也是暗中努力惡補了很多足球相關知識,想通過賽事競猜先賺一個小目標。今天我們將介紹如何用機器學習來預測足球比賽結果!

本 Chat 采用 Python 編程語言,使用 人工智能建模平臺 Mo 作為在線開發環境進行編程,通過獲取 2000 年到 2018 年共 19 年英超的比賽數據,然后基于監督學習中邏輯回歸模型、支持向量機模型和 XGBoost 模型,對英超比賽結果進行預測。

下面我們一起來看看預測英超比賽結果的機器學習步驟:

主要流程步驟

獲取數據和讀取數據的信息

數據清洗和預處理

特征工程

建立機器學習模型并進行預測

總結與展望

1. 獲取數據和讀取數據的信息

首先我們進入 Mo 工作臺,創建一個空白項目,點擊 開始開發 進入內嵌 JupyterLab 的 Notebook 開發環境。

接著我們需要在項目中上傳數據集。

英超每年舉辦一個賽季,在每年的 8 月到第二年的 5 月進行,共有 20 支球隊,實行主客場雙循環賽制,每個賽季共 38 輪比賽(其中 19 場主場比賽,19 場客場比賽),每輪比賽共計 10 場比賽,所以每個賽季,英超共有 380 場比賽。

數據集地址

數據集中特征說明文檔

如果您已經在 MO 平臺新建項目,可以在平臺直接導入數據集,流程如下:

1.1 讀取 csv 數據接口解釋

采用 Pandas 讀取、寫入數據 API 匯總網址

讀取 csv 數據一般采用 pandas.read_csv():

pandas.read_csv(filepath_or_buffer, sep ="," , delimiter = None)

filepath_or_buffer:文件路徑

sep:指定分隔符,默認是逗號

delimiter:定界符,備選分隔符(如果指定改參數,則sep失效)

usecols: 指定讀取的列名,列表形式

# 導入必須的包
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"]
1.2 時間列表

獲取每一年的數據后,將每一年的年份放入到 time_list 列表中:

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"]

1.3 用 Pandas.read_csv() ?接口讀取數據

讀取時將數據與 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)
1.4 刪除特定文件的空值

經過查看第 15 個文件讀取的第 381 行為空值,故采取刪除行空值操作。

1.4.1 刪除空值的接口

Pandas.dropna(axis=0,how="any")

axis: 0 表示是行;1表示是列

how:"all"表示只去掉所有值均缺失的行、列;any表示只去掉有缺失值的行、列

1.4.2 接口運用
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

1.5 刪除行數不是 380 的文件名

考慮到英超一般是 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)
1.6 查看某一個數據集前n行數據

文件名.head(n)

n:默認是5,想獲取多少行數據就填寫數字值。

讀取數據前五行操作:

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

1.8 獲取某一年主場隊伍的名稱
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)
1.9 解析數據集列表頭含義

數據集行數已經固定,一般都是 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,列元素表頭:
 %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(全場比賽結果)等等,更多關于數據集中特征信息可以參考數據集特征說明文檔 。

2. 數據清洗和預處理

我們挑選 Hometeam,Awayteam,FTHG,FTAG,FTR 這五列數據,作為我們的原始的特征數據,后面基于這些原始特征,我們再構造一些新的特征。

2.1 ?挑選信息列

HomeTeam: 主場球隊名

AwayTeam: 客場球隊名

FTHG: 全場 主場球隊進球數

FTAG: ?全場 客場球隊進球數

FTR: ?比賽結果 ( H= 主場贏, D= 平局, A= 客場贏)

# 將挑選的信息放在一個新的列表中
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)
2.2 分析原始數據

我們首先預測所有主場球隊全都勝利,然后預測所有的客場都會勝利,對結果進行對比分析:

2.2.1 統計所有主場球隊都會勝利的準確率
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
2.2.2 統計所有客場球隊都會勝利的準確率
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

綜上比較:我們可以看出主場勝利的概率相對于輸和平局來說,確實概率要大。

2.3 我們想知道 Arsenal 作為主場隊伍時,他們的表現,如何求出 2005-06 所有比賽累計進球數 ?

我們知道 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
2.4 我們想知道各個球隊作為主場隊伍時,他們的表現如何 ?

先試試求 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
3. 特征工程

特征工程指的是把原始數據轉變為模型的訓練數據的過程,它的目的就是獲取更好的訓練數據特征,得到更好的訓練模型。特征工程能使得模型的性能得到提升,有時甚至在簡單的模型上也能取得不錯的效果。特征工程在機器學習中占有非常重要的作用,一般認為括特征構建、特征提取、特征選擇三大部分。

3.1 構造特征

因為這個比賽是一年一個賽季,是有先后順序的,那我們就可以統計到截止到本場比賽之前,整個賽季內,主客場隊伍的凈勝球的數量。那么對于每一個賽季的每一周,都統計出每個球隊到本周為止累計的進球數和丟球數之差,也就是凈勝球的數量。

3.1.1 計算每個隊周累計凈勝球數量

處理后的數據,我們可以通過看某一年的某幾條數據來體現,比如: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.2 統計主客場隊伍到當前比賽周的累計得分

統計整個賽季主客場隊伍截止到當前比賽周的累計得分。一場比賽勝利計 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 分。

3.1.3 ?統計某支隊伍最近三場比賽的表現

前面我們構造的特征反映了一只隊伍本賽季的歷史總表現,我們看看隊伍在最近三場比賽的表現。
我們用:

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
3.1.4 加入比賽周特征(第幾個比賽周)

然后我們把比賽周的信息也放在里面,也就是這一場比賽發生在第幾個比賽周。
特征構造后的結果,我們可以直接查看 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
3.1.5 合并比賽的信息

我們打算把數據集比賽的信息都合并到一個表里面,然后我們把我們剛才計算得到的這些得分數據,凈勝球數據除以周數,就得到了周平均后的值。結果就可以通過查看構造特征后數據集的后 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 條數據,計算后發現我們統計后的數據集大小是準確的。

3.2 刪除某些數據

前面我們根據初始的特征構造出了很多的特征。這其中有一部分是中間的特征,我們需要把這些中間特征拋棄掉。因為前三周的比賽,每個隊的歷史勝負信息不足,所以我們打算棄掉前三周的數據。

# 拋棄前三周的比賽
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")
3.3 分析我們構造的數據

在前面,我們計算了每一的年主客場的勝率,現在我們看看有效數據中,是主場勝利的多呢,還是客場勝利的多呢?

# 比賽總數
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 小節原始數據分析的結果是一致的,說明我們前面構造的特征是有效的,比較貼近實際的。

3.4 解決樣本不均衡問題

通過構造特征之后,發現主場獲勝的比例接近 50% ,所以對于這個三分類的問題,標簽比例是不均衡的。

我們把它簡化為二分類問題,也就是主場球隊會不會勝利,這也是一種解決標簽比例不均衡的問題的方法。

# 定義 target ,也就是否 主場贏
def only_hw(string):
    if string == "H":
        return "H"
    else:
        return "NH"
playing_stat["FTR"] = playing_stat.FTR.apply(only_hw)
3.5 將數據分為特征值和標簽值
# 把數據分為特征值和標簽值
X_all = playing_stat.drop(["FTR"],1)
y_all = playing_stat["FTR"]
# 特征值的長度
len(X_all)
5250
3.6 數據歸一化、標準化

我們對所有比賽的特征 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])
3.7 轉換特征數據類型
# 把這些特征轉換成字符串類型
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):
{}".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("
Feature 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

3.8 皮爾遜相關熱力圖

我們生成一些特征的相關圖,以查看特征與特征之間的相關性。 為此,我們將利用 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)

通過上圖我們可以看出特征 HTP 特征和 HTGD 特征相關性很強,同樣 ATP 特征和 ATGD 特征相關性很強,可以表明多重共線性的情況。這個我們也很容易理解,主場周平均得分數越高,那么主場周平均凈勝球數也同樣越高。如果我們考慮這些變量,我們可以得出結論,它們給出了幾乎相同的信息,因此實際上發生了多重共線性,這里我們會考慮刪除 HTP 和 "ATP" 這兩個特征,保留 HTGD 和 ATGD 這兩個特征。皮爾森熱圖非常適合檢測這種情況,并且在特征工程中,它們是必不可少的工具。同時,我們也可以看出上上上次球隊的比賽結果對目前比賽的結果影響較小,這里我們考慮保留這些特征。

考慮到樣本集特征 HTP 和 HTGD,ATP 和 ATGD 的相關性都超過了 90% ,故我們刪除特征 HTP , ATP :

X_all=X_all.drop(["HTP","ATP"],axis=1)

看看與FTR最相關的10個特征

#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 ,表明一個球隊主場周平均凈勝球數越高,他們贏的概率也就越大。

4.建立機器學習模型并進行預測 4.1 切分數據

將數據集隨機分成為訓練集和測試集,并返回劃分好的訓練集測試集樣本和訓練集測試集標簽。我們直接采用 train_test_split 接口進行處理。

4.1.1 ?train_test_split API 接口介紹

X_train, X_test, y_train, y_test =cross_validation.train_test_split(train_data,train_target,test_size=0.3, random_state=0)

參數解釋:

train_data:被劃分的樣本特征集

train_target:被劃分的樣本標簽

test_size:如果是浮點數,在0-1之間,表示樣本占比;如果是整數的話就是樣本的數量

random_state:是隨機數的種子。

返回值解釋:

x_train:訓練集特征值

x_test:測試集特征值

y_train:訓練集目標值

y_test:測試集目標值

隨機數種子:其實就是該組隨機數的編號,在需要重復試驗的時候,保證得到一組一樣的隨機數。比如你每次都填1,其他參數一樣的情況下你得到的隨機數組是一樣的。但填0或不填,每次都會不一樣。隨機數的產生取決于種子,隨機數和種子之間的關系遵從以下兩個規則:種子不同,產生不同的隨機數;種子相同,即使實例不同也產生相同的隨機數。

4.1.2 代碼處理分割數據
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)
4.2 相關模型及其接口介紹

下面我們分別使用邏輯回歸、支持向量機和 XGBoost 這三種不同的模型,來看看他們的表現。我們先定義一些輔助函數,記錄模型的訓練時長和評估時長,計算模型的準確率和 f1 分數。我們首先介紹一下這三個模型聯系與區別和相關的接口:

4.2.1 邏輯回歸介紹

邏輯回歸模型是:假設數據服從伯努利分布,通過極大化似然函數的方法,運用梯度下降來求解參數,來達到將數據二分類的目的。該模型的主要優點是解釋性比較好;如果特征工程做得好,模型效果也非常不錯;訓練速度也比較快;輸出結果也很容易調整。但是該模型的缺點也很突出,比如:準確率不是很高,比較難處理數據不均衡問題等。

4.2.2 邏輯回歸模型接口介紹

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)

主要參數解析:

penalty:正則化參數,l1 or ?l2, default: l2;

C:正則化系數λ的倒數,default: 1.0;

fit_intercept : 是否存在截距, default: True

solver:損失函數的優化方法,有以下四種可供選擇{newton-cg, lbfgs, liblinear,sag}, ?default: liblinear

multi_class:分類方式選擇,一般有{ovr, multinomial}, default:ovr;

class_weight:類型權重參數,默認為None

random_state:隨機數種子,默認為無

tol:迭代終止判據的誤差范圍

n_jobs:并行數,為-1時跟CPU核數一致,默認值為1。

以上是主要參數的簡單解析,如果大家想深入了解,可以參看官方網址 。

4.2.3 支持向量機介紹

SVM(Support Vector Machine) 是一種二類分類模型。它的基本模型是在特征空間中尋找間隔最大化的分離超平面的線性分類器。

(1)當訓練樣本線性可分時,通過硬間隔最大化,學習一個線性分類器,即線性可分支持向量機;
(2)當訓練數據近似線性可分時,引入松弛變量,通過軟間隔最大化,學習一個線性分類器,即線性支持向量機;
(3)當訓練數據線性不可分時,通過使用核技巧及軟間隔最大化,學習非線性支持向量機。

4.2.4 支持向量機分類模型API

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)

主要參數解析:

C:C-SVC的懲罰參數C,默認值是1.0。C越大,相當于懲罰松弛變量,希望松弛變量接近0,即對誤分類的懲罰增大,趨向于對訓練集全分對的情況,這樣對訓練集測試時準確率很高,但泛化能力弱。C值小,對誤分類的懲罰減小,允許容錯,將他們當成噪聲點,泛化能力較強。

kernel :核函數,默認是rbf,可以是‘linear’, ‘poly’, ‘rbf’, ‘sigmoid’, ‘precomputed’

0 – 線性:u"v

1 – 多項式:(gamma_u"_v + coef0)^degree

2 – RBF函數:exp(-gamma|u-v|^2)

3 –sigmoid:tanh(gamma_u"_v + coef0)

degree :多項式poly函數的維度,默認是3,選擇其他核函數時會被忽略。

gamma :rbf,poly 和sigmoid的核函數參數。默認是auto,則會選擇1/n_features

coef0 :核函數的常數項。對于poly和 sigmoid有用。

max_iter :最大迭代次數。-1為無限制。

decision_function_shape :ovo, ovr or None, default=None。

主要調節的參數有:C、kernel、degree、gamma、coef0;參數詳解請參考官網。

4.2.5 XGBoost 原理介紹

XGBoost 是 Boosting算法的其中一種, Boosting 算法的思想是許多弱分類器集成在一起,形成一個強分類器,基本原理是下一棵決策樹輸入樣本會與前面決策樹的訓練和預測相關。以為 XGBoost 是一種提升樹模型,所以他是將許多樹模型集成在一起,形成一個很強的分類器。而所用到的樹模型則是 CART 回歸樹模型。

4.2.6 XGBoost 接口介紹

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)

主要參數解析:

booster:模型類別,主要有2種,gbtree 和 gbliner,默認是: gbtree ;

nthread:使用 CPU 個數,為 -1 時表示使用全部 CPU 進行并行運算(默認),等于 1 時表示使用1個 CPU 進行運算;

scale_pos_weight:正樣本的權重,在二分類任務中,當正負樣本比例失衡時,設置正樣本的權重,模型效果更好。例如,當正負樣本比例為 1:10 時,scale_pos_weight=10;

n_estimatores:總共迭代的次數,即決策樹的個數;

early_stopping_rounds:在驗證集上,當連續n次迭代,分數沒有提高后,提前終止訓練

max_depth:樹的深度,默認值為6,典型值3-10;

min_child_weight:值越大,越容易欠擬合;值越小,越容易過擬合(值較大時,避免模型學習到局部的特殊樣本),默認為1;

learning_rate:學習率,控制每次迭代更新權重時的步長,默認0.3;

gamma:懲罰項系數,指定節點分裂所需的最小損失函數下降值;

alpha:L1 正則化系數,默認為 1 ;

lambda:L2 正則化系數,默認為 1 ;

seed:隨機種子。

如想詳細學習該 API ,可以參考官網網址 。

4.3 建立機器學習模型并評估
4.3.1 建立模型
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))
4.3.2 分別初始化,訓練和評估模型
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。

通過運行結果,我們發現:

在訓練時間上,邏輯回歸耗時最短,XGBoost 耗時最長,為 2 秒多。

在預測時間上,邏輯回歸耗時最短,支持向量機耗時最長。

在訓練集上 F1 分數方面,XGBoost 得分最高,支持向量機得分最低,但是差距不是很大。

在訓練集上準確率方面分析,XGBoost得分最高,邏輯回歸最低。

在測試集上 F1 分數方面分析,邏輯回歸的最好,其余兩個模型基本相等,相對較低。

在測試集上準確率方面分析,邏輯回歸支持向量機** 2 個模型基本相等,稍微比 XBGoost 高一點。

4.4 超參數調整

我們使用 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))
預測           
               
                                           
                       
                 

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/20027.html

相關文章

  • Python一些列安裝

    摘要:系列安裝報錯結果一樣的錯解決方法成功了過擬合當你觀察訓練精度高但檢測精度低很可能你遇到過度擬合問題。正如其名,它是的一個實現,作者為正在華盛頓大學研究機器學習的大牛陳天奇。為了方便大家使用,陳天奇將封裝成了庫。 xgboost系列 ubuntu14.04 安裝 pip install xgboost 報錯 sudo apt-get update 結果一樣的錯 解決方法: sudo -...

    vslam 評論0 收藏0
  • Kaggle冠軍經驗分享丨如何用15個月沖到排行榜的首位

    摘要:你是如何開始參加比賽的正如之前所說的,我一直在閱讀大量機器學習和深度學習方面的書籍和論文,但發現很難將我學到的算法應用于小型數據集。機器學習中,你對哪個子領域最感興趣我對深度學習的各種進步都很感興趣。 showImg(https://segmentfault.com/img/bVboxKz?w=800&h=600); 作者 Kaggle Team中文翻譯 MikaCDA 數據分析師...

    AnthonyHan 評論0 收藏0
  • python機器/深度學習項目匯總

    摘要:作者微信公眾號的皮卡丘歡迎大家搜索關注知乎機器學習美顏簡單品讀小說實現顏值預測預測比賽結果制作且版飛機大戰實現簡單的換臉術遺傳算法擬合圖像實現貓臉檢測分析個人音樂收藏垃圾郵件識別深度學習強化學習玩破解游戲實現簡單的機器翻譯模型學寫作實現文本 作者:Charles微信公眾號:Charles的皮卡丘(歡迎大家搜索關注)知乎:https://zhuanlan.zhihu.com/p/... ...

    toddmark 評論0 收藏0

發表評論

0條評論

FrancisSoung

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<