【机器学习】分类算法-KNN算法实践

一、前言

    前面的一篇文章介绍了KNN算法的基本思想,接下来我们就根据B站UP主【abilityjh】老师的节奏,做一个关于KNN算法运用于“约会网站配对”的算法实现。当然,这个实践的代码是一样的,但是理解的话,我是用自己的话来阐述自己敲完这个算法后的理解,可能更多的是一些大白话,大家也可以去看这个老师的原视频,会有很多收获哦!

二、案例介绍

b8121b8fe32f4fa0b0ae85f4f424dcf7.png

文本数据:

8ab848c73fed4391a42b8611968bfe29.png

案例描述:我们需要通过这个DataText.txt文档中的数据来测试我们KNN的准确性,该文档有1000条数据,我们把其中一部分拿来做训练集,另一部分拿来做测试集,结合我们的KNN算法就可以来测试KNN算法的准确性。

三、KNN算法实践

(1)实践思路

baa2ef6b37274806a7f173263b2581da.png

如图所示:我们先用将我们txt中的文本数据,转化为对应信息的矩阵或者列表,然后我们通过txt中的数据发现“里程数”的数据比其他两项的数据大了很多,如果这样来求未知点和训练数据中点的距离的话,后两项数据太小基本,没有作用,所以这里我们通过0-1标准化对里程数据做归一化处理;然后我们把之前写的KNN算法封装成一个函数调用,再测试KNN准确性即可。(PS:虽然流程简单,但是代码实现过程中还是有很多坑!)

(2)代码实现

①实现文件数据读取

def file2matrix(filename):
    fr = open(filename)
    numberOfLines = len(fr.readlines())
    # 定义一个numberOfLines行,3列的零矩阵
    # 一定要加两个括号
    returnMat = np.zeros((numberOfLines, 3))
    # 标签向量
    classLabelVector = []
    fr.close()
    fr = open(filename)
    index = 0
    for line in fr.readlines():
        # 去掉每一行的前后空格
        line = line.strip()
        # 根据tab将数据切割出来,listFromLine就成了一个字符串列表
        listFromLine = line.split("\t")
        # listFromLine[0:3]将listFromLine的前三列赋值给returnMat[]数组,因为returnMat有numberOfLines行,就会执行numberOfLines次操作
        returnMat[index, :] = listFromLine[0:3]
        # listFromLine[-1]表示最后一列
        if listFromLine[-1] == 'didntLike':
            classLabelVector.append(1)
        elif listFromLine[-1] == 'smallDoses':
            classLabelVector.append(2)
        elif listFromLine[-1] == 'largeDoses':
            classLabelVector.append(3)
        index += 1
    fr.close()
    return returnMat, classLabelVector


datingDataMat, datingLabels = file2matrix("D:/python工具/素材处/KNN(二)/DataText.txt")
print(datingDataMat)
print(datingLabels)

在这段代码中,我觉得最重要的几个点就是:文件读取、对每行数据处理(确保能分割成矩阵或者列表!)。代码的理解,我都打上了注释,大家可以仔细看看。

效果:

5cdf5c1830354d0ea178f19f5c20e3c8.png

②数据归一化处理

从上面的数据,可以看出里程数的数值是很大的,然后我们用0-1标椎化做处理,将里程数的每个数据缩小在0~1之间。

8379a443066b46afb32e62358e084d65.png

# 数据归一化处理
# 0-1标注化
def autoNorm(dataSet):
    # min(0)按特征的列选取,min(1)按照特征的行选取
    minVals = dataSet.min(0)
    maxVals = dataSet.max(0)
    # shape记录了dataSet的行和列
    normDataSet = np.zeros(dataSet.shape)
    normDataSet = (dataSet - minVals) / (maxVals - minVals)
    return normDataSet

dataSet = autoNorm(datingDataMat)
print(dataSet)
print(datingLabels)

效果:

a8a891a5f594451782bdbe84bcd906f0.png

③对KNN代码封装

代码原理上一篇博客已经介绍

# inX输入数据,dataSet测试数据,labels标签,k最近的点的个数
def knn(inX, dataSet, labels, k):
    dist = (((dataSet - inX) ** 2).sum(1)) ** 0.5
    sortdDist = dist.argsort()
    classCount = {}
    for i in range(k):
        voteLabel = labels[sortdDist[i]]
        classCount[voteLabel] = classCount.get(voteLabel, 0) + 1
    maxType = 0
    maxCount = -1
    for key, value in classCount.items():
        if value > maxCount:
            maxType = key
            maxCount = value
    return maxType

④调用KNN算法进行测试

m = 0.8
# shape[0]表示行、shape[1]表示列
dataSize = dataSet.shape[0]
print("数据集的总行数:", dataSize)
# 80%作为训练 20%作为测试
trainSize = int(m * dataSize)
testSize = int((1 - m) * dataSize)
k = 5
result = []
error = 0
# 调用封装好的KNN函数
for i in range(testSize):
    # dataSet[trainSize + i - 1, :]表示dataSet矩阵中的第trainSize + i - 1行元素(包含对应的所有列)
    # dataSet[0:trainSize, :]表示一个从0~trainSize行,包含对应所有列的矩阵
    # datingLabels[0:trainSize]表示截取列表datingLabels中的0~trainSize个元素
    result = K.knn(dataSet[trainSize + i - 1, :], dataSet[0:trainSize, :], datingLabels[0:trainSize], k)
    # result != datingLabels[trainSize + i - 1]表示通过KNN算法得到的result是否与原来的datingLabels中对应下标为trainSize + i - 1是否相等
    if result != datingLabels[trainSize + i - 1]:
        error += 1

print('错误率:', error / testSize)

这段代码中,我觉得对新手来说最不好理解的就是for循环中的dataSet矩阵的切片操作,我自己也是下来梳理了一下,才通顺起来,相应代码的注解放在代码中了,大家自己取用。

效果:

294da493292c4ebaa6511aea85ec31fe.png

可见,我们1000条数据,用80%做训练集,20%做测试集,K选用为5用使用KNN算法的出错率,只有5.52%,其实还是可以的。(大家也可以改变数据,再测试一下)

PS:当然KNN算法的优缺点以及使用场景,就不止这些,大家可以下来好好探索一番,我这里就主要梳理一下代码啦!

四、总结

    博主作为一个新手,才开始学习机器学习而言,我觉得这篇关于KNN算法的实践,对自己帮助挺大的,让我学到了以下很多知识:

①关于文件数据的读取;

②数据的处理、归一化;

③函数的封装调用;

④矩阵和列表的一些切片操作;

最后,如果这篇文章对大家有所帮助,别忘了点赞、关注支持博主一波哦~,你们的助力,就是我持续更新的动力!

PS:如果有需要这个DataText.txt数据集的小伙伴,直接私信我,即可发送。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值