1.資料讀取與介紹
- 導入相關庫及子產品
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import KFold
- 利用pandas進行資料讀取,通過info()函數了解該資料的大緻資訊
file_name='data.csv'
data=pd.read_csv(file_name)
print('****該資料的大緻資訊如下****')
print(data.info())
- 列印前五行資料
- 擷取該資料的行數與列數
輸出為:該資料共有30697條記錄,25個特征項
通過以上結果顯示,我們得到:該資料在shot_made_flag字段上缺失值較多,且該字段為标簽項,0表示未射入球門,1表示攝入球門,是以需删去shot_made_flag項為NaN的記錄行。
data=data[data['shot_made_flag'].notnull()]
data.info()
2.特征資料可視化展示
- 将射球時相對于球門的位置(loc_x,loc_y),(lat,lon)在圖形中展示出來
#設定畫布大小
plt.figure(figsize=(12,12))
#畫第一個子圖
plt.subplot(121)
plt.title('the location of the shot')
plt.xlabel('loc_x')
plt.ylabel('loc_y')
plt.scatter(data['loc_x'], data['loc_y'], color='g', alpha = 0.02)
#畫第二個子圖
plt.subplot(122)
plt.title('the site of the shot')
plt.xlabel('longitude')#經度
plt.ylabel('latitude')#緯度
plt.scatter(data['lon'], data['lat'], color='r', alpha = 0.02)
3.資料預處理
上面可視化圖形顯示,科比的射門位置大緻呈半圓形,是以建構兩個新的字段值dist和angle,其中dist=sqtr(x^2 +y^2),angle為夾角。
data['dist'] = np.sqrt(data['loc_x']**2 + data['loc_y']**2)
loc_x_zero = data['loc_x'] == 0
#print (loc_x_zero)
data['angle'] = np.array([0]*len(data))
data['angle'][~loc_x_zero] = np.arctan(data['loc_y'][~loc_x_zero] / data['loc_x'][~loc_x_zero])
data['angle'][loc_x_zero] = np.pi / 2
- 建構新的字段remaining_time
- 列印字段action_type、combined_shot_type、shot_type和shot_type
print(data.action_type.unique())
print(data.combined_shot_type.unique())
print(data.shot_type.unique())
print(data.shot_type.value_counts())
列印字段season
輸出:array([‘2000-01’, ‘2001-02’, ‘2002-03’, ‘2003-04’, ‘2004-05’, ‘2005-06’,
‘2006-07’, ‘2007-08’, ‘2008-09’, ‘2009-10’, ‘2010-11’, ‘2011-12’,
‘2012-13’, ‘2013-14’, ‘2014-15’, ‘2015-16’, ‘1996-97’, ‘1997-98’,
‘1998-99’, ‘1999-00’], dtype=object)
- 建構新列
data['season'] = data['season'].apply(lambda x: int(x.split('-')[1]) )
data['season'].unique()
- 可視化distance與dist之間的關系
plt.figure(figsize=(5,5))
plt.scatter(data['dist'], data['shot_distance'], color='blue')
plt.title('dist and shot_distance')
plt.xlabel('dist')
plt.ylabel('shot_distance')
- 删除多餘字段
drops = ['shot_id', 'team_id', 'team_name', 'shot_zone_area', 'shot_zone_range', 'shot_zone_basic', \
'matchup', 'lon', 'lat', 'seconds_remaining', 'minutes_remaining', \
'shot_distance', 'loc_x', 'loc_y', 'game_event_id', 'game_id', 'game_date']
for drop in drops:
data = data.drop(drop, 1)
- 将分類字段轉化為數值型
categorical_vars = ['action_type', 'combined_shot_type', 'shot_type', 'opponent', 'period', 'season']
for var in categorical_vars:
data = pd.concat([data, pd.get_dummies(data[var], prefix=var)], 1)
data = data.drop(var, 1)
4.使用scikit-learn建立模型
- 構造訓練集
train_kobe = data.copy()
train_kobe = train_kobe.drop(axis=1, columns='shot_made_flag')
train_label = data['shot_made_flag']
- 導入相關庫及子產品
from sklearn.ensemble import RandomForestRegressor
from sklearn.metrics import confusion_matrix,log_loss
import time
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import KFold
-
機器學習步驟如下:
在這裡面,我們采用随機森林內建算法,對科比是否進球進行合理分類,代碼主要實作目标為:
- 尋求随機森林中樹的最優建構數量
- 尋求樹的最優深度,防止過度拟合現象發生
# find the best n_estimators for RandomForestClassifier
print('Finding best n_estimators for RandomForestClassifier...')
min_score = 100000
best_n = 0
scores_n = []
range_n = np.logspace(0,2,num=3).astype(int)
for n in range_n:
print("the number of trees : {0}".format(n))
t1 = time.time()
rfc_score = 0.
rfc = RandomForestClassifier(n_estimators=n)
for train_k, test_k in KFold(len(train_kobe), n_folds=10, shuffle=True):
rfc.fit(train_kobe.iloc[train_k], train_label.iloc[train_k])
#rfc_score += rfc.score(train.iloc[test_k], train_y.iloc[test_k])/10
pred = rfc.predict(train_kobe.iloc[test_k])
rfc_score += log_loss(train_label.iloc[test_k], pred) / 10
scores_n.append(rfc_score)
if rfc_score < min_score:
min_score = rfc_score
best_n = n
t2 = time.time()
print('Done processing {0} trees ({1:.3f}sec)'.format(n, t2-t1))
print(best_n, min_score)
# find best max_depth for RandomForestClassifier
print('Finding best max_depth for RandomForestClassifier...')
min_score = 100000
best_m = 0
scores_m = []
range_m = np.logspace(0,2,num=3).astype(int)
for m in range_m:
print("the max depth : {0}".format(m))
t1 = time.time()
rfc_score = 0.
rfc = RandomForestClassifier(max_depth=m, n_estimators=best_n)
for train_k, test_k in KFold(len(train_kobe), n_folds=10, shuffle=True):
rfc.fit(train_kobe.iloc[train_k], train_label.iloc[train_k])
#rfc_score += rfc.score(train.iloc[test_k], train_y.iloc[test_k])/10
pred = rfc.predict(train_kobe.iloc[test_k])
rfc_score += log_loss(train_label.iloc[test_k], pred) / 10
scores_m.append(rfc_score)
if rfc_score < min_score:
min_score = rfc_score
best_m = m
t2 = time.time()
print('Done processing {0} trees ({1:.3f}sec)'.format(m, t2-t1))
print(best_m, min_score)
輸出結果如下:
結果顯示:最優樹數量為100,樹最大深度為10
- 可視化在不同數量樹以及樹深度下随機森林的資訊熵(香農熵),資訊熵越大,表明此時資訊不确定性越大,即預測的準确性越低