3. 用决策树预测获胜球队

# -*- coding: utf-8 -*-
"""
Created on Sun Sep 23 16:15:30 2018

@author: asus
"""
#3 用决策树预测获胜球队

#3.1.2 用pandas加载数据集
import pandas as pd
dataset = pd.read_csv("NBA.csv")
dataset.ix[:5]
dataset[dataset.duplicated()] #检查重复元素

#3.1.3 数据集清洗
#日期是字符串格式,而不是日期对象
#第一行没有数据
#从视觉上检查结果,发现表头不完整或不正确

dataset = pd.read_csv("NBA.csv", parse_dates=["Date"]) #参数skiprows=[0,],表示
                                                  #数据从除去标题的第一行开始读取
dataset.columns = ["Date", "Score Type", "Visitor Team", "VisitorPts",
                   "Home Team", "HomePts", "OT?", "Notes"]
dataset.ix[:5]
print(dataset[dataset.duplicated()])
#每场比赛有两个队:主场队和客场队。最直接的方法就是拿几率作为基准,猜中的几率为50%。
#猜测任意一支球队获胜,都有一半胜算。

#3.1.4 提取新特征
#确定类别值,用1表示主场获胜,用0表示客场获胜。对于篮球比赛而言,得分最多的获胜。
dataset["HomeWin"] = dataset["VisitorPts"] < dataset["HomePts"]
y_ture = dataset["HomeWin"].values
#y_true数组保存的是类别数据,scikit-learn可直接读取

#首先,创建两个能帮助我们进行预测的特征,分别是这两支队伍上场比赛的胜负情况。赢得上场
#比赛,大致可以说明该球队的水平较高。
#遍历每一行数据,记录获胜球队。当到达一行新数据时,分别查看该行数据中两支球队在各自的
#上一场比赛中有没有获胜。
from collections import defaultdict
won_last = defaultdict(int) #作用为查询字典中没有的key时,返回一个默认值,如0
#字典的键为球队,值为是否赢得上一场比赛。
dataset['HomeLastWin'] = None     #此两行书上没有,应增加改两行,否则下面的循环不能
dataset['VisitorLastWin'] = None  #创建这两列

for index, row in dataset.iterrows():
    home_team = row["Home Team"]
    visitor_team = row["Visitor Team"]
    row["HomeLastWin"] = won_last[home_team]
    row["VisitorLastWin"] = won_last[visitor_team]
    dataset.ix[index] = row
    won_last[home_team] = row["HomeWin"]
    won_last[visitor_team] = not row["HomeWin"]
#注意,上述代码是按时间排列好的,如未排列,请将dataset.iterrows()替换为
#dataset.sort("Date").iterrows()。
#用当前比赛(建立到的哪一行数据所表示的比赛)的结果更新两支球队上场比赛的获胜情况,以
#便下次再遍历到这两支球队时使用。
dataset.ix[20:25]

#3.2 决策树
#决策树是一种有监督的机器学习算法,它看起来就像是由一系列节点组成的流程图,其中位于上
#层节点的值决定下一步走向哪个节点。

#3.2.1 决策树中的参数
#退出准则的方法
#min_samples_split:指定创建一个新节点至少需要的个体数量。
#min_samples_leaf:指定为了保留节点,每个节点至少应该包含的个体数量。
#第一个参数控制着决策节点的创建,第二个参数决定着决策节点能否被保留。

#决策树的另一个参数是创建决策的标准,
#基尼不纯度(Gini impurity):用于衡量决策节点错误预测新个体类别的比例。
#信息增益(Information gain):用信息论中的熵来表示决策节点提供多少信息。

#3.2.2 使用决策树
from sklearn.tree import DecisionTreeClassifier
clf = DecisionTreeClassifier(random_state=14)
#随机种子,以后在自己的实验中,需使用不同的
#从pandas数据框中抽取数据
x_previouswins = dataset[["HomeLastWin", "VisitorLastWin"]].values
from sklearn.cross_validation import cross_val_score #交叉验证
scores = cross_val_score(clf, x_previouswins, y_ture, scoring="accuracy")
import numpy as np
print("Accuracy:{0:1f}%".format(np.mean(scores) * 100))
#从数据集中构建有效特征(特征工程)是数据挖掘的难点所在,好的特征直接关系到结果的正确率,
#甚至比选择合适的算法更重要。

#3.3 NBA比赛结果预测
#第一个特征,主场队是否通常比对手水平高。
#使用2013赛季排名作为特征取值来源
standings = pd.read_csv("NBA2.csv")
standings
#接下来,创建一个新特征,创建过程与上个特征类似。遍历每一行,查找主场队和客场队两支球
#队的战绩。
dataset["HomeTeamRanksHigher"] = 0
for index, row in dataset.iterrows():
    home_team = row["Home Team"]
    visitor_team = row["Visitor Team"]
    if home_team == "New Orleans Pelicans":
        home_team = "New Orleans Hornets"
    elif visitor_team == "New Orleans Pelicans":
        visitor_team = "New Orleans Hornets"
    home_rank = standings[standings["Team"] == home_team]["Rk"].values[0]
    visitor_rank = standings[standings["Team"] == visitor_team]["Rk"].values[0]
    row["HomeTeamRanksHigher"] = int(home_rank > visitor_rank)
    dataset.ix[index] = row
#整合数据,有球队2014赛季改了名称,查找球队是,需要换回原来的名字。
#比较排名,更新特征值
#测试结果
x_homehiger = dataset[["HomeLastWin", "VisitorLastWin",
                       "HomeTeamRanksHigher"]].values
clf = DecisionTreeClassifier(random_state=14)
scores = cross_val_score(clf, x_homehiger, y_ture, scoring="accuracy")
print("Accuracy:{0:.1f}%".format(np.mean(scores) * 100))

#统计两支球队上场比赛情况,作为另一个特征。
#不考虑哪支球队是主场作战,仅看在上一场中谁是赢家。
last_match_winner = defaultdict(int)
dataset["HomeTeamWonLast"] = 0
for index, row in dataset.iterrows():
    home_team = row["Home Team"]
    visitor_team = row["Visitor Team"]
    teams = tuple(sorted([home_team, visitor_team]))
    row["HomeTeamWonLast"] = 1 if last_match_winner[teams] == row["Home Team"] else 0 
    dataset.ix[index] = row
    winner = row["Home Team"] if row["HomeWin"] else row["Visitor Team"]
    last_match_winner[teams] = winner
#用新抽取的两个特征创建数据集。观察不同特征组合的分类效果。
x_lastwinner = dataset[["HomeTeamRanksHigher", "HomeTeamWonLast"]].values
clf = DecisionTreeClassifier(random_state=14)
scores = cross_val_score(clf, x_lastwinner, y_ture, scoring="accuracy")
print("Accuracy:{0:.1f}%".format(np.mean(scores) * 100))

#最后,看决策树在训练数据很大的情况下,能否得到有效的分类模型。我们将会为决策树添加球
#队,以检测它是否能整合新增的信息。
#虽然决策树能够处理特征值为类别型的数据,但scikit-learn库所实现的决策树算法要求先对这
#类特征进行处理。用LabelEncoder转换器就能把字符串类型的球队名转换为整型。
from sklearn.preprocessing import LabelEncoder
encoding = LabelEncoder()
encoding.fit(dataset["Home Team"].values)
#抽取所有比赛的主客场球队的球队名(已转化为数值型)并将其组合起来,形成一个矩阵。
home_teams = encoding.transform(dataset["Home Team"].values)
visitor_teams = encoding.transform(dataset["Visitor Team"].values)
x_teams = np.vstack([home_teams, visitor_teams]).T
#决策树可以用这些特征值进行训练,但DecisionTreeClassifier仍把它们当作连续型特征。即
#会认为1和2相似,但对两支球队而言,要么是同一支球队,要么不同,没有中间状态。
#为了消除这种和实际不一致的情况,可以用OneHotEncoder转换器把整数转换为二进制数字。
from sklearn.preprocessing import OneHotEncoder
onehot = OneHotEncoder()
#在相同的数据集上进行预处理和训练操作,将结果保存起来备用。
x_teams_expanded = onehot.fit_transform(x_teams).todense()
#在新数据集上调用决策树分类器
clf = DecisionTreeClassifier(random_state=14)
scores = cross_val_score(clf, x_teams_expanded, y_ture, scoring="accuracy")
print("Accuracy:{0:.1f}%".format(np.mean(scores) * 100))

#3.4 随机森林

#3.4.2 随机森林算法的参数
#RandomForestClassifier
#n_estimators:用来指定创建决策树的数量。该值越高,所花时间越长,正确率(可能)越高。
#oob_score:如果设置为真,测试时将不使用训练模型时用过的数据。
#n_jobs:采用并行计算方法训练决策树时所用到的内核数量。

#3.4.3 使用随机森林算法
from sklearn.ensemble import RandomForestClassifier
clf = RandomForestClassifier(random_state=14)
scores = cross_val_score(clf, x_teams_expanded, y_ture, scoring='accuracy')
print("Accuracy:{0:.1f}%".format(np.mean(scores) * 100))
#随机森林使用不同的特征自己进行学习,应该比普通的决策树更为高效。
x_all = np.hstack([x_homehiger, x_teams_expanded])
clf = RandomForestClassifier(random_state=14)
scores = cross_val_score(clf, x_all, y_ture, scoring='accuracy')
print("Accuracy:{0:.1f}%".format(np.mean(scores) * 100))
#可以使用GridSearchCV类搜索最佳参数
parameter_space = {
        "max_features": [2, 10, 'auto'],
        "n_estimators": [100,],
        "criterion": ["gini", "entropy"],
        "min_samples_leaf": [2, 4, 6],
        }
clf = RandomForestClassifier(random_state=14)
from sklearn.model_selection import GridSearchCV
grid = GridSearchCV(clf, parameter_space)
grid.fit(x_all, y_ture)
print("Accuracy:{0:.1f}%".format(grid.best_score_ * 100))
#输出用网格搜索找到的最佳模型,查看都使用了哪些参数。
print(grid.best_estimator_)

#3.4.4 创建新特征
#dataset["New Feature"] = feature_creator()  #没找到
#feature_creator函数返回数据集中每条数据的各个特征值。常用数据集作为参数
#dataset["New Feature"] = feature_creator(dataset)
#最直接的做法是一开始为新特征设置默认的值
#dataset["My New Feature"] = 0
for index, row in dataset.iterrows():
    home_team = row["Home Team"]
    visitor_team = row["Visitor Team"]
    # Some calculation here to alter row
    dataset.ix[index] = row
#请注意,上面的这种遍历方法效率不高。如果你要用的话,请一次性处理所有特征。




你可能感兴趣的:(python数据挖掘入门与实践)