先來看看這份科比生涯的數據集:數據集下載算法
這個表格記錄了科比30000多個鏡頭的詳細數據,共有25個標籤。app
具體的設計思路是將這25個標籤表明的數據進行分析,找出對科比投籃結果有影響的標籤,利用機器學習中隨機森林的算法訓練出能夠預測科比是否可以投籃命中的模型。dom
先來看看這25個標籤具體表明什麼(本身不是籃球的專業人士和愛好者,因此具體的內容可能有所出入,不過不會影響到分析結果)機器學習
action_type(用什麼方式投的籃)
combined_shot_type(結合什麼方式投籃)
game_event_id(遊戲事件ID)
game_id(遊戲ID)
la(投籃的經度)
loc_x (投籃的x座標)
loc_y(投籃的y座標)
lon(投籃的緯度)
minutes_remaining(離比賽結束還有多少分鐘)
period(第幾場)
playoffs(是否是季後賽)
season(賽季)
seconds_remaining(離比賽結束還有多少秒)
shot_distance(投籃離籃筐的的距離)
shot_made_flag (是否是進球了(主要的標籤))
shot_type(2分球仍是3分球區域)
shot_zone_area(投籃區域的表示方法一)
shot_zone_basic(投籃區域的表示方法二)
shot_zone_range(投籃區域的表示方法三)
team_id(隊伍ID)
team_name(隊伍名字)
game_date(比賽時間)
matchup(比賽雙方隊伍)
opponent(本身所在隊伍名字)
shot_id(鏡頭ID)
能夠看到,這25個標籤中對於科比可否投籃命中有一些可有可無的數據,好比team_id,由於這30000多份樣本中全是在湖人隊打的,shot_id,game_id等等這個數據也可有可無,具體的分析將會在下面講解。函數
3、數據分析
首先咱們導入數據,編寫代碼以下學習
import pandas as pd測試
# 導入數據
filename= "data.csv"
raw = pd.read_csv(filename)
print(raw.shape)
print(raw.head()) #head函數打印前5行,若是須要打印前10行,這樣寫編碼
接下來咱們再來分析這一份數據表,咱們發現其中shot_made_flag這個標籤居然有缺失值,這個表示了科比是否進球了,做爲最重要的數據,是不能隨意進行填充的,咱們必須刪除掉這些樣本進行下一步的工做,代碼以下spa
import pandas as pd設計
# 導入數據
filename= "data.csv"
raw = pd.read_csv(filename)
kobe = raw[pd.notnull(raw['shot_made_flag'])]
print(kobe.shape)
此時咱們只有25697個數據進行訓練了。
接着咱們分析lat,loc_x,loc_y,lon這4個標籤,這4個標籤說明了科比投籃的位置,而具體指的是什麼呢,有什麼關係嗎,咱們畫散點圖來看一下。
編寫代碼以下
import pandas as pd
import matplotlib.pyplot as plt
# 導入數據
filename= "data.csv"
raw = pd.read_csv(filename)
#刪除shot_made_flag爲空的數據項,而且命名爲kobe用做訓練
kobe = raw[pd.notnull(raw['shot_made_flag'])]
#畫散點圖用來分析lat loc_x loc_y lon這4個標籤
alpha = 0.02 #指定一個數字,用於後面的透明度
plt.figure(figsize=(6,6)) #指定畫圖域
# loc_x and loc_y
plt.subplot(121) #一行兩列 第一個位置
plt.scatter(kobe.loc_x, kobe.loc_y, color='R', alpha=alpha) #畫散點圖
plt.title('loc_x and loc_y')
# lat and lon
plt.subplot(122) #一行兩列 第二個位置
plt.scatter(kobe.lon, kobe.lat, color='B', alpha=alpha)
plt.title('lat and lon')
plt.show()
咱們大體能夠看出,這4個座標大體表示了距離籃筐的距離,那樣的話,咱們接下來用於數據處理的時候選擇其中的一組數據便可了。
shot_type,shot_zone_area,shot_zone_basic,shot_zone_range 這4個標籤表明了投籃的區域,其實仍是說明一件事,這裏就不作贅述了,固然shot_zone_area,shot_zone_basic,shot_zone_range這3個標籤將投籃區域相比於shot_type來講分的更細,直接刪掉是否是會有問題,其實大可沒必要擔憂,由於,接下來咱們將會用極座標的形式表示科比的投籃位置,將更會細化科比的投籃區域。
4、數據處理
首先處理咱們上節所說的極座標的問題,而後咱們會發現算出來的dist和,shot_distance居然具備正相關性。
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import time
from sklearn.ensemble import RandomForestClassifier #導入隨機森林分類器
from sklearn.cross_validation import KFold
from sklearn.metrics import log_loss
# 導入數據
filename= "data.csv"
raw = pd.read_csv(filename)
#刪除shot_made_flag爲空的數據項,而且命名爲kobe用做訓練
kobe = raw[pd.notnull(raw['shot_made_flag'])]
#對於lat,loc_x,loc_y,lon這4個標籤,咱們取loc_x和loc_y這2個標籤,並將其轉化爲極座標的形式
#dist表示離籃筐的距離,angle表示投籃的角度,這樣將會更好的科比投籃的反應結果`
raw['dist'] = np.sqrt(raw['loc_x']**2 + raw['loc_y']**2)
loc_x_zero = raw['loc_x'] == 0
raw['angle'] = np.array([0]*len(raw))
raw['angle'][~loc_x_zero] = np.arctan(raw['loc_y'][~loc_x_zero] / raw['loc_x'][~loc_x_zero])
raw['angle'][loc_x_zero] = np.pi / 2
#畫圖展現dist和shot_distance的正相關性
plt.figure(figsize=(5,5))
plt.scatter(raw.dist, raw.shot_distance, color='blue')
plt.title('dist and shot_distance')
plt.show()
運行結果以下
這樣咱們能夠保留其中的一個(這裏咱們保留了dist這個標籤),接着咱們將minutes_remaining和seconds_remaining轉化成一個標籤remaining_time,而後刪除沒必要要的列,非數值型的轉換成onehot編碼格式
具體編寫代碼以下,具體說明在代碼註釋中
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
# 導入數據
filename= "data.csv"
raw = pd.read_csv(filename)
#刪除shot_made_flag爲空的數據項,而且命名爲kobe用做訓練
kobe = raw[pd.notnull(raw['shot_made_flag'])]
#對於lat,loc_x,loc_y,lon這4個標籤,咱們取loc_x和loc_y這2個標籤,並將其轉化爲極座標的形式
#dist表示離籃筐的距離,angle表示投籃的角度,這樣將會更好的科比投籃的反應結果
raw['dist'] = np.sqrt(raw['loc_x']**2 + raw['loc_y']**2)
loc_x_zero = raw['loc_x'] == 0
raw['angle'] = np.array([0]*len(raw))
raw['angle'][~loc_x_zero] = np.arctan(raw['loc_y'][~loc_x_zero] / raw['loc_x'][~loc_x_zero])
raw['angle'][loc_x_zero] = np.pi / 2
#對於minutes_remaining:離比賽結束還有多少分鐘;seconds_remaining:離比賽結束還有多少秒(0-60),這
#2個屬性咱們合成距離比賽結束的時間
raw['remaining_time'] = raw['minutes_remaining'] * 60 + raw['seconds_remaining']
#機器學習只能識別數值型的數據
#將賽季中'Jan-00' 'Feb-01' 'Mar-02' ··· '1998-99'轉換成
# 0 1 2 ··· 99
raw['season'] = raw['season'].apply(lambda x: int(x.split('-')[1]) )
#刪除對於比賽結果沒有影響的數據
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:
raw = raw.drop(drop, 1)
#將非數值型的數據轉換成爲onehot編碼的格式,加入到數據中而且將原來的數據刪除
categorical_vars = ['action_type', 'combined_shot_type', 'shot_type', 'opponent', 'period', 'season']
for var in categorical_vars:
raw = pd.concat([raw, pd.get_dummies(raw[var], prefix=var)], 1)
raw = raw.drop(var, 1)
print(raw)
爲何會有129行之多,是由於咱們用了onehot編碼,具體什麼是onehot編碼這裏就不作贅述了,感興趣的能夠谷歌或者百度一下。
最後咱們總結一下,到底這25個標籤還剩下什麼,首先除去和比賽結果無關的標籤,’shot_id’, ‘team_id’, ‘team_name’, ‘shot_zone_area’, ‘shot_zone_range’, ‘shot_zone_basic’,’matchup’, ‘lon’,
‘lat’, ‘seconds_remaining’, ‘minutes_remaining’,’shot_distance’, , ‘game_event_id’, ‘game_id’,
‘game_date’
而後’loc_x’, ‘loc_y’轉換成了極座標的形式,變成了’dist’,’angle’;’seconds_remaining’和’minutes_remaining’合併成了’remaining_time’。
最後將’action_type’, ‘combined_shot_type’, ‘shot_type’, ‘opponent’, ‘period’, ‘season’轉換成onehot編碼格式。
至此咱們的數據處理工做基本完成了。
5、利用sklearn來進行數據的處理
具體的思路是利用隨機森林分類器配合着交叉驗證的方法進行數據的分析,先找到最佳的樹的個數,和樹的深度。
編寫代碼以下
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import time
from sklearn.ensemble import RandomForestClassifier #導入隨機森林分類器
from sklearn.cross_validation import KFold
from sklearn.metrics import log_loss
# 導入數據
filename= "data.csv"
raw = pd.read_csv(filename)
#刪除shot_made_flag爲空的數據項,而且命名爲kobe用做訓練
kobe = raw[pd.notnull(raw['shot_made_flag'])]
#對於lat,loc_x,loc_y,lon這4個標籤,咱們取loc_x和loc_y這2個標籤,並將其轉化爲極座標的形式
#dist表示離籃筐的距離,angle表示投籃的角度,這樣將會更好的科比投籃的反應結果`
raw['dist'] = np.sqrt(raw['loc_x']**2 + raw['loc_y']**2)
loc_x_zero = raw['loc_x'] == 0
raw['angle'] = np.array([0]*len(raw))
raw['angle'][~loc_x_zero] = np.arctan(raw['loc_y'][~loc_x_zero] / raw['loc_x'][~loc_x_zero])
raw['angle'][loc_x_zero] = np.pi / 2
# 對於minutes_remaining:離比賽結束還有多少分鐘;seconds_remaining:離比賽結束還有多少秒(0-60),這
# 2個屬性咱們合成距離比賽結束的時間
raw['remaining_time'] = raw['minutes_remaining'] * 60 + raw['seconds_remaining']
#機器學習只能識別數值型的數據
#將賽季中'Jan-00' 'Feb-01' 'Mar-02' ··· '1998-99'轉換成
# 0 1 2 ··· 99
raw['season'] = raw['season'].apply(lambda x: int(x.split('-')[1]) )
# 刪除對於比賽結果沒有影響的數據
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:
raw = raw.drop(drop, 1)
#將非數值型的數據轉換成爲onehot編碼的格式,加入到數據中而且將原來的數據刪除
categorical_vars = ['action_type', 'combined_shot_type', 'shot_type', 'opponent', 'period', 'season']
for var in categorical_vars:
raw = pd.concat([raw, pd.get_dummies(raw[var], prefix=var)], 1)
raw = raw.drop(var, 1)
#將數據分爲訓練集和測試集
train_kobe = raw[pd.notnull(raw['shot_made_flag'])]
train_label = train_kobe['shot_made_flag']
train_kobe = train_kobe.drop('shot_made_flag', 1)
test_kobe = raw[pd.isnull(raw['shot_made_flag'])]
test_kobe = test_kobe.drop('shot_made_flag', 1)
print('尋找隨機森林分類器的的最佳樹的數量...')
min_score = 100000
best_n = 0
scores_n = []
range_n = np.logspace(0, 2, num=10).astype(int)
for n in range_n:
print('樹的數量 : {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])
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('建造 {0} 顆樹(耗時{1:.3f}秒)'.format(n, t2 - t1))
print("最佳樹的顆樹爲 : {0},得分爲: {1}".format(best_n,min_score))
print('\n')
print('尋找隨機森林分類器的最佳樹的最佳深度...')
min_score = 100000
best_m = 0
scores_m = []
range_m = np.logspace(0, 2, num=10).astype(int)
for m in range_m:
print("樹的最大的深度 : {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])
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('樹的最大深度爲: {0}(耗時{1:.3f}秒)'.format(m, t2 - t1))
print('最佳樹的深度: {0},得分爲:{1}'.format(best_m, min_score))
plt.figure(figsize=(10,5))
plt.subplot(121)
plt.plot(range_n, scores_n)
plt.ylabel('score')
plt.xlabel('number of trees')
plt.subplot(122)
plt.plot(range_m, scores_m)
plt.ylabel('score')
plt.xlabel('max depth')
plt.show()
下面咱們用100,12這個參數訓練模型,而且預測出5000個’shot_made_flag’的缺失值。
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import time
from sklearn.ensemble import RandomForestClassifier #導入隨機森林分類器
from sklearn.cross_validation import KFold
from sklearn.metrics import log_loss
# 導入數據
filename = "data.csv"
raw = pd.read_csv(filename)
# 刪除shot_made_flag爲空的數據項,而且命名爲kobe用做訓練
kobe = raw[pd.notnull(raw['shot_made_flag'])]
# 對於lat,loc_x,loc_y,lon這4個標籤,咱們取loc_x和loc_y這2個標籤,並將其轉化爲極座標的形式
# dist表示離籃筐的距離,angle表示投籃的角度,這樣將會更好的科比投籃的反應結果`
raw['dist'] = np.sqrt(raw['loc_x']**2 + raw['loc_y']**2)
loc_x_zero = raw['loc_x'] == 0
raw['angle'] = np.array([0]*len(raw))
raw['angle'][~loc_x_zero] = np.arctan(raw['loc_y'][~loc_x_zero] / raw['loc_x'][~loc_x_zero])
raw['angle'][loc_x_zero] = np.pi / 2
# 對於minutes_remaining:離比賽結束還有多少分鐘;seconds_remaining:離比賽結束還有多少秒(0-60),這
# 2個屬性咱們合成距離比賽結束的時間
raw['remaining_time'] = raw['minutes_remaining'] * 60 + raw['seconds_remaining']
# 機器學習只能識別數值型的數據
# 將賽季中'Jan-00' 'Feb-01' 'Mar-02' ··· '1998-99'轉換成
# 0 1 2 ··· 99
raw['season'] = raw['season'].apply(lambda x: int(x.split('-')[1]) )
#刪除對於比賽結果沒有影響的數據
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:
raw = raw.drop(drop, 1)
#將非數值型的數據轉換成爲onehot編碼的格式,加入到數據中而且將原來的數據刪除
categorical_vars = ['action_type', 'combined_shot_type', 'shot_type', 'opponent', 'period', 'season']
for var in categorical_vars:
raw = pd.concat([raw, pd.get_dummies(raw[var], prefix=var)], 1)
raw = raw.drop(var, 1)
# print(raw)
# 將數據分爲訓練集和測試集
train_kobe = raw[pd.notnull(raw['shot_made_flag'])]
train_label = train_kobe['shot_made_flag']
train_kobe = train_kobe.drop('shot_made_flag', 1)
test_kobe = raw[pd.isnull(raw['shot_made_flag'])]
test_kobe = test_kobe.drop('shot_made_flag', 1)
# 訓練模型而且用預測shot_made_flag的缺失值
model = RandomForestClassifier(n_estimators=100, max_depth=12)
model.fit(train_kobe, train_label)
predictions = model.predict(test_kobe)
result=pd.DataFrame({'shot_id':test_shot_id['shot_id'].as_matrix(),'shot_made_flag':predictions.astype(np.int32)})
result.to_csv("result.csv", index=False)
這裏給出了5000個缺失值。
6、總結本篇文章主要用了機器學習的sklearn庫,配合着numpy,pandas,matplotlib的技術路線,利用隨機森林算法對科比生涯數據進行分析,對缺失值進行了預測。