2.6 多类别分类问题:它属于哪种玻璃
多类别分类问题与二元分类问题类似,不同之处在于它有几个离散的输出,而不是只有两个。回顾探测未爆炸的水雷的问题,它的输出只有两种可能性:声纳探测的物体是岩石或者水雷。而红酒口感评分问题根据其化学成分会产生几个可能的输出(其口感评分值是从3分到8分)。但是对于红酒口感评分问题,口感评分值存在有序的关系。打5分的红酒要好于打3分的,但是要劣于打8分的。对于多类别分类问题,输出结果是不存在这种有序关系的。
此节将根据玻璃的化学成分来判断玻璃的类型,目标是确定玻璃的用途。玻璃的用途包括建筑房间用玻璃、车辆上的玻璃、玻璃容器等。确定玻璃的用途类型是为了鉴证。例如在一个车祸或犯罪现场,会有玻璃的碎片,确定这些玻璃碎片的用途、来源,有助于确定谁是过错方或者谁是罪犯。代码清单2-16为生成玻璃数据集的统计信息的代码。图2-20为归一化玻璃数据的箱线图,箱线图显示有相当数量的异常点。
代码清单2-16 玻璃数据集的统计信息-glassSummary.py
__author__ = 'mike_bowles'
import pandas as pd
from pandas import DataFrame
from pylab import *
import matplotlib.pyplot as plot
target_url = ("https://archive.ics.uci.edu/ml/machine-"
"learning-databases/glass/glass.data")
glass = pd.read_csv(target_url,header=None, prefix="V")
glass.columns = ['Id', 'RI', 'Na', 'Mg', 'Al', 'Si',
'K', 'Ca', 'Ba', 'Fe', 'Type']
print(glass.head())
#generate statistical summaries
summary = glass.describe()
print(summary)
ncol1 = len(glass.columns)
glassNormalized = glass.iloc[:, 1:ncol1]
ncol2 = len(glassNormalized.columns)
summary2 = glassNormalized.describe()
for i in range(ncol2):
mean = summary2.iloc[1, i]
sd = summary2.iloc[2, i]
glassNormalized.iloc[:,i:(i + 1)] = \
(glassNormalized.iloc[:,i:(i + 1)] - mean) / sd
array = glassNormalized.values
boxplot(array)
plot.xlabel("Attribute Index")
plot.ylabel(("Quartile Ranges - Normalized "))
show()
Output: [filename - ]
print(glass.head())
Id RI Na Mg Al Si K Ca Ba Fe Type
0 1 1.52101 13.64 4.49 1.10 71.78 0.06 8.75 0 0 1
1 2 1.51761 13.89 3.60 1.36 72.73 0.48 7.83 0 0 1
2 3 1.51618 13.53 3.55 1.54 72.99 0.39 7.78 0 0 1
3 4 1.51766 13.21 3.69 1.29 72.61 0.57 8.22 0 0 1
4 5 1.51742 13.27 3.62 1.24 73.08 0.55 8.07 0 0 1
print(summary) - Abridged
Id RI Na Mg Al
count 214.000000 214.000000 214.000000 214.000000 214.000000
mean 107.500000 1.518365 13.407850 2.684533 1.444907
std 61.920648 0.003037 0.816604 1.442408 0.499270
min 1.000000 1.511150 10.730000 0.000000 0.290000
25% 54.250000 1.516523 12.907500 2.115000 1.190000
50% 107.500000 1.517680 13.300000 3.480000 1.360000
75% 160.750000 1.519157 13.825000 3.600000 1.630000
max 214.000000 1.533930 17.380000 4.490000 3.500000
K Ca Ba Fe Type
count 214.000000 214.000000 214.000000 214.000000 214.000000
mean 0.497056 8.956963 0.175047 0.057009 2.780374
std 0.652192 1.423153 0.497219 0.097439 2.103739
min 0.000000 5.430000 0.000000 0.000000 1.000000
25% 0.122500 8.240000 0.000000 0.000000 1.000000
50% 0.555000 8.600000 0.000000 0.000000 2.000000
75% 0.610000 9.172500 0.000000 0.100000 3.000000
max 6.210000 16.190000 3.15000 0 0.510000 7.000000```
<div style="text-align: center"><img src="https://yqfile.alicdn.com/8840bbbaa931259fed4a2bd382e44a55531acf50.png" width="" height="">
</div>
玻璃数据的箱线图显示有相当数量的异常点,至少与前面的例子相比,异常点数量上是比较多的。玻璃数据集有几个因素可能会导致出现异常点。首先这是一个分类问题,在属性值和类别之间不需要存在任何连续性,也就是说不应期望在各种类别之间,属性值是相互接近的、近似的。另外一个玻璃数据比较独特的地方是它的数据是非平衡的。成员最多的类有76个样本,而成员最小的类只有9个样本。统计时,平均值可能是由成员最多的那个类的属性值决定,因此不能期望其他的类别也有相似的属性值。采取激进的方法来区分类别可能会达到较好的结果,但这也意味着预测模型需要跟踪不同类别之间复杂的边界。在第3章可以了解到,如果给定足够多的数据,集成方法可以比惩罚线性回归方法产生更复杂的决策边界。而在第5、第7章可以看到哪种方法可以获得更好的效果。
平行坐标图可能对此数据集揭示的信息更多。图2-21为其平行坐标图。数据根据输出类别用不同的颜色标记。有些类别区分度很好。例如,深蓝色的线聚集度很好,在某些属性上与其他类别的区分度也很好。深蓝的线在某些属性上经常处于数据的边缘,也就是说,是这些属性上的异常点。浅蓝的线在某些属性上也与深蓝的线一样,处于边缘地带,但是数量上要比深蓝的少,而且两者都在边缘地带时的所属的属性也不尽相同。棕色的线聚集性也很好,但其取值基本上在中心附近。
<div style="text-align: center"><img src="https://yqfile.alicdn.com/12a7f264e8e5791d4cda46d6f38b3bddad43428a.png" width="" height="">
</div>
代码清单2-17为产生玻璃数据的平行坐标图的代码。针对岩石vs.水雷问题,平行坐标图的线用2种颜色代表了2种目标类别。在回归问题(红酒口感评分、鲍鱼预测年龄),标签(目标类别)取实数值,平行坐标图的线取一系列不同的颜色。在多类别分类问题中,每种颜色代表一种类别,共有6种类别,6种颜色。标签是1~7,没有4。颜色的选择与回归问题中的方式类似:将目标类别(标签)除以其最大值,然后再基于此数值选择颜色。图2-22为玻璃数据的关联热图。关联热图显示了属性之间绝大多数是弱相关的,说明属性之间绝大多数是相互独立的,这是件好事情。标签(目标类别)没有出现在热图中,因为目标(类别)只取几个离散值中的一个。不包括目标类别无疑减少了关联热图所能揭示的信息。
代码清单2-17 玻璃数据的平行坐标图-glassParallelPlot.py
author = 'mike_bowles'
import pandas as pd
from pandas import DataFrame
from pylab import *
import matplotlib.pyplot as plot
target_url = ("https://archive.ics.uci.edu/ml/machine-"
"learning-databases/glass/glass.data")
glass = pd.read_csv(target_url,header=None, prefix="V")
glass.columns = ['Id', 'RI', 'Na', 'Mg', 'Al', 'Si',
'K', 'Ca', 'Ba', 'Fe', 'Type']
glassNormalized = glass
ncols = len(glassNormalized.columns)
nrows = len(glassNormalized.index)
summary = glassNormalized.describe()
nDataCol = ncols - 1
normalize except for labels
for i in range(ncols - 1):
mean = summary.iloc[1, i]
sd = summary.iloc[2, i]
glassNormalized.iloc[:,i:(i + 1)] = \
(glassNormalized.iloc[:,i:(i + 1)] - mean) / sd
Plot Parallel Coordinate Graph with normalized values
for i in range(nrows):
#plot rows of data as if they were series data
dataRow = glassNormalized.iloc[i,1:nDataCol]
labelColor = glassNormalized.iloc[i,nDataCol]/7.0
dataRow.plot(color=plot.cm.RdYlBu(labelColor), alpha=0.5)
plot.xlabel("Attribute Index")
plot.ylabel(("Attribute Values"))
plot.show()`
对玻璃数据的研究揭示了一个有趣的问题。具体地说,箱线图以及平行坐标图暗示了如果给定足够多的数据,采用集成方法是一个很好的选择。一系列的属性用来区分一个类别,明显类别之间会有复杂的边界。哪种算法会产生最佳的预测性能还有待进一步观察。本章学习的分析数据的方法已圆满完成了任务。它们可以帮助加深对问题的理解,通过各种权衡后可以更好地预判哪种算法可以获得较好的性能。