kNN算法和决策树

  kNN算法

  kNN算法的原理很简单,就是将新数据的特征与样本集中相应的特征进行比较,而后提取将样本集中特征最类似的数据的分类标签做为新数据的标签,通常的,只选取数据集中前k个最类似的元素,所以该算法被称为kNN,一般k取不大于20的整数。数组

  下面看书上给出的实例:app

  from numpy import *ide

  import operator函数

  def createdataset():spa

  group=array([[1.0,1.1],[1.0,1.0],[0,0],[0,0.1]])对象

  labels=['a','a','b','b']排序

  return group,labels索引

  group,labels=createdataset()事务

  def classify(inx,dataset,labels,k):

  datasetsize=dataset.shape[0]

  diffmat=tile(inx,(datasetsize,1)) - dataset

  sqdiffmat=diffmat**2

  sqdistance=sqdiffmat.sum(axis=1)

  distance=sqdistance**0.5 #计算距离,也就是比较特征

  sorteddist=distance.argsort()

  classcount={}

  for i in range(k):

  votelabel=labels[sorteddist[i]]

  classcount[votelabel]=classcount.get(votelabel,0)+1 #为字典classcount建立前k个最近的数据的标签对应出现次数的键值对

  sortedclasscount=sorted(classcount.items(),key=operator.itemgetter(1),reverse=True)

  return sortedclasscount[0][0]

  print(classify([0,0],group,labels,3))

  首先,定义了一个createdataset()函数用来生成数据样本集,而后定义的classify()函数有4个输人参数:用于分类的输人向量是inx,输入的训练样本集为dataset, 标签向量为labels 最后的参数k表示用于选择最近邻居的数目其中标签向量的元素数目和矩 阵如dataset的行数相同。

  dataset.shape[0]返回dataset数组的第二维,也就是二维数组的行数,此例中为4,接下来的tile函数将inx数组的第二维重复了四次,第一维重复一次,也就是将inx数组从一行变成了4行,每一行都是原来的inx数组,这样就与dataset数组的行列数是同样的,用于接下来计算inx与每一个数据样本的距离,这里的sqdiffmat.sum(axis=1)表示每一行的数组求和,这里返回一个长度为4的一维数组,每个元素都是sqdiffmat对应一行的和,下面的argsort()函数将distance中的元素从小到大排列,提取其对应的index(索引),而后输出到sorteddist。

  而后建立了一个空字典classcount,在接下来的for循环中为字典classcount建立了前k个最近的数据的标签对应出现次数的键值对

  接下来有一个sorted函数,它的语法以下:

  sorted(iterable, key=None, reverse=False)

  iterable – 可迭代对象。

  key – 主要是用来进行比较的元素,只有一个参数,具体的函数的参数就是取自于可迭代对象中,指定可迭代对象中的一个元素来进行排序。

  reverse – 排序规则,reverse = True 降序 , reverse = False 升序(默认)。

  items函数返回字典中可遍历的(键, 值) 元组数组。

  operator.itemgetter函数的做用是获取对象哪些维的数据,参数是表示维的序号。

  在这个例子中这个sorted函数的做用就是对字典classcount所生成的元组数组按照标签对应出现的次数进行降序排序,最后整个classify函数返回的sortedclasscount[0][0]就是出现次数最多的标签,以此做为待划分数据的分类标签。最后运行结果为 b 。

  决策树

  决策树伪代码以下:

  检测数据集中的每一个子项是否属于同一分类:

  If so return 类标签;

  Else

  寻找划分数据集的最好特征

  划分数据集

  建立分支节点

  for 每一个划分的子集

  调用决策树函数并增长返回结果到分支节点中

  return 分支节点

  下面根据伪代码一步一步实现

  熵

  在划分数据集以前以后信息发生的变化称为信息增益,知道如何计算信息增益,咱们就能够 计算每一个特征值划分数据集得到的信息增益,得到信息增益最高的特征就是最好的选择,集合信息的度量方式称为香农熵或者简称为熵,熵定义为信息的指望值。

  若是待分类的事务可能划分在多个分类之中, 则符号x的信息定义为 l(x)=-lb(p(x)),p(x)为选择该分类的几率。

  要计算熵,则须要计算全部类别全部可能值包含的信息指望值。下面给出书上的计算熵代码:

  from math import log

  def c_shannon_ent(data_set):

  num_entries=len(data_set)

  label_counts={}

  for feat_vec in data_set:

  current_label=feat_vec[-1]

  if current_label not in label_counts.keys():

  label_counts[current_label]=0

  label_counts[current_label]+=1

  shannon_ent=0.0

  for key in label_counts:

  prob=float(label_counts[key])/num_entries

  shannon_ent-=prob*log(prob,2)

  return shannon_ent

  def create_data_set():

  data_set=[[1,1,'yes'],[1,0,'no'],[0,1,'no'],[1,1,'yes'],[0,1,'no']]

  labels=['no surfacing','flippers']

  return data_set,labels

  my_data,labels=create_data_set()

  print(c_shannon_ent(my_data))

  keys()函数用于返回一个字典全部的键。不难看出label_counts是一个将类别与属于该类别的样本数做为键值对的字典。实际上,对于data_set上的一个随机变量x,x为yes所属类的几率为2/5,x为no的几率为3/5,那么x的熵为-(2/5)*lb(2/5)-(3/5)*lb(3/5),也就是上面代码中计算的data_set的熵。(在这个实例中,yes和no对应的是最终分类标签(是否为鱼),前面的1,0是用于判断的特征数据,因此按照yes和no的分类来计算data_set的熵)熵越高,表明数据的无序程度就越高。

  划分数据集

  先看看书上的对于给定特征划分数据集的代码:

  def split_data_set(data_set,axis,value):

  ret_data_set=[]

  for feat_vec in data_set:

  if feat_vec[axis]==value:

  reduced_feat_vec=feat_vec[:axis]

  reduced_feat_vec.extend(feat_vec[axis+1:])

  ret_data_set.append(reduced_feat_vec)

  return ret_data_set

  这段代码仍是很容易看懂的,首先建立了一个新列表,而后对于符合所输入的特征的数据就截取到 reduced_feat_vec中(把特征值截掉了),而后再将 reduced_feat_vec添入新建的列表ret_data_set中做为一个元素,这样就获得了一个符合所选特征值的数据集ret_data_set。

  选择最好的数据集划分方式

  def choose_best_feature_to_split(data_set):

  num_features=len(data_set[0])-1

  base_entropy=c_shannon_ent(data_set)

  best_info_gain=0.0;best_feature=-1

  for i in range(num_features):

  feat_list=[example[i] for example in data_set]

  unique_vals=set(feat_list)

  new_entropy=0.0

  for value in unique_vals:

  sub_data_set=split_data_set(data_set,i,value)

  prob=len(sub_data_set)/float(len(data_set))

  new_entropy+=prob*c_shannon_ent(sub_data_set)

  info_gain=base_entropy-new_entropy

  if(info_gain>best_info_gain):

  best_info_gain=info_gain

  best_feature=i

  return best_feature

  若是上面都看懂了,那么看懂这一段代码也不会难的。

  首先用一个变量存储特征总数,一个变量存储初始熵,而后每选一个特征,就用一个集合unique_vals存储该特征全部可能的取值,再根据这个对该特征进行分类而且计算分类后的熵,最后计算出信息增益info_gain,而后从全部特征值中找出信息增益最大的一个,输出该特征值。为何找信息增益最大的呢?上面说到在划分数据集以前以后信息发生的变化称为信息增益,也就是划分先后的熵之差,而熵越高,代表无序程度越大,信息增益实际上就是无序程度减小的程度,越大就代表分类后的无序程度越小。

  构建决策树

  def major_cnt(class_list):

  class_count={}

  for vote in class_list:

  if vote not in class_count.keys():class_count[vote]=0

  class_count[vote]+=1

  sorted_class_count=sorted(class_count.items,key=operator.itemgetter,reverse=True)

  return sorted_class_count[0][0]

  def create_tree(data_set,labels):

  class_list=[example[-1] for example in data_set]

  if class_list.count(class_list[0])==len(class_list):

  return class_list[0]

  if len(data_set[0])==1:

  return major_cnt(class_list)

  best_feat=choose_best_feature_to_split(data_set)

  best_feat_label=labels[best_feat]

  my_tree={best_feat_label:{}}

  del(labels[best_feat])

  feat_values=[example[best_feat] for example in data_set]

  unique_vals=set(feat_values)

  for value in unique_vals:

  sub_labels=labels[:]

  my_tree[best_feat_label][value]=create_tree(split_data_set(data_set,best_feat,value),sub_labels)

  return my_tree

  第一个函数和Knn里的一段代码是很类似的,这里再也不多说。

  第二个函数有两个参数:数据集data_set和标签labels,标签对该算法来讲不是必须的,只是能代表数据的内在乎义。

  create_tree中第一个if表示若是数据都是同一类就返回该类别,第二个if表示特征用完后数据仍然不是同一类则返回出现次数最多的分类标签。而后就是选取最好的特征进行分类,再对分好类的数据集执行一样的操做,最后生成整颗树,代码仍是至关简单的。

  最后给出完整的代码:郑州人流价格 http://www.zzzykdfk.com/

  from math import log

  import operator

  def c_shannon_ent(data_set):

  num_entries=len(data_set)

  label_counts={}

  for feat_vec in data_set:

  current_label=feat_vec[-1]

  if current_label not in label_counts.keys():

  label_counts[current_label]=0

  label_counts[current_label]+=1

  shannon_ent=0.0

  for key in label_counts:

  prob=float(label_counts[key])/num_entries

  shannon_ent-=prob*log(prob,2)

  return shannon_ent

  def create_data_set():

  data_set=[[1,1,'yes'],[1,0,'no'],[0,1,'no'],[1,1,'yes'],[0,1,'no']]

  labels=['no surfacing','flippers']

  return data_set,labels

  def split_data_set(data_set,axis,value):

  ret_data_set=[]

  for feat_vec in data_set:

  if feat_vec[axis]==value:

  reduced_feat_vec=feat_vec[:axis]

  reduced_feat_vec.extend(feat_vec[axis+1:])

  ret_data_set.append(reduced_feat_vec)

  return ret_data_set

  def choose_best_feature_to_split(data_set):

  num_features=len(data_set[0])-1

  base_entropy=c_shannon_ent(data_set)

  best_info_gain=0.0;best_feature=-1

  for i in range(num_features):

  feat_list=[example[i] for example in data_set]

  unique_vals=set(feat_list)

  new_entropy=0.0

  for value in unique_vals:

  sub_data_set=split_data_set(data_set,i,value)

  prob=len(sub_data_set)/float(len(data_set))

  new_entropy+=prob*c_shannon_ent(sub_data_set)

  info_gain=base_entropy-new_entropy

  if(info_gain>best_info_gain):

  best_info_gain=info_gain

  best_feature=i

  return best_feature

  def major_cnt(class_list):

  class_count={}

  for vote in class_list:

  if vote not in class_count.keys():class_count[vote]=0

  class_count[vote]+=1

  sorted_class_count=sorted(class_count.items,key=operator.itemgetter,reverse=True)

  return sorted_class_count[0][0]

  def create_tree(data_set,labels):

  class_list=[example[-1] for example in data_set]

  if class_list.count(class_list[0])==len(class_list):

  return class_list[0]

  if len(data_set[0])==1:

  return major_cnt(class_list)

  best_feat=choose_best_feature_to_split(data_set)

  best_feat_label=labels[best_feat]

  my_tree={best_feat_label:{}}

  del(labels[best_feat])

  feat_values=[example[best_feat] for example in data_set]

  unique_vals=set(feat_values)

  for value in unique_vals:

  sub_labels=labels[:]

  my_tree[best_feat_label][value]=create_tree(split_data_set(data_set,best_feat,value),sub_labels)

  return my_tree

  data,labels=create_data_set()

  print(create_tree(data,labels))

  输出结果:{‘no surfacing’:{0:‘no’,1:{‘flippers’:{0:‘no’,1:‘yes’}}}}

相关文章
相关标签/搜索