用户的静态数据–mysql
用户的动态数据–浏览、加购、收藏等
标签形态及标签建模
算法路线及算法思路:
标签层级
属性的显隐性反馈
构建决策树三要素
I(x)=plog(1/p)
,对不确定性函数求解期望,期望就是E(x)=-sum(xlog(x))
Gain(A) = Info(D)-Info_A(D)
贪心算法:顾名思义,贪心算法总是作出在当前看来最好的选择。也就是说贪心算法并不从整体最优考虑,它所作出的选择只是在某种意义上的局部最优选择。
无论哪种方法构建树,因为树的构建过程是递归形式的,所以有可能出现树的过拟合情况
先剪枝(较多)
后剪枝
剪枝系数(了解)
剪枝算法
决策树算法的优点
决策树算法的缺点
决策树算法处理连续值
ID3步骤图解如下
总结 : 根据信息熵和信息增益得到的决策树和之前利用自己制定规则得到的决策树,有明显的不同,因此,利用信息熵和信息增益可以得到分类效果更优的决策树。
import pandas as pd
#1.导入数据、
buyData=pd.read_csv("buy.csv",sep=",")
print(buyData)
# age income student credit_rating Class:buy_computer
# 0 1 3 0 1 0
# 1 1 3 0 0 0
# 2 2 3 0 1 1
# 3 3 2 0 1 1
# 4 3 1 1 1 1
# 5 3 1 1 0 0
# 6 2 1 1 0 1
# 7 1 2 0 1 0
# 8 1 1 1 1 0
# 9 3 2 1 1 1
# 10 1 2 1 0 1
# 11 2 2 0 0 1
# 12 2 3 1 1 1
# 13 3 2 0 0 0
print(buyData.shape)#(14, 5)
print(buyData.ndim) #2
# print(buyData.dtype)
print(buyData.info())
# RangeIndex: 14 entries, 0 to 13
# Data columns (total 5 columns):
# age 14 non-null int64
# income 14 non-null int64
# student 14 non-null int64
# credit_rating 14 non-null int64
# Class:buy_computer 14 non-null int64
# dtypes: int64(5)
# memory usage: 640.0 bytes
print(buyData.head())
# age income student credit_rating Class:buy_computer
# 0 1 3 0 1 0
# 1 1 3 0 0 0
# 2 2 3 0 1 1
# 3 3 2 0 1 1
# 4 3 1 1 1 1
print(buyData.index) #RangeIndex(start=0, stop=14, step=1)
print(buyData.columns)
#Index(['age', 'income', 'student', 'credit_rating', 'Class:buy_computer'], dtype='object')
#2.数据处理
X=buyData.drop(labels="Class:buy_computer",axis=1)
y=buyData["Class:buy_computer"]
#3.特征工程
#数据集切分
from sklearn.model_selection import train_test_split
X_train,X_test,y_train,y_test=train_test_split(X,y,random_state=22,test_size=0.2)
# print(X_train.shape)
# print(X_test.shape)
# print(y_train.shape)
# print(y_test.shape)
#4.建立决策树模型
from sklearn.tree import DecisionTreeClassifier
dtc=DecisionTreeClassifier(criterion="entropy",max_depth=6,min_samples_leaf=2)#超参数
dtc.fit(X_train,y_train)
#5.模型预测
y_pred=dtc.predict(X_test)
print(y_pred) #[0 1 1]
#6.模型校验
print("model in trainset score is %.2f"%(dtc.score(X_train,y_train)))
print("model in trainset score is %.2f"%(dtc.score(X_test,y_test)))
# model in trainset score is 0.82
# model in trainset score is 0.67
from sklearn.metrics import confusion_matrix,classification_report
print("confusion matrix:",confusion_matrix(y_test,y_pred))
print("conputetion matrix:",classification_report(y_test,y_pred))
#7.保存模型
from sklearn.externals import joblib
joblib.dump(dtc,"buy.pkl")
#8.模型可视化
from sklearn.tree import export_graphviz
export_graphviz(dtc,out_file="buy.dot",feature_names=X.columns,class_names=["no","yes"],
filled=True)
import pandas as pd
#1.导入数据、
buyData=pd.read_csv("buy.csv",sep=",")
#2.数据处理
X=buyData.drop(labels="Class:buy_computer",axis=1)
y=buyData["Class:buy_computer"]
#3.特征工程
#数据集切分
from sklearn.model_selection import train_test_split
X_train,X_test,y_train,y_test=train_test_split(X,y,random_state=22,test_size=0.2)
#4.读取模型
from sklearn.externals import joblib
dtc=joblib.load("buy.pkl")
#5.模型预测
y_pred=dtc.predict(X_test)
print(y_pred) #[0 1 1]
#6.模型校验
print("model in trainset score is %.2f"%(dtc.score(X_train,y_train)))
print("model in trainset score is %.2f"%(dtc.score(X_test,y_test)))
# model in trainset score is 0.82
# model in trainset score is 0.67
from sklearn.metrics import confusion_matrix,classification_report
print("confusion matrix:",confusion_matrix(y_test,y_pred))
print("conputetion matrix:",classification_report(y_test,y_pred))
dot -Tpdf .\buy.dot -o buy.pdf
import pandas as pd
file=pd.read_csv("./SklearnTest.txt")
#数据处理--is_date=
new_Date=file.query("is_date==-1")
data=file.query("is_date!=-1")
# print(new_Date)
# height house car handsome job is_date
# 8 1.65 0 1 6.6 0 -1
# print(data)
# height house car handsome job is_date
# 0 1.80 1 0 6.5 2 1
# 1 1.62 1 0 5.5 0 1
# 2 1.71 0 1 8.5 1 1
# 3 1.58 1 1 6.3 1 1
# 4 1.68 0 1 5.1 0 0
# 5 1.63 1 0 5.3 1 0
# 6 1.78 0 0 4.5 0 0
# 7 1.64 0 0 7.8 2 0
#2.将data已经处理好的数据分为X和y
X=data.drop("is_date",axis=1)
y=data["is_date"]
#3.进行切分
from sklearn.model_selection import train_test_split
#random_state=9随机数种子,如果指定随机数种子,保证每次切分的时候结果的可重复性
X_train,X_test,y_train,y_test=train_test_split(X,y,test_size=0.2,random_state=9)
#4.训练模型
from sklearn.tree import DecisionTreeClassifier
dtc=DecisionTreeClassifier()
dtc.fit(X_train,y_train)
print(dtc.feature_importances_)
#5.预测
y_pred=dtc.predict(X_test)
print(y_test)
#6.校验
print("model in train set score is:",dtc.score(X_train,y_train))
print("model in test set score is:",dtc.score(X_test,y_test))
from sklearn.metrics import classification_report,confusion_matrix
print("classification_report score is:",classification_report(y_test,y_pred))
print("confusion_matrix score is:",confusion_matrix(y_test,y_pred))
#可视化
from sklearn.tree import export_graphviz
export_graphviz(dtc,out_file="love.dot",feature_names=X.columns,filled=True,class_names=["no","yes"])
通过Graphviz 的地址下载该软件:http://www.graphviz.org/ , 配置本地环境变量,通过命令dot -Tpdf iris.dot -o outpu.pdf
将dot文件转化至pdf可视化决策树。
class_names=["is_date:no","is_date:yes"]
,这里为什么指定no代表0,yes代表1呢?这是因为在class_names中默认以数值递增的顺序进行对应,也是就是0对应is_date:no.
import pandas as pd
#加载数据
love_file=pd.read_csv("./SklearnTest.txt")
#数据集(切分为训练集和测试集)和新数据
data,newData=love_file.query("is_date!=-1"),love_file.query("is_date==-1")
#将数据集切分成X特征和Y类别标签
X_data=data.drop(["is_date"],axis=1)
y_data=data["is_date"]
#切分数据集
from sklearn.cross_validation import train_test_split
#random——state随机数种子-保证每一次切分数据集结果可重复性
X_train, X_test, y_train, y_test = train_test_split(X_data, y_data, test_size=0.33, random_state=1)
#建立决策树模型
from sklearn.tree import DecisionTreeClassifier
dtc=DecisionTreeClassifier(criterion="entropy")
#训练模型使用的是fit方法---训练模型
print(dtc.fit(X_train,y_train))
#预测新数据的结果
y_pred=dtc.predict(X_test)
#模型校验
print("model in train set score:",dtc.score(X_train,y_train))
print("model in test set score:",dtc.score(X_test,y_test))
# model in train set score: 1.0
# model in test set score: 0.3333333333333333
from sklearn.metrics import confusion_matrix
print(confusion_matrix(y_test,y_pred))
#新数据
X_new_data=newData.drop(["is_date"],axis=1) #y_new_data
print(dtc.predict(X_new_data))
#可视化处理
from sklearn.tree import export_graphviz
export_graphviz(dtc.tree_,out_file="love.dot",filled=True,feature_names=love_file.columns,class_names=["no","yes"])
import pandas as pd
#加载数据
love_file=pd.read_csv("./SklearnTest.txt")
#1.数据集(切分为训练集和测试集)和新数据
data,newData=love_file.query("is_date!=-1"),love_file.query("is_date==-1")
#将数据集切分成X特征和Y类别标签
X_data=data.drop(["is_date"],axis=1)
y_data=data["is_date"]
#2.切分数据集
from sklearn.cross_validation import train_test_split
#random——state随机数种子-保证每一次切分数据集结果可重复性
X_train, X_test, y_train, y_test = train_test_split(X_data, y_data, test_size=0.33, random_state=1)
#3.数据处理
from sklearn.preprocessing import StandardScaler
sc=StandardScaler()
#对训练数据集先进行fit操作在进行transfrom操作
#fit操作相当于收集所有参数信息,transfrom将所有的数据减去均值除以方差
X_train_std=sc.fit_transform(X_train)
#对于测试数据集来讲只需要使用transform方法进行归一化
X_test_std=sc.transform(X_test)
#4.建立决策树模型
from sklearn.tree import DecisionTreeClassifier
dtc=DecisionTreeClassifier(criterion="entropy")
#训练模型使用的是fit方法---训练模型
print(dtc.fit(X_train_std,y_train))
#5.预测新数据的结果
y_pred=dtc.predict(X_test)
#6.模型校验
print("model in train set score:",dtc.score(X_train_std,y_train))
print("model in test set score:",dtc.score(X_test_std,y_test))
from sklearn.datasets import load_iris
iris=load_iris()
#打印iris的基础信息
print(iris.keys()) #dict_keys(['data', 'target', 'target_names', 'DESCR', 'feature_names'])
print(iris.data)
# [5.8 2.7 5.1 1.9]
# [6.8 3.2 5.9 2.3]
# [6.7 3.3 5.7 2.5]
# [6.7 3. 5.2 2.3]
# [6.3 2.5 5. 1.9]
# [6.5 3. 5.2 2.]
import numpy as np
print(np.unique(iris.target))
print(iris.target_names)#['setosa' 'versicolor' 'virginica']
print(iris.DESCR)#
print(iris.feature_names)#['sepal length (cm)', 'sepal width (cm)', 'petal length (cm)', 'petal width (cm)']
# Data Set Characteristics:
# :Number of Instances: 150 (50 in each of three classes)
# :Number of Attributes: 4 numeric, predictive attributes and the class
# :Attribute Information:
# - sepal length in cm
# - sepal width in cm
# - petal length in cm
# - petal width in cm
# - class:
# - Iris-Setosa
# - Iris-Versicolour
# - Iris-Virginica
# :Summary Statistics:
#选择特征和标签
X=iris.data
y=iris.target
#切分数据
from sklearn.model_selection import train_test_split
X_train,X_test,y_train,y_test=train_test_split(X,y,random_state=22,test_size=0.2)
#训练模型
from sklearn.tree import DecisionTreeClassifier
dtc=DecisionTreeClassifier()
#训练
dtc.fit(X_train,y_train)
print(dtc.feature_importances_)#[0.01672241 0. 0.59033215 0.39294544]
#预测
y_pred=dtc.predict_proba(X_test)
print(y_pred)
#验证
print("model in train set score is:",dtc.score(X_train,y_train))
print("model in test set score is:",dtc.score(X_test,y_test))
# model in train set score is: 1.0
# model in test set score is: 0.8666666666666667
#可视化
from sklearn.tree import export_graphviz
export_graphviz(dtc,out_file="iris.dot",filled=True,
class_names=iris.target_names,
feature_names=['sepal length (cm)', 'sepal width (cm)', 'petal length (cm)', 'petal width (cm)'],)
features_importance_(重要)
fit\predict\predict_log_porba\predict_proba
API参数详解 :
(1)criterion:一个字符串,指定切分质量的评价准则。可以为如下两个参数:
Gini:表示切分时评价准则时Gini系数。
Entropy:表示切分的时候评价准则是信息增益
(2)splitter:一个字符串,指定切分原则,可以为如下:
best:表示选择最优的切分
random:表示随机切分
(3)max_features:可以为整数、浮点、字符串或者None,指定了寻找best split时考虑的特征数量。
如果是整数,则每次切分只考虑max_features个特征。
如果是浮点数,则每次切分只考虑max_features*n_features个特征。
如果是字符串auto或者sqrt,则max_features等于sqrt(n_feautures)
如果是字符串log2,则max_features等于log2(n_features)
如果是none,则max_features等于n_features.
(4)max_depth:可以为整数或者None,指定树的最大深度。
如果为None,则表示树的深度不限(直到每个叶子都是纯的,即叶子结点中所有的样本点都属于一个类,或者叶子中包含小于min_samples_split个样本点。
(5)min_samples_split:为整数,指定每个内部节点(非叶子节点)包含的最少样本数。
(6)min_samples_leaf为整数,指定每个叶子节点包含的最少的样本数。
(7)min_weight_fraction_leaf:为浮点数,叶子结点中样本的最小权重系数。
(8)min_leaf_nodes:为整数或None,指定最大的叶节点数量。
如果为None,此时叶子节点数量不限制。
如果为非None,则max_depth被忽略。
(9)class_weight:为一个字典、字典的列表、字符串‘balanced’,或者None,它指定了分类的权重。权重的形式为:{class_label:weight}
如果是None,则每个分类的权重都为1.
字符串balanced表示分类权重是样本中各分类出现频率的反比。
(10)random_state:一个整数或者一个Randomstate实例,或者None。
如果为整数,则它指定了随机数生成器的种子。
如果为Randomstate实例,则指定了随机数生成器。
如果为None,则使用默认的随机数生成器。
(11)presort:一个布尔值,指定是否提前排序数据,从而加速寻找最优切分的过程。设置为True时,对于大数据集会减慢总体的训练过程;但是对于一个小数据集或者设定了最大深度的情况下,会加速训练过程。
API的属性详解:
(1)classes_:分类的标签值
(2)feature_importances_:给出了特征的重要程度。该值越高,则特征越重要(也称之为Gini_importance)
(3)max_feature_:max_feature的推断值。
(4)n_classes_:给出了分类的数量
(5)n_feautures_:执行fit之后特征的数量
(6)n_outputs_:执行fit之后输出的数量
(7)tree_(tree):一个Tree对象,即底层的决策树。
API的方法详解 :
(1)fit(X,y):训练模型
(2)predict(X,)用模型进行预测,返回预测值
(3)predict_log_proba(X):返回一个数组,数组的元素依次是X预测为各个类别的概率的对数值。
(4)predict_proba(X):返回一个数组,数组的元素依次时X预测为各个类别的概率值。
(5)score(X,y):返回在(X,y)上预测的准确率(accurary)的平均值。
from numpy import *
import math
import copy
import cPickle as pickle
class ID3DTree(object):
def __init__(self):
self.tree={}
self.dataSet=[]
self.labels=[]
def loadDataSet(self,path,labels):
recordlist = []
fp = open(path,"rb") # 读取文件内容
content = fp.read()
fp.close()
rowlist = content.splitlines() # 按行转换为一维表
recordlist=[row.split("\t") for row in rowlist if row.strip()]
self.dataSet = recordlist
self.labels = labels
def train(self):
labels = copy.deepcopy(self.labels)
self.tree = self.buildTree(self.dataSet,labels)
# 创建决策树主程序
def buildTree(self,dataSet,labels):
cateList = [data[-1] for data in dataSet] # 抽取源数据集的决策标签列
# 程序终止条件1: 如果classList只有一种决策标签,停止划分,返回这个决策标签
if cateList.count(cateList[0]) == len(cateList):
return cateList[0]
# 程序终止条件2: 如果数据集的第一个决策标签只有一个 返回这个决策标签
if len(dataSet[0]) == 1:
return self.maxCate(cateList)
# 算法核心:
bestFeat = self.getBestFeat(dataSet) # 返回数据集的最优特征轴:
bestFeatLabel = labels[bestFeat]
tree = {bestFeatLabel:{}}
del(labels[bestFeat])
# 抽取最优特征轴的列向量
uniqueVals = set([data[bestFeat] for data in dataSet]) # 去重
for value in uniqueVals:
subLabels = labels[:] #将删除后的特征类别集建立子类别集
splitDataset = self.splitDataSet(dataSet, bestFeat, value) # 按最优特征列和值分割数据集
subTree = self.buildTree(splitDataset,subLabels) # 构建子树
tree[bestFeatLabel][value] = subTree
return tree
#计算出现最多的列别标签
def maxCate(self,catelist): # 计算出现最多的类别标签
items = dict([(catelist.count(i), i) for i in catelist])
return items[max(items.keys())]
#计算最优特征
def getBestFeat(self,dataSet):
# 计算特征向量维,其中最后一列用于类别标签,因此要减去
numFeatures = len(dataSet[0]) - 1 # 特征向量维数=行向量维度-1
baseEntropy = self.computeEntropy(dataSet) # 基础熵:源数据的香农熵
bestInfoGain = 0.0; # 初始化最优的信息增益
bestFeature = -1 # 初始化最优的特征轴
# 外循环:遍历数据集各列,计算最优特征轴
# i 为数据集列索引:取值范围 0~(numFeatures-1)
for i in xrange(numFeatures): # 抽取第i列的列向量 uniqueVals = set([data[i] for data in dataSet]) # 去重:该列的唯一值集 newEntropy = 0.0 # 初始化该列的香农熵
for value in uniqueVals: # 内循环:按列和唯一值计算香农熵 subDataSet = self.splitDataSet(dataSet, i, value) # 按选定列i和唯一值分隔数据集
prob = len(subDataSet)/float(len(dataSet))
newEntropy += prob * self.computeEntropy(subDataSet) infoGain = baseEntropy - newEntropy # 计算最大增益
if (infoGain > bestInfoGain): # 如果信息增益>0; bestInfoGain = infoGain
# 用当前信息增益值替代之前的最优增益值 bestFeature = i # 重置最优特征为当前列
return bestFeature
#计算信息熵
def computeEntropy(self,dataSet): # 计算香农熵
datalen = float(len(dataSet))
cateList = [data[-1] for data in dataSet] # 从数据集中得到类别标签
items = dict([(i,cateList.count(i)) for i in cateList])
# 得到类别为key,出现次数value的字典
infoEntropy = 0.0 # 初始化香农熵 for key in items: # 计算香农熵
prob = float(items[key])/datalen
infoEntropy -= prob * math.log(prob,2) # 香农熵:= - p*log2(p) --infoEntropy = -prob * log(prob,2)
return infoEntropy
# 分隔数据集:删除特征轴所在的数据列,返回剩余的数据集
# dataSet:数据集; axis:特征轴; value:特征轴的取值
def splitDataSet(self, dataSet, axis, value):
rtnList = []
for featVec in dataSet:
if featVec[axis] == value:
rFeatVec = featVec[:axis]
# list操作 提取0~(axis-1)的元素
rFeatVec.extend(featVec[axis+1:])
# list操作 将特征轴(列)之后的元素加回
rtnList.append(rFeatVec)
return rtnList
#决策树分类器代码
def predict(self,inputTree,featLabels,testVec): # 分类器
root = inputTree.keys()[0] # 树根节点
secondDict = inputTree[root] # value-子树结构或分类标签
featIndex = featLabels.index(root) # 根节点在分类标签集中的位置
key = testVec[featIndex] # 测试集数组取值
valueOfFeat = secondDict[key] #
if isinstance(valueOfFeat, dict):
classLabel = self.predict(valueOfFeat, featLabels, testVec) # 递归分类
else: classLabel = valueOfFeat
return classLabel
# 存储树到文件
def storeTree(self,inputTree,filename):
fw = open(filename,'w')
pickle.dump(inputTree,fw)
fw.close()
# 从文件抓取树
def grabTree(self,filename):
fr = open(filename)
return pickle.load(fr)
import sys
import os
from numpy import *
# 设置utf-8 unicode环境
reload(sys)
sys.setdefaultencoding('utf-8')
#构建输入的数据集
labels=["年龄","收入","学生","信誉"]
dataset = [[0,0,0,0,"no"],[0,0,0,1,"no"],[0,1,0,0,"no"],[0,2,1,0,"yes"],[0,1,1,1,"yes"],
[1,0,0,0,"yes"],[1,2,1,1,"yes"], [1,1,0,1,"yes"],[1,0,1,0,"yes"],[2,1,0,0,"yes"],[2,2,1,0,"yes"],
[2,2,1,1,"no"],[2,1,1,0,"yes"],[2,1,0,1,"no"]]
numlist = [64 ,64 ,128,64 ,64 ,128,64 ,32 ,32 ,60 ,64 ,64 ,132,64 ]
print mat(dataset).T
datalines =[]
for element,num in zip(dataset,numlist):
liststr =""
for cell in element:
liststr += str(cell)+"\t"
liststr = liststr[:-1]
for i in xrange(num):
datalines.append(liststr)
fp = open("dataset.dat","w")
fp.write("\n".join(datalines))
from numpy import *
from math import log
from ID3DTree import *
import copy
import treePlotter2
import matplotlib.pyplot as plt
dtree = ID3DTree()
dtree.loadDataSet("dataset.dat",["age","revenue","student","credit"])
# dtree.loadDataSet("lenses.txt",['age','prescript','astigmatic','tearRate'])
dtree.train()
print dtree.tree
treePlotter2.createPlot(dtree.tree)
from numpy import *
from math import log
from ID3DTree import *
import copy
import treePlotter2
import matplotlib.pyplot as plt
dtree = ID3DTree()
dtree.loadDataSet("dataset.dat",["age","revenue","student","credit"])
dtree.train()
dtree.storeTree(dtree.tree,"data.tree")
mytree = dtree.grabTree("data.tree")
print mytree
from numpy import *
from math import log
from ID3DTree import *
import copy
import treePlotter2
import matplotlib.pyplot as plt
dtree = ID3DTree()
labels = ["age","revenue","student","credit"]
vector = ['0','1','0','0'] # ['0','1','0','0','no']
mytree = dtree.grabTree("data.tree")
print "真实输出 ","no","->","决策树输出",dtree.predict(mytree,labels,vector)
Gini指数(基尼指数) : 选择最佳划分的度量通常是根据划分后子女节点的不纯性的程度决定的。一般最佳划分对应于产生最小Gini指标值得点。
P(i|t)表示给定节点t中属于类i的记录所占的比例。
错误率
以2分类问题为例计算信息熵、基尼不纯度和错误率
节点 | 计数 |
---|---|
类=0 | 1 |
类=1 | 5 |
Gini=1-=0.278
Entropy=-(1/6)log(1/6)-(5/6)log(5/6)=0.650
Error=1-max[1/6,5/6]=0.167
是给定节点的不纯性度量,N是父节点上的记录总数,k是属性值的个数是与子女节点v相关联的记录个数,决策树归纳算法通常选择最大化增益 的测试条件,因为对所有的测试条件来说, 是一个不变的值,所以最大化增益等价于最小化子女节点的不纯性度量的的加权平均值。当选择熵作为不纯性度量时,熵的差就是所谓的信息增益。
底数一般为2或e
两点分布的熵
均匀分布的信息熵
定义概率:
最大熵
熵是随机变量不确定性度量,不确定越大,熵越大
若随机变量退化成定值,熵最小,为0
若随机分布为均匀分布,熵最大
根据上面的分析,P(x)的对数关于随机变量x的二次形式,所以,该分布p(x)必然是正态分布。
Venn图理解几个熵的概念
条件熵
两个随机变量X,Y的联合分布,可以形成联合熵H(X,Y)表示,(X,Y)发生所包含的熵,减去X单独发生的熵,就是在X发生前提下Y发生带来的熵即H(X|Y)=H(X,Y)-H(X)
利用互信息得到条件熵