Unverified Commit 0f0b0699 authored by Kiryuu's avatar Kiryuu
Browse files

Update 05

parent 1bb7ef4e
# 科比投篮预测——数据处理与分析
> 2016 年 4 月 12 日星期三,科比在洛杉矶湖人队的最后一场比赛中砍下 60 分,标志着他从 NBA 退役。17 岁时入选 NBA,并且在他漫长的职业生涯中赢得了这项运动的最高荣誉。
>
> 利用 20 年来科比的进球和失误数据,你能预测哪些投篮会落在篮框里吗?这个实训非常适合练习分类基础、特征工程和时间序列分析。训练让科比得到了 8 位数的合同和 5 枚总冠军戒指。那么通过本实训你会得到什么呢?
>
> 本实训主要实现:
>
> - 数据处理
> - 构建模型
> - 结果预测
> 数据来源:https://www.kaggle.com/c/kobe-bryant-shot-selection/data
> ![banner.png](banner.png)
## 第1关:数据清洗
### 任务描述
- 根据 `loc_x`,`loc_y``lan,lon` 所做图像构造距离 `dist` 字段,公式如下:
```math
\\dist = \sqrt{x^2+y^2}
```
- 根据 `loc_x` 构造角度列 `angle` 字段。
`loc_x` 为 0 使用下面公式计算 `angle`
```math
\\angle=arctan(loc_y[loc_y!=0]/loc_x[loc_x!=0])
```
`loc_x` 为 1 使用下面公式计算 `angle`
```math
\\angle=PI/2
```
- 计算总剩余时间,构造 `remaining_time` 字段,公式如下:
```math
\\remaining\_time=minutes\_remaining∗60+seconds\_remaining
```
数据字段描述如下:
字段 | 描述 |
:------------: | :------------: |
actiong_type |进攻方式(更具体)
combined_shor_type |进攻方式
game_event_id| 赛事id
game_id|比赛id
lat|投篮经度
loc_x|x轴投篮点
loc_y|y轴投篮点
lon|投篮维度
minutes_remaining|单节剩余时间(分钟)
period|表示第几节
playoffs|是否是季后赛
season|赛季
seconds_remaining|剩余时间(秒)
shot_distance|投篮距离
shot_made_flag|是否进球
shot_type|进球得分
shot_zone_area|投篮区域
shot_zone_basic|投篮区域(更具体)
shot_zone_range|投篮范围
team_id|球队id
team_name|球队名称
game_date|比赛日期
matchup|比赛双方
opponent|对手
shot_id|投篮id
### 编程要求
在右侧编辑器补充代码,数据文件路径为 `task1/data.csv`
### 测试说明
平台会对你编写的代码进行测试,请返回所构造的三个特征的前 5 行数据:
预期输出:
```python
dist angle remaining_time
0 181.859836 0.407058 627
1 157.000000 -0.000000 622
2 168.600119 -0.928481 465
3 222.865430 0.903063 412
4 0.000000 1.570796 379
```
提示:
```python
print(data.isnull().sum())#统计各列字段空值数量
```
---
开始你的任务吧,祝你成功!
### 答案
```python
import numpy as np
import pandas as pd
import warnings
warnings.filterwarnings("ignore")
pd.set_option('display.max_columns', 1000)
pd.set_option('display.width', 1000)
pd.set_option('display.max_colwidth', 1000)
def student():
result=""
# ********* Begin *********#
raw = pd.read_csv("task1/data.csv")
raw['dist'] = np.sqrt(raw['loc_x']**2 + raw['loc_y']**2)
loc_x_zero = raw['loc_x'] == 0
raw['angle'] = 0
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
raw['remaining_time'] = raw['minutes_remaining'] * 60 + raw['seconds_remaining']
result=raw[["dist","angle","remaining_time"]].head()
# ********* End *********#
return result
```
## 第2关:数据预处理
### 任务描述
本关任务:
- 删除所有不需要的变量
- 处理有字符串的列
数据字段描述如下:
字段 | 描述 |
:------------: | :------------: |
actiong_type |进攻方式(更具体)
combined_shor_type |进攻方式
game_event_id| 赛事id
game_id|比赛id
lat|投篮经度
loc_x|x轴投篮点
loc_y|y轴投篮点
lon|投篮纬度
minutes_remaining|单节剩余时间(分钟)
period|表示第几节
playoffs|是否是季后赛
season|赛季
seconds_remaining|剩余时间(秒)
shot_distance|投篮距离
shot_made_flag|是否进球
shot_type|进球得分
shot_zone_area|投篮区域
shot_zone_basic|投篮区域(更具体)
shot_zone_range|投篮范围
team_id|球队id
team_name|球队名称
game_date|比赛日期
matchup|比赛双方
opponent|对手
shot_id|投篮id
dist|投篮点与篮框之间的距离
angle|投篮角度
remaining_time|剩余总时间(秒)
### 相关知识
#### 删除变量
在上一关卡中,我们通过 `loc_x``loc_y` 得到了 `dist` 列和 `angle` 列,有了这两列之后,`loc_x`, `loc_y`, `lon`, `lat`, `shot_distance` 这几列就多余了。还使用 `remaining_time` 替代了 `minutes_remaining``seconds_remaining` 列。
[科比投篮预测——可视化](https://www.educoder.net/shixuns/nq7yp5uj/challenges)实训中,`shot_zone_area`, `shot_zone_basic``shot_zone_range` 三个图形均可以使用 `dist``angle` 分隔出来。所以我们也可以将这三个变量舍弃。
查看 `mathup``opponent` 这两列:
![img/01.png](img/01.png)
我们可以发现数据中只有科比在湖人队的投篮数据,所以,我们只需要 `opponent` 列。
#### 生成虚拟变量
我们将使用随机森林分类器来构建我们的模型但是它不接受像 `action_type` 这样的字符串变量,所以我们需要生成虚拟变量。`Pandas` 中有一个 `get_dummies()` 函数可以实现该功能:
```python
pandas.get_dummies(data, prefix=None, prefix_sep=_, dummy_na=False, columns=None, sparse=False, drop_first=False)
```
参数说明:
- `data`: `array-like`, `Series`, or `DataFrame`,输入的数据。
- `prefix`: `string`, `list of strings`, or `dict of strings`, `default None`, `get_dummies`,转换后,列名的前缀。
- `dummy_na`: `bool`, `default False`, 增加一列表示空缺值,如果 `False` 就忽略空缺值。
- `columns`: `list-like`, `default None`,指定需要实现类别转换的列名。
- `drop_first`: `bool`, `default False`,获得 `k` 中的 `k-1` 个类别值,去除第一个。
举个例子:
```python
import pandas as pd
df = pd.DataFrame([
['green' , 'A'],
['red' , 'B'],
['blue' , 'A']])
df.columns = ['color', 'class']
print(df)
print(\"\
\")
print(pd.get_dummies(df))
```
输出:
```python
color class
0 green A
1 red B
2 blue A
color_blue color_green color_red class_A class_B
0 0 1 0 1 0
1 0 0 1 0 1
2 1 0 0 1 0
```
### 编程要求
在右侧编辑器补充代码,并完成下列任务:
- 读取 `task2/data.csv` 文件
- 删除**所有**不需要的变量
- 处理 `value` 为字符串的列,生成虚拟变量
- 输出处理之后的 `DataFrame`**所有列名**
### 测试说明
平台会对你编写的代码进行测试:
预期输出:
```python
Index(['playoffs', 'shot_made_flag', 'dist', 'angle', 'remaining_time',
'action_type_Alley Oop Dunk Shot', 'action_type_Alley Oop Layup shot',
'action_type_Cutting Finger Roll Layup Shot',
'action_type_Cutting Layup Shot', 'action_type_Driving Bank shot',
...
'season_2006--07', 'season_2007--08', 'season_2008--09',
'season_2009--10', 'season_2010--11', 'season_2011--12',
'season_2012--13', 'season_2013--14', 'season_2014--15',
'season_2015--16'],
dtype='object', length=130)
```
---
开始你的任务吧,祝你成功!
### 答案
```python
import numpy as np
import pandas as pd
import warnings
warnings.filterwarnings("ignore")
raw = pd.read_csv("task2/data.csv",index_col=0)
def student(raw):
# ********** Begin ********** #
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)
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)
return raw.columns
# ********** End ********** #
if __name__ == "__main__":
stu = student(raw)
print(stu)
```
## 第3关:构造模型并调参
### 任务描述
本关任务:分割训练和测试数据进行模型构造并找到合适的参数。
### 相关知识
为了完成本关任务,你需要掌握:
1. 如何构造模型,
2. 如何寻找模型的最优参数。
#### 分割训练集
首先需要分离特征变量与目标变量。在寻找最优参数时为了防止过拟合我们采用交叉验证的方式分割数据,引入的方式为 `from sklearn.model_selection import KFold`,参数需设置为 3 折交叉验证,对数据进行洗牌。
#### 构造模型
这里我们使用随机森林 `from sklearn.ensemble import RandomForestClassifier`,它的优点是它能够处理很高维度(`feature` 很多)的数据,并且不用做特征选择。在每次交叉训练时需要知道模型使用当前参数时的优劣,所以需要建立损失函数以评价模型:
```python
import scipy as sp
def logloss(act, pred):
epsilon = 1e-15
pred = sp.maximum(epsilon, pred)
pred = sp.minimum(1-epsilon, pred)
ll = sum(act*sp.log(pred) + sp.subt\\fract(1,act)*sp.log(sp.subt\\fract(1,pred)))
ll = ll * -1.0/len(act)
return ll
```
#### 寻找最优参数
使用随机森林分类器和 `kfold` 交叉验证来测试模型:
- 使用 `range` 生成模型参数 `n_estimators` 的取值 `n`
- 将模型分成 3 份
- 选择其中 2 个用于构建模型,另 1 个用于测试模型
- 对其他 2 个重复相同的过程
- 计算分数取平均值
- 使用下一个 `n` 再次执行该过程
- 找到最佳分数的 `n`
-`max_depth` 参数重复相同的过程
### 编程要求
在右侧编辑器补充代码,在训练集上进行 3 折交叉验证寻找模型 `n_estimators``max_depth` 的最优值。(寻找的范围为 `[1,10,100]`
### 测试说明
平台会对你编写的代码进行测试:
预期输出:
```python
n_estimators100
max_depth10
```
---
开始你的任务吧,祝你成功!
### 答案
```python
import numpy as np
import pandas as pd
import scipy as sp
import warnings
warnings.filterwarnings("ignore") #忽略警告
with warnings.catch_warnings():
warnings.filterwarnings("ignore",category=DeprecationWarning)
from numpy.core.umath_tests import inner1d
from sklearn.ensemble import RandomForestRegressor
from sklearn.metrics import confusion_matrix
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import KFold
# 设置数据显示条数
pd.set_option('display.max_columns', 1000)
pd.set_option('display.width', 1000)
pd.set_option('display.max_colwidth', 1000)
# 评估模型
def logloss(act, pred):
epsilon = 1e-15
pred = sp.maximum(epsilon, pred)
pred = sp.minimum(1-epsilon, pred)
ll = sum(act*sp.log(pred) + sp.subtract(1,act)*sp.log(sp.subtract(1,pred)))
ll = ll * -1.0/len(act)
return ll
def student():
# ********* Begin *********#
df=pd.read_csv("task3/data.csv")
train = df.drop('shot_made_flag', 1)
train_y = df['shot_made_flag']
min_score = 100000
best_n = 0
scores_n = []
range_n = [1,10,100]
for n in range_n:
rfc_score = 0.
rfc = RandomForestClassifier(n_estimators=n)
kf=KFold(n_splits=3,shuffle=True)
for train_k, test_k in kf.split(train,train_y):
rfc.fit(train.iloc[train_k], train_y.iloc[train_k])
pred = rfc.predict(train.iloc[test_k])
rfc_score += logloss(train_y.iloc[test_k], pred) / 3
scores_n.append(rfc_score)
if rfc_score < min_score:
min_score = rfc_score
best_n = n
print("n_estimators:"+str(best_n))
min_score = 100000
best_m = 0
scores_m = []
range_m = [1,10,100]
for m in range_m:
rfc_score = 0.
rfc = RandomForestClassifier(max_depth=m, n_estimators=best_n)
kf=KFold(shuffle=True,n_splits=3)
for train_k, test_k in kf.split(train,train_y):
rfc.fit(train.iloc[train_k], train_y.iloc[train_k])
pred = rfc.predict(train.iloc[test_k])
rfc_score += logloss(train_y.iloc[test_k], pred) / 3
scores_m.append(rfc_score)
if rfc_score < min_score:
min_score = rfc_score
best_m = m
print("max_depth:"+str(best_m))
# ********* End *********#
```
## 第4关:参数验证
### 任务描述
本关任务:通过绘制折线图验证我们选择的 `n_estimators``max_depth` 参数是否是最好的。
### 相关知识
在构建模型和调参之后,我们需要验证我们的参数是否是最优值,所以我们需要通过可视化来验证结果,这里需要使用 Python 的 `matplotlib` 模块来实现数据的可视化功能。
### 编程要求
在右侧编辑器补充代码,并完成下列要求:
- 通过 `matplotlib` 模块实现折线图的绘制
- `figsize=(10,5)`
- y 轴都命名为 `score`,与 `n_estimators` 参数相关的图 x 轴命名为 `number of trees`,与 `max_depth` 相关的图 x 轴命名为 `max depth`
- 将得到的图形保存在 `task4/result/pict1.jpg`
### 测试说明
平台会对你编写的代码进行测试:
图形预期输出:
![img/02.png](img/02.png)
---
开始你的任务吧,祝你成功!
### 答案
```python
import matplotlib.pyplot as plt
import warnings
warnings.filterwarnings("ignore")
def visual(range_n,scores_n,range_m,scores_m):
# ********* Begin *********#
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.savefig("task4/result/pict1.jpg")
# ********* End *********#
```
## 第5关:预测结果
### 任务描述
本关任务:使用第三关得到的参数来做最终的模型和预测,输出预测的结果。
### 相关知识
通过 `sklearn` 模块中的随机森林 `RandomForestClassifier` 进行结果的预测,方法中的 `n_estimators``max_depth` 参数均来自第三关所得到的最优参数。
### 编程要求
在右侧编辑器补充代码,并完成下列要求:
- 读取 `task5/data.csv` 文件,该文件的内容为第二关数据预处理之后的正确结果
- 使用 `RandomForestClassifier` 进行结果预测
- 将预测得到的结果 `array` 赋值给 `pred`
### 测试说明
平台会对你编写的代码进行测试,**你的预测结果会以txt的形式向你展示**
预期输出的部分内容如下:
![img/03.png](img/03.png)
---
开始你的任务吧,祝你成功!
### 答案
```python
import numpy as np
import pandas as pd
import scipy as sp
import warnings
warnings.filterwarnings("ignore") #忽略警告
with warnings.catch_warnings():
warnings.filterwarnings("ignore",category=DeprecationWarning)
from numpy.core.umath_tests import inner1d
from sklearn.ensemble import RandomForestClassifier
def student(n_estimators,max_depth):
# ********* Begin *********#
raw = pd.read_csv("task5/data.csv",index_col=0)
df = raw[pd.notnull(raw['shot_made_flag'])]
submission = raw[pd.isnull(raw['shot_made_flag'])]
submission = submission.drop('shot_made_flag', 1)
train = df.drop('shot_made_flag', 1)
train_y = df['shot_made_flag']
model = RandomForestClassifier(n_estimators=n_estimators, max_depth=max_depth)
model.fit(train, train_y)
pred = model.predict_proba(submission)
# ********* End *********#
return pred
```
输出文本:
```
shot_made_flag 0 0.633575 1 0.632451 2 0.357906 3 0.303049 4 0.639660 5 0.633345 6 0.534817 7 0.522006 8 0.396273 9 0.641144 10 0.515910 11 0.620694 12 0.672604 13 0.674156 14 0.665178 15 0.643273 16 0.633602 17 0.666133 18 0.649284 19 0.413879 20 0.416820 21 0.644769 22 0.655585 23 0.646460 24 0.326868 25 0.380794 26 0.664369 27 0.640731 28 0.341423 29 0.621023 ... ... 4970 0.623324 4971 0.641949 4972 0.639830 4973 0.642527 4974 0.204062 4975 0.639651 4976 0.629659 4977 0.625863 4978 0.088293 4979 0.656269 4980 0.320075 4981 0.640628 4982 0.644848 4983 0.326532 4984 0.641466 4985 0.654755 4986 0.334431 4987 0.655865 4988 0.657429 4989 0.647846 4990 0.646659 4991 0.648278 4992 0.647874 4993 0.646310 4994 0.651345 4995 0.637574 4996 0.524761 4997 0.353106 4998 0.332512 4999 0.503255 [5000 rows x 1 columns]
```
\ No newline at end of file
import test
import numpy as np
from PIL import Image