Press "Enter" to skip to content

编写KNN算法预测结果,并使用十次-十折交叉验证精度

一、问题描述

 

在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

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注