读研时期的课题研究为神经网络,也算与机器学习有些渊源。可惜我所读大学的教授们认为神经网络太理论化了,没有多少实际的用处(显然最近几年大数据和深度学习的飞速发展远远超出了他们当时的预期),这也多少导致我没有深入的研究神经网络。或许当时选择神经网络是正确的,现在很多地方都需要类似的人工智能手段去分析数据,探索数据,也正是因此,决定潜心学习机器学习以及深度学习。机器学习有很多很好的资料,比如《机器学习》、斯坦福大学的机器学习公开课,但能迅速入门并且比较直观地展示机器学习结果的书却比较少,有幸看到了《机器学习实战》这本书,里面的代码都是用python实现的,有代码有结果,还是特别适合我的,于是决定按照书中的章节,并参考《机器学习》中某些算法深入地讲解,开启机器学习的旅途。后面计划做一系列机器学习的笔记,手动编写python代码,顺便学习一下python语言。下面就开始吧。
基于实例的学习方法只是简单地将训练样例(样本)存储起来,从这些实例中泛化的工作被推迟到必须被分类新的实例时。基于实例的学习方法中最基本的是k-近邻算法,该算法假定所有实例对应n维空间中的点,一个实例的最近邻是根据标准欧氏距离计算的。假设 表示训练样例中的第i个实例,每个实例均有n个特征属性,分别为,则实例 和 之间的欧氏距离定义为:
在最近邻算法中目标函数值既可以是离散值也可以是连续值。k-近邻算法描述如下:当要确定新实例的分类时,就要在训练样例中根据欧氏距离公式计算与新实例最近的k个实例(样本),然后计算这k个实例中出现次数最多的分类,将其作为新实例的分类,通常这里的k是不大于20的正整数。考虑k=10,根据欧氏距离公式计算出10个与新实例最近的实例,在这10个实例中,某个分类出现的次数最多(假设为8次),则新实例就为该分类。
《机器学习实战》第二章的k-近邻算法所展示的代码中,个人感觉跟k-近邻算法有直接联系的有两段代码,第一个是classify0,用于直接实现k-近邻算法,第二个为autoNorm,用于将数值归一化,其余的代码或者用于处理文件的输入,或者用于测试k-近邻算法的执行效果。为什么要进行数据的归一化,什么时候进行归一化,都要根据实际情况中的样本特征做出选择。比如,训练样本中的某个特征的取值范围远远大于其它特征(该特征的范围从1到10000,其它特征大概为从0到100),那么在使用欧氏距离公式进行计算时,该特征对结果的影响将远远超过其它特征,而其它特征的重要程度应该和该特征等同,这时候就需要对数据进行归一化处理,将所有特征的取值都降到合理的范围,从而消除特殊情况。
下面就对k-近邻算法进行详细的学习,由于对python不熟悉的缘故,个人感觉暂时的困难都集中在学习python语言上,不过也正好借机学习python了,毕竟python在科研领域有着很大的使用量。因此,对classify0函数进行了详细的注解,下面即为代码部分:
#k-近邻算法。输入分别为:待分类的实例inX,训练样本集dataSet(矩阵),训练样本的标签向量labels(向量),最近邻居的数据数目k
#inX的列数于dataSet的列数相等,dataSet的行数于labels的元素数目相等
def classify0(inX, dataSet, labels, k):
#训练样本集的行数
dataSetSize = dataSet.shape[0]
#将inX扩展到于dataSet一样的行数,然后计算两个矩阵的差值
diffMat = tile(inX, (dataSetSize, 1)) - dataSet
#对差值矩阵进行平方计算
sqDiffMat = diffMat**2
#对平方后的差值矩阵按照每行进行求和计算,得到向量sqDistances
sqDistances = sqDiffMat.sum(axis=1)
#对向量sqDistances进行平方根计算,得到训练样本与输入样例的欧氏距离
distances = sqDistances**0.5
#对欧氏距离向量进行排序
sortedDistIndices = distances.argsort()
classCount = {}
for i in range(k):
#获取距离最近的k个样本的标签
voteIlabel = labels[sortedDistIndices[i]]
#统计每个标签出现的次数
classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1
#按照降序对标签进行排序
sortedClassCount = sorted(classCount.iteritems(), key=operator.itemgetter(1), reverse=True)
#返回出现次数最多的标签,即为待分类实例所属的类
return sortedClassCount[0][0]
在详细地学习过k-近邻算法的实现后,参考书中的例子进行了k-近邻算法的测验,主要测试了针对约会网站的分类和手写识别系统,这两个测试使用的是《机器学习实战》提供的数据集。
首先是对约会网站分类的测试,由于分类效果依赖于参数k和测试样本占样本数目的比例,开始测试按照书中的参数进行,即k=3,比例为0.1进行,结果如下:
>>> kNN.datingClassTest()
the training examples are: 900, the testing examples are: 100
the total error is: 5.000000
the total error rate is: 0.050000
调整k=5,比例不变,结果为:
>>> kNN.datingClassTest()
the training examples are: 900, the testing examples are: 100
the total error is: 4.000000
the total error rate is: 0.040000
继续调整k=10,比例不变,结果为:
>>> kNN.datingClassTest()
the training examples are: 900, the testing examples are: 100
the total error is: 4.000000
the total error rate is: 0.040000
继续调整k=15,比例不变,结果为:
>>> kNN.datingClassTest()
the training examples are: 900, the testing examples are: 100
the total error is: 6.000000
the total error rate is: 0.060000
上面的结果说明,k值不是越大越好,当超过某个值后,准确率反而下降了。
下面选择k=5,通过改变测试样本的比例为0.15来看看输出结果:
>>> kNN.datingClassTest()
the training examples are: 850, the testing examples are: 150
the total error is: 9.000000
the total error rate is: 0.060000
继续保持k=5,比例变为0.2,结果如下:
>>> kNN.datingClassTest()
the training examples are: 800, the testing examples are: 200
the total error is: 14.000000
the total error rate is: 0.070000
上面的数据说明,当整个样本集数目一定时,增加测试样本的数量(减少训练样本的数量)反而降低了准确率。
接下来是使用k-近邻算法识别手写数字(个人对图像处理一窍不通,不知道实际情况中是如何将图像作为机器学习的输入的,有待进一步的了解学习)。
选择k=3,结果如下:
>>> kNN.handwritingClassTest()
the training examples are: 1934, the testing examples are: 946
the total number of error is:11
the total error rate is: 0.011628
选择k=5,结果如下:
the training examples are: 1934, the testing examples are: 946
the total number of error is:17
the total error rate is: 0.017970
选择k=10,结果如下:
the training examples are: 1934, the testing examples are: 946
the total number of error is:20
the total error rate is: 0.021142
选择k=15,结果如下:
the training examples are: 1934, the testing examples are: 946
the total number of error is:26
the total error rate is: 0.027484
在手写数字识别过程中,随着k值得增大,准确率反而在降低。
至此,完成了k-近邻算法的学习和实验,最后对该算法进行总结。K-近邻算法是分类数据最简单最有效的算法,使用算法时必须有接近实际数据的训练样本数据。K-近邻算法的缺陷之一是必须保存全部数据集,如果训练数据集非常巨大,必须使用大量的存储空间。此外由于必须对数据集中的每个数据计算距离值,当训练数据集同样非常大时,性能会比较低。K-近邻算法的另一个缺陷是无法给出任何数据的基础结构信息,因此也无法知晓平均实例样本和典型实例样本具有什么样的特征。通过实验过程也可以发现,对参数的选取和调整要根据实际情况进行多次实验才能达到比较理想的效果。