首页 浪子小说 其它 人工智能

第三节 识别毒蘑菇

人工智能 赵亮 张宁 编著 8500 2024-10-22 04:36

  

  Python的scikit-learn(简称sklearn)模块可以非常好地支持决策树分类,尽管它使用的是更加复杂的决策树算法,但依然是在上一节讲述的原理基础上的优化算法。本节将使用scikit-learn的决策树分类来识别“蘑菇数据”中的毒蘑菇。

  首先介绍本案例使用的数据。原始数据来源于加州大学欧文分校用于机器学习的数据库(UCI数据库),本书使用的是经过必要处理的数据,此数据可从教材资源平台下载。

  接下来在命令行界面安装scikit-learn。

  pip install -u scikit-learn

  安装scikit-learn之前需要确保模块numpy和scipy已经安装,否则可以使用pip install安装。

  pip install -u numpy

  pip install -u scipy

  进入Python之后,使用如下命令调用scikit-learn的决策树方法。

  from sklearn import tree

  模块scikit-learn的决策树是基于DecisionTreeClassifier对象,它能够解决二分类问题(如蘑菇是否可食用),也可以解决多分类问题。在使用中,对输入训练数据的维度要求如下。

  输入X:样本数量×特征属性数量;

  输入Y:样本类别标签,与X要一一对应。

  下面先用一个简单的例子来熟悉使用方法。对四个点X=[[0,0],[0,1],[1,0],[1,1]]使用决策树进行分类,四个点分别属于两个类别0和1,它们对应的类别标签是Y=[0,0,1,1]。这可以通过如下简单代码实现。

  In[1]:from sklearn import tree

  X=[[0,0],[0,1],[1,0],[1,1]]

  Y=[0,0,1,1]

  clf=tree.DecisionTreeClassifier()

  clf=clf.fit(X,Y)

  clf命令用来构造决策树,通过clf.fit(X,Y)实现了决策树的构建,此时clf已经是能够进行分类的决策树了,可以用它来进行新数据的分类。例如,输出[[0.3,0],[0.8,1],[1.2,1]]的类别,代码如下。

  In[2]:test=[[0.3,0],[0.8,1],[1.2,1]]

  In[3]:clf.predict(test)

  Out[3]:array([0,1,1])

  通过上述输出可以看到决策树给出的分类结果是[0.3,0]类别为0;[0.8,1]类别为1;[1.2,1]类别为1。读者可以在平面直角坐标系上画出这些点,看看分类是否合理。

  读者还可以尝试下列与决策树相关的函数,看看它们具有什么功能。

  In[4]:dir(clf)

  Out[4]:

  [……

  'apply',

  'class_weight',

  'classes_',

  'criterion',

  'decision_path',

  'feature_importances_',

  'fit',

  'fit_transform',

  'get_params',

  'max_depth',

  'max_features',

  'max_features_;,

  'max_leaf_nodes',

  'min_impurity_split',

  'min_samples_leaf',

  'min_samples_split',

  'min_weight_fraction_leaf',

  'n_classes_',

  'n_features_',

  'n_outputs_',

  'predict',

  'predict_log_proba',

  'predict_proba',

  'presort',

  'random_state',

  'score',

  'set_params',

  'splitter',

  'transform',

  'tree_']

  下面开始进行蘑菇分类。本书提供的蘑菇数据如表3-5所示,包含样本编号和特征属性,其中第一行是类别标记及属性名称,第一列为样本编号。

  表3-5

  该表共包含8 123条数据,特征属性共有22个,这些属性及其对应的取值含义如下所示。

  类别标记:

  毒蘑菇,poisonous,p

  可食用,edible,e

  特征属性及取值

  1.cap-shape:bell=b,conical=c,convex=x,flat=f,knobbed=k,sunken=s

  2.cap-surface:fibrous=f,grooves=g,scaly=y,smooth=s

  3.cap-color:brown=n,buff=b,cinnamon=c,gray=g,green=r,pink=p,purple=u,red=e,white=w,yellow=y

  4.bruises:bruises=t,no=f

  5.odor:almond=a,anise=l,creosote=c,fishy=y,foul=f,musty=m,none=n,pungent=p,spicy=s

  6.gill-attachment:attached=a,descending=d,free=f,notched=n

  7.gill-spacing:close=c,crowded=w,distant=d

  8.gill-size:broad=b,narrow=n

  9.gill-color:black=k,brown=n,buff=b,chocolate=h,gray=g,green=r,orange=o,pink=p,purple=u,red=e,white=w,yellow=y

  10.stalk-shape:enlarging=e,tapering=t

  11.stalk-root:bulbous=b,club=c,cup=u,equal=e,rhizomorphs=z,rooted=r,missing=?

  12.stalk-surface-above-ring:fibrous=f,scaly=y,silky=k,smooth=s

  13.stalk-surface-below-ring:fibrous=f,scaly=y,silky=k,smooth=s

  14.stalk-color-above-ring:brown=n,buff=b,cinnamon=c,gray=g,orange=o,pink=p,red=e,white=w,yellow=y

  15.stalk-color-below-ring:brown=n,buff=b,cinnamon=c,gray=g,orange=o,pink=p,red=e,white=w,yellow=y

  16.veil-type:partial=p,universal=u

  17.veil-color:brown=n,orange=o,white=w,yellow=y

  18.ring-number:none=n,one=o,two=t

  19.ring-type:cobwebby=c,evanescent=e,flaring=f,large=l,none=n,pendant=p,sheathing=s,zone=z

  20.spore-print-color:black=k,brown=n,buff=b,chocolate=h,green=r,orange=o,purple=u,white=w,yellow=y

  21.population:abundant=a,clustered=c,numerous=n,scattered=s,several=v,solitary=y

  22.habitat:grasses=g,leaves=l,meadows=m,paths=p,urban=u,waste=w,woods=d

  首先使用pandas读取数据,这是一个强大的数据处理工具。通过显示数据形状可以看到共有8 124行、24列。

  In[5]:import pandas as pd

  import numpy as np

  In[6]:data=pd.read_excel('mushroom.xlsx',header=0)

  In[7]:data.shape

  Out[7]:(8124,24)

  使用如下命令观察前5行数据。

  In[8]:data.head(5)

  Out[8]:

  样本编号标记属性1 属性2 属性3 属性4 属性5 属性6 属性7 属性8 ...

  属性13 属性14 属性15 属性16 属性17 属性18\

  0 1.0 p x s n t p f c n ...s w w p w o

  1 2.0 e x s y t a f c b ...s w w p w o

  2 3.0 e b s w t l f c b ...s w w p w o

  3 4.0 p x y w t p f c n ...s w w p w o

  4 5.0 e x s g f n f w b ...s w w p w o

  属性19 属性20 属性21 属性22

  0 p k s u

  1 p n n g

  2 p n n m

  3 p k s u

  4 e n a g

  [5 rows x 24 columns]

  进行数据拆分,获得输入数据X和对应的类别标记Y,这个过程是为了准备训练数据。用以下代码获取类别标记。

  In[9]:label=data['标记']

  #读取标记列

  In[10]:label=np.array(label)

  #转化成数组,这是Python最常使用的数据格式

  In[11]:label.shape

  Out[11]:(8124,)

  #获得标记的个数。实际标记是8123个,需要剔除最后一个' '标记

  In[12]:label=label[0:-1]

  #获得8123个标记

  因为用来表示类别的“e”和“p”是英文字母,所以需要转化成1和0以便计算机使用,其中1表示可食用,0表示有毒。使用以下代码完成转化,这是一个循环程序。

  In[13]:for i in range(0,8123):

  if label[i]=='e':

  label[i]=1

  else:

  label[i]=0

  接下来就可以设置Y数据了。

  In[14]:Y=label

  In[15]:Y=Y.astype(Y)

  接下来处理训练样本。

  In[16]:data=data.drop(['样本编号','标记'],axis=1)

  #训练样本需要将两列去掉(样本编号和标记)

  In[17]:data.shape

  Out[17]:(8124,22)

  #训练样本的行列数量

  In[18]:newdata=np.array(data)

  In[19]:newdata=newdata[0:-1,:]

  #去掉最后一行

  In[20]:newdata.shape

  Out[20]:(8123,22)

  #新的数据

  特征属性的值同样是用字符表示的,而Python的决策树需要对数值进行处理。所以接下来使用下面的编码将字符直接转化成ASCII编码的整数。表3-6中的最后一列是通常的字符,前两列分别是这个字符的十进制编码和十六进制编码。

  表3-6

  使用下面的代码将字符转化成它对应的整数。如g转化为103,O转化为79等。这是一个循环程序,其中的ord( )函数负责转化功能。

  In[21]:for i in range(0,8123):

  for j in range(0,22):

  newdata[i,j]=ord(newdata[i,j])

  新的训练数据为

  In[22]:X=newdata

  接下来就可以构造决策树并用于分类了,输出的是描述所生成的决策树的参数。

  In[23]:clf=tree.DecisionTreeClassifier()

  In[24]:clf.fit(X,Y)

  Out[24]:

  DecisionTreeClassifier(class_weight=None,criterion='gini',

  max_depth=None,

  max_features=None,max_leaf_nodes=None,

  min_impurity_split=1e-07,min_samples_leaf=1,

  min_samples_split=2,min_weight_fraction_leaf=0.0,

  presort=False,random_state=None,splitter='best')

  使用决策树用于新数据的分类,可以看到对下列4个新的蘑菇数据进行分类后,输出结果表明其中有3种是可食用的,1种是有毒的。

  In[25]:test=np.anay([[…],[…],[…],[…]])

  np.anay([[120,115,121,...,110,110,103],

  [98,115,119,...,110,110,109],

  [120,121,119,...,107,115,117],

  [120,115,103,...,110,97,103]])

  In[26]:clf.predict(test)

  Out[26]:array([1,1,0,1])

  这个决策树的准确率如何呢?一种简单的方法是使用训练数据中的X,用决策树获得对应的类别标记,也就是预测分类结果(这里用Y_predict表示),然后把它和实际的类别标记Y进行比较。scikit-learn支持这样的比较,使用的方法是accuracy_score。

  In[27]:from sklearn.metrics import accuracy_score

  In[28]:Y_predict=clf.predict(X)

  #这里使用前面训练好的决策树,输入训练样本的X,给出对应的predict

  In[29]:accuracy_score(Y,Y_predict)

  #这里利用accuracy_score来比较预测值和真实值。

  Out[29]:1.0

  可以看到这个决策树在训练数据上的准确率是100%(1.0)。这表明使用上述算法构建的决策树完全捕捉了训练数据的分类信息。这也许是因为训练出的决策树确实具有很好的分类效果,但也有可能并不是真正的分类准确率,而是发生了过拟合现象。

  为了更好地评估分类准确率,需要使用与训练数据不同的测试数据。可以抽取全部数据中的一部分作为训练数据,另一部分作为测试数据,使用抽取出的训练数据来构建决策树,然后使用测试数据评估准确率。这可以通过如下方式来实现。

  In[30] from sklearn.model_selection import train_test_split

  In[31]:X_train,X_test,Y_train,Y_test=train_test_split

  (X,Y,test_size=0.2)

  #这里将全部样本分成两部分,其中训练样本占80%,测试样本占20%,这

  #里采用了随机分割样本的方法,所以读者的输出可能与下面的结果不同

  In[32]:newclf=tree.DecisionTreeClassifier()

  In[33]:newclf.fit(X_train,Y_train)

  #利用训练数据来构建决策树

  Out[33]:

  DecisionTreeClassifier(class_weight=None,criterion='gini',

  max_depth=None,

  max_features=None,max_leaf_nodes=None,

  min_impurity_split=1e-07,min_samples_leaf=1,

  min_samples_split=2,min_weight_fraction_leaf=0.0,

  presort=False,random_state=None,splitter='best')

  #返回新的决策树的参数

  In[34]:Y_predict=newclf.predict(X_test)

  #注意,这里是将新训练的决策树用在测试样本的X上,并预测出对应Y

  In[35]:accuracy_score(Y_test,Y_predict)

  Out[35]:1.0

  可以看到在测试集上的准确率仍然是100%,这说明这个分类器确实具有很高的准确率。因为测试数据和训练数据是采用随机划分的方式获得的,读者最后获得的输出结果可能会与此不同。

  从上述内容可以看出,决策树实现起来简单并且效果很好。本书采用最简单的形式实现这个算法,scikit-learn的决策树有很多参数可以调整,读者可以尝试调整决策树的参数,观察分类性能会发生什么改变。

  

目录
设置
手机
书架
书页
简体
评论