一、问题描述
在UC Irvine Machine Learning数据集上选择三个数据,编写KNN算法预测结果,并使用十次-十折交叉验证
二、数据集选用
1.Wine.data
2.Iris.data
3.O-ring-erosion-only.data
实验平台:Python3.7
提取码:7060
三、 KNN分类器
kNN算法的核心思想是如果一个样本在特征空间中的k个最相邻的样本中的大多数属于某一个类别,则该样本也属于这个类别,并具有这个类别上样本的特性。
原理:
1.存在一个训练样本集,并且样本集中每个数据都存在标签,即我们知道样本集中每一数据与所属分类的对应关系。
2.输入没有标签的新数据后,将新数据的每个特征与样本集中数据对应的特征进行比较,然后算法提取样本集中特征最相似数据(最近邻)的分类标签。在这里距离一般用欧式距离或曼哈顿距离。
3.一般的,我们只选择样本数据集中前k个最相似的数据,通常k是不大于20的整数,最后选择k个最相似数据中出现次数最多的分类,作为新数据的分类。
四、 十折交叉验证
十折交叉验证是将训练集分割成10个子样本,一个单独的子样本被保留作为验证模型的数据,其他9个样本用来训练。交叉验证重复10次,每个子样本验证一次,平均10次的结果或者使用其它结合方式,最终得到一个单一估测。这个方法的优势在于,同时重复运用随机产生的子样本进行训练和验证,每次的结果验证一次,10次交叉验证是最常用的。
五、源码
''' 1、计算已知类别数据集中的点与当前点之间的距离 2、按照距离递增次序排序 3、选取与当前点距离最小的k个点 4、确定前k个点所在类别的出现概率 5、返回前k个点出现频率最高的类别作为当前点的预测分类 ''' import numpy as np import operator #处理文本 def fileToMatrix(iris): fr = open(iris) arrayOLines = fr.readlines() numberOfLines = len(arrayOLines) returnMat = np.zeros((numberOfLines, 5)) classLabelVector = [] index = 0 for line in arrayOLines: line = line.strip() listFromLine = line.split(',') returnMat[index,:] = listFromLine[0:5] classLabelVector.append(listFromLine[-1]) index += 1 return returnMat, classLabelVector #功能:归一化数据,避免某些数据的特征值过大 #def autoNorm(dataSet): def autoNorm(dataSet): minVals = dataSet.min(0)#取列值的最小值 maxVals = dataSet.max(0) ranges = maxVals - minVals normDataSet = np.zeros(np.shape(dataSet)) m = dataSet.shape[0] normDataSet = dataSet - np.tile(minVals, (m,1)) normDataSet = normDataSet/np.tile(ranges, (m, 1))#特征值相除 return normDataSet, ranges, minVals #功能:kNN核心算法 #intX - 输入向量,dataSet - 输入训练样本集,labels - 标签向量,k表示用于选择最近邻居的数目 #def classify(inX, dataSet, labels, k): def classify(inX, dataSet, labels,k): #欧式距离的计算 dataSize = dataSet.shape[0]#数据的行数 diffMat = np.tile(inX, (dataSize,1)) - dataSet#将输入向量inX纵向重复dataSet的行数次 sqDiffMat = diffMat ** 2 #距离度量,度量公示为欧氏距离 sqDistances = sqDiffMat.sum(axis = 1)# 每行数据相加 distances = sqDistances ** 0.5#得到训练样本集每一点与当前点的距离 sortedDistIndicies = distances.argsort() #对欧式距离进行排序 #选择距离最小的k个点 classCount = {} for i in range(k): voteIlabel = labels[sortedDistIndicies[i]]#最近K个的距离对应的类别 classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1#类别分别出现的概率 sortedClassCount = sorted(classCount.items(), key = operator.itemgetter(1), reverse = True)#选择发生频率最高的元素标签进行排序 return sortedClassCount[0][0] #功能:#功能:十折交叉验证 #思路:将数据集分成十份,轮流将其中9份做训练1份做测试,10次结果的均值作为对算法精度的估计 #一般还要进行多次10倍交叉验证 #def dataClassTest(iris, k): if __name__=='__main__': file_data = 'iris.data' k=5 testRate = 0.1 datingDataMat, datingLabels = fileToMatrix(file_data) datingDataMat = datingDataMat[:,:k-1] normMat, ranges, minVals = autoNorm(datingDataMat) m = normMat.shape[0] numTestVecs = int(m * testRate) all = 0 for k in range(1,11): t = normMat[0:numTestVecs] p = datingLabels[0:numTestVecs] for i in range(numTestVecs): errorCount = 0 classifierResult = classify(normMat[i,:],normMat[numTestVecs:m,:],datingLabels[numTestVecs:m],3) if(classifierResult != datingLabels[i]): errorCount += 1.0 #----------将第几折的数据拿出来,放回到normMat的前面 b = normMat[numTestVecs*(k-1):numTestVecs*k] normMat[0:numTestVecs] = b normMat[numTestVecs*(k-1):numTestVecs*k] = t errorRate = errorCount/float(numTestVecs) #----------将第几折类别拿出来,放回到datingLabels的前面 c = datingLabels[numTestVecs*(k-1):numTestVecs*k] datingLabels[0:numTestVecs] = c datingLabels[numTestVecs*(k-1):numTestVecs*k] = p errorRate = errorCount/float(numTestVecs) all = all + errorRate #------------------------------------------------------------------ print("第%d折分类的错误率为%f" % (k,(errorCount/float(numTestVecs)))) #获得平均错误率 print("平均正确率为%f" % (1-(all/10)))
六、实验结果
6.1 wine.data
6.2 iris.data
6.3 o-ring-erosion-only.data
七、 实验结果分析总结:
通过对比三个数据集,数据类型相似或相近,在酒和鸢尾花上交叉验证的准确率分别高达94%和99%,在O形圈上的准确率是50%,这是与数据中的数据特征相关,数据本身数值影响了分类准确率。KNN算法优点是精度较高、无数据输入假定;缺点是空间复杂度高。验证法与2折、3折相比,10折同时重复运用随机产生的子样本进行训练和验证,每次的结果验证一次,能得到更精确的分类器。
Be First to Comment