Lebron個人數據對球隊勝場數的影響(part 2)

yuwei
Jacky’s blog
Published in
15 min readSep 12, 2018
source

前提:

接續上一篇討論EDA,我們會繼續接下來的步驟

特徵工程和特徵選擇(Feature Engineering and Feature selction)

特徵工程: 是一個將未經加工的資料進行加工並產生新的feature的過程,將原本的raw data feature進行數值轉換,有可能是進行取log或標準化(有MinMaxScaler和Standard Scaler等等) ,如果是針對非數值資料,可以使用onehotencoder將原本的categorical變成0和1並拆成好幾個feature以方便模型做辨識, feature engineer 就是從raw data 增加新的features

這個步驟是在機器學習專案裡面最重要的步驟,預測的成效,是否會有巨大的variance將取決於你在此一步驟的努力

特徵選擇: 是一個選擇最相關的feature的過程, 會根據不同的因素來判斷如何選取最好的features,可以直接選取擁有最大的相關係數(correlation coefficiency) 即可, 可以使得模型更好地被解釋,feature selection就是藉由feature engineering後的data進行’選擇’的行爲

這兩個步驟需要反覆驗證是否真的會使model變好

在這邊我會使用automated feature engineering(自動特徵工程) 來對Lebron比賽數據進行分析,manual和automated 兩個方法通常是automated feature engineering會對模型有比較好的效果, 提高模型預測的能力, 雖然花費的時間都一樣, 自動特徵工程的module花了我許多時間去理解其幫助我們再創造更多feature有何幫助

Feature engineering基本觀念

指從已經存在的data建立新的特徵值, 建立的方法有分成兩種型態

transformations: 只在同一個DataFrame裡進行作業,用既有的columns 去經過改變創造新的columns(ex. 取log, 單取日期裡面的月)

aggregations: 橫跨在不同的DataFrame裡作業, 有點像是groupby的效果,可以找出在這個條件下,另一個DataFrame的最大值,最小值或平均值等等

假如Lebron有分季賽跟季後賽的數據,transformation就是指針對季賽或季後賽分別的DataFrame進行統計運算, 如’防守籃板’和’進攻籃板’相加就可以變成一個全新的feature ‘總籃板’, 而aggregation是讓兩個DataFrame建立聯繫, 如Lebron季賽戰績假設是45勝37敗的話,這樣子通常季後賽總得分或總助攻是多少,類似groupby的概念

Featuretools :是一個自動進行多表格間的統計計算, 其中最重要的是 Deep Feature Synthesis (深度特徵合成), 此為透過一固定的深度d 進行運算,表示只將彼此的資料算到d深度, 而DFS也包含了 Feature primitives,

Feature primitives : 將個別化的計算用在Raw datasets上來建立新的features

相信大家一定會很模糊, 那我們就來用這個Lebron James專案來實作

步驟:

  1. 針對需要one- hot -encoder資料(離散型資料)進行get dummies
  2. 分析特徵值並將特徵值分為不同領域的DataFrame
  3. 建立DataFrame集並分別加入不同的DataFrame
  4. 建立DataFrame彼此的relationship
  5. 進行deep features synthesis

1.one- hot -encoder

機器學習無法辨別非數值型資料, 如果為True,必須將其改為1, False 改為0, 而面對離散型資料, ex 同一個對手column裡 有(CLE, MIA)等等, 我們要用get dummies 將該離散特徵的某個取值就對應歐式空間上的某一點

# '對手'和'所在隊伍'皆是離散型資料
df_matchteam=pd.get_dummies(df_new_date['對手'],prefix='對手')
df_belongteam=pd.get_dummies(df_new_date['所在隊伍'],prefix='所屬隊伍')
#將dummies後的variables與舊的DataFrame結合
df_new_date.drop(['所在隊伍','對手'],axis=1,inplace=True)
df_featuretools=pd.concat([df_new_date,df_belongteam,df_matchteam],axis=1)

2. 分析特徵值

現在準備使用featuretools 的DataFrame有以下這些欄位,

'場次', '季賽場次', '主客場', '是否先發', '上場時間', '二分球命中數', '二分球投球數', '二分球命中率','三分球命中數', '三分球投球數', '三分球命中率', '罰球命中數', '罰球投球數', '罰球命中率', '進攻籃板', '防守籃板',       '全部籃板', '助攻', '抄截', '火鍋', '失誤', '犯規', '得分', 'Game Score(貢獻值)', '正負值','輸贏', '所屬隊伍_CLE', '所屬隊伍_MIA', '對手_ATL',  '對手_BOS', '對手_BRK', '對手_CHA','對手_CHI', '對手_CHO', '對手_CLE', '對手_DAL', '對手_DEN', '對手_DET','對手_GSW', '對手_HOU', '對手_IND', '對手_LAC', '對手_LAL', '對手_MEM', '對手_MIA', '對手_MIL','對手_MIN', '對手_NJN', '對手_NOH', '對手_NOK', '對手_NOP', '對手_NYK', '對手_OKC',   '對手_ORL', '對手_PHI', '對手_PHO', '對手_POR', '對手_SAC', '對手_SAS', '對手_SEA', '對手_TOR', '對手_UTA', '對手_WAS'

我們可以清楚的分辨出, Lebron數據是一個區塊, 待過的球隊是一個區塊, 所面對的球隊一個區塊, 透過這樣的分類, 我知道, Lebron在他待過的球隊(待過球隊區塊), 在跟不同的球隊對抗時(對陣球隊區塊), 會產生不同的成績(數據區塊)

在這邊我們不探討’年紀’的影響

belong_team = [ '所屬隊伍_CLE', '所屬隊伍_MIA']opp_team = ['對手_ATL', '對手_BOS', '對手_BRK', '對手_CHA','對手_CHI', '對手_CHO', '對手_CLE', '對手_DAL', '對手_DEN', '對手_DET', '對手_GSW',
'對手_HOU', '對手_IND', '對手_LAC', '對手_LAL', '對手_MEM', '對手_MIA', '對手_MIL','對手_MIN', '對手_NJN', '對手_NOH', '對手_NOK', '對手_NOP', '對手_NYK', '對手_OKC','對手_ORL', '對手_PHI', '對手_PHO', '對手_POR', '對手_SAC', '對手_SAS', '對手_SEA','對手_TOR', '對手_UTA', '對手_WAS']
stats = [ '二分球命中數', '二分球投球數', '二分球命中率','三分球命中數', '三分球投球數', '三分球命中率','罰球命中數', '罰球投球數', '罰球命中率','進攻籃板', '防守籃板','全部籃板','助攻', '抄截', '火鍋', '失誤','犯規', '得分', 'Game Score(貢獻值)', '正負值','是否先發', '上場時間','場次', '季賽場次', '主客場']target=['輸贏']

好了, 我們已經分析好等一下DataFrame集裡面的各個DataFrame裡的features, 記住,最重要的目標是在特定數據下,Lebron是否會帶領球隊取得勝利

3.利用featuretools 建立DataFrame集

在featuretools裡面此DataFrame集被稱為EntitySet, 而DataFrame又被稱為Entities,

import featuretools as ft#建立新的EntitySets
es = ft.EntitySet(id='df_featuretools')

加入Entities , 每個entities都必須指定一個index ,它是在原先的columns裡面(column裡的element 必須都不同), 也就是說,在index裡面的value都只能出現一次, 我們使用’場次’來到index

運行上面的code,就會得到以下的回饋:

關於Relationships的部分,我等一下會進一步說明

現在我們要開始告訴featuretools 這些entities是為什麼樣的關係, 超連結裡有提到, relationships裡必須是one-to-many而不是one-to-one或many-to-many的關係, one 就是parent項, many 就是child項, 表示belong_team的場次必定會對unique的stats和opp

belong_opp=ft.Relationship(es['belong_team']['場次_id'],es['opp_team']['對手_id'])
belong_stat=ft.Relationship(es['belong_team']['場次_id'],es['stats']['場次'])
es=es.add_relationship(belong_opp)
es=es.add_relationship(belong_stat)

加入relationships後就可以開始進行deep features synthesis , 但在進行dfs前你必須先瞭解feature primitive, 我將用表格呈現有許多的方法可以製作出新的features

#兩種type我分別呈現10給你們看
primitives=ft.list_primitives()
primitives_df=primitives[primitives['type'] == 'aggregation'].append(primitives[primitives['type'] == 'transform'])
primitives_df.groupby('type').head(10)
feature primitives
#dfs 表示為deep features synthesis
#target_entity是指你想讓這個DataFrame為features的
#chunk_size>0 代表一次計算幾個row, 1>chunk_size>0 代表每次會抽取的比率
chunk_size = 'cutoff time' 會依據每個截止時間依次進行 或chunk_size=None
feature,feature_names=ft.dfs(entityset=es,target_entity='stats',
max_depth= 2,verbose =1,n_jobs=-1,chunk_size=100)

好了, 我們已進行完dfs的部分, 還記得我剛剛有把target加上去嗎? 我們現在要把含有’輸贏’的columns都drop掉,以免對預測模型產生錯亂

還有Game Score(貢獻值)的問題,這個數值本身就是用得分助攻等數據來計算出球員的貢獻值,所以我們也把它drop掉,以免影響取important features的問題

現在將feature_matrix 改名為train 以便接下來的建模

Feature Selection

我們使用feature_selector,這是由我之前已經提過的大神William Koehrsen自己寫出來的特徵選擇套件, 在這個feature_selector中, 針對缺失值, 對模型0重要性的columns, 低重要性的columns, 只有單一值和features間的相關程度等重要的特徵選擇步驟都有進行一定程度的著墨,我也將帶大家來使用這個套件

from feature_selector import FeatureSelector

1.將其改成features label(target)型態

要把features 和 target都分離出來, 並放入FeatureSelector的function 中

labels=train['輸贏']
train = train.drop(['輸贏'], axis=1)
fs = FeatureSelector(data=train,labels=labels)

2.處理缺失值

(1)有幾個含有NaN(缺失值)的features

#設定超過0.6都是NaN就會+1
fs.identify_missing (missing_threshold=0.6)

(2)呈現含有NaN值的features名稱和缺失比例

fs.record_missing.head()

(3)依照有NaN值的比例做圖

fs.plot_missing()

3.找出共線性(colliear)大於一定比例的features

(1)設定閥值

#設定閥值 超過就會+1
fs.identify_collinear(correlation_threshold=0.9)

(2)以DataFrame的型態呈現collinear 兩features之間的關係

fs.record_collinear.head()

(3)做出heatmap圖

4.尋找對預測target沒有貢獻的features

(1)使用lightGBM演算法(到機器學習演算法章節會在跟各位說明)

(2)zero_importance的features

#fs.ops會回傳為zero_importance的features的list
zero_importance_features = fs.ops['zero_importance']
zero_importance_features[:10]

(3)也尋找低貢獻的features

#當重要貢獻度的feautures累積超過0.99後,剩下就是低貢獻features
fs.identify_low_importance(cumulative_importance=0.99)
#回傳低貢獻的DataFrame
fs.record_low_importance.head()

(4)好奇貢獻最大的features是哪一個

fs.feature_importances.sort_values(by='cumulative_importance')

最後,你一定會好奇為什麼我們一直在看這些理因要drop掉的features,但為什麼我們都沒有做處理,只是單純查看這些factors,因為我們是要把剛剛篩選出來的不必要features都一併去除掉

#method可以客製化你想要先去除的
train_removed=fs.remove(methods='all')

如果你不放心,想要check被去除掉的columns,可以

all_to_remove=fs.check_removal()
all_to_remove

結論

這一篇我們主要介紹了特徵工程和特徵選擇的方法,這兩個是機器學習專案裡非常重要的一環,因為就算在之後的套模型裡,理解模型後,相對的難度就不會比做特徵工程和選擇上來的複雜,以後我會再藉由其他專案帶大家用手動的方是來處理特徵值

最後,歡迎任何問題與我討論,都可以寄來我的email,我的信箱是jacky308082@gmail.com

--

--

yuwei
Jacky’s blog

Curious Data scientist. Strong Lebron James’s fan. #StriveForGreatness #JustAKidFromTaiwan https://www.linkedin.com/in/yu-wei-chung/