机器学习之Knn算法
机器学习交通工具(无人机,自动驾驶)VR(虚拟现实)比特币,区块链定义:人工智能是研究开发用于模拟,延伸和扩展人的只能的理论、延伸和扩展人的智能的理论、方法、技术及应用系统的一门综合性交叉学科。弱人工智能:包含基础的,特定场景下角色型的任务,如Siri和AlphaGo机器人通用人工智能:包含人类水平的任务,涉及机器的持续学习。强人工智能:比人类更聪明的机器。机器学习是人工智能的一个领域深度学习又是
机器学习
交通工具(无人机,自动驾驶)
VR(虚拟现实)
比特币,区块链
定义:人工智能是研究开发用于模拟,延伸和扩展人的只能的理论、延伸和扩展人的智能的理论、方法、技术及应用系统的一门综合性交叉学科。
- 弱人工智能:包含基础的,特定场景下角色型的任务,如Siri和AlphaGo机器人
- 通用人工智能:包含人类水平的任务,涉及机器的持续学习。
- 强人工智能:比人类更聪明的机器。
机器学习是人工智能的一个领域
深度学习又是机器学习的一个分支
人工智能包括:
- 思考方面:机器学习,自动推理,人工意识,知识表示
- 听觉方面:语音识别
- 视觉方面:视觉识别
- 运动方面:动作执行
人类学习方式:
机器学习方式:
机器学习:
机器学习本质上就是用大量的输入和输出来训练出一个模型,用这个模型输入的数据所得出的输出要尽可能贴合所解决的问题的解。模型其实就是一个函数。训练模型实质上就是用大量的数据求出最合适的参数。
基本术语:
数据集,训练,测试,样本(sample),属性(attribute),特征(feature),属性值,属性空间,样本空间,输入空间,特征向量
机器学习的任务:
-
令W是这个给定世界的有限或无限所有对象的集合,由于观察能力的限制,我们只能获得这个世界的一个有限子集Q属于W,称为样本集。
-
机器学习就是根据这个有限样本集Q,推算这个世界的模型,使得其对这个世界的认知为真。

机器学习算法:
- 监督学习:统计分类,回归分析
- 无监督学习:聚类,关联规则

KNN算法:
分类的概念:把每个数据点分配到合适的类别中,即所谓的分类,其解决的问题就是如何建立一个有效的分类算法模型将待分类的样本进行正确的划分
分类的核心思想是 相似
而判别相似性的一个重要条件就是距离
import matplotlib.pyplot as plt
fight = (3, 2, 1, 101, 99, 98, 18)
kiss = (104, 100, 81, 10, 5, 2, 90)
# 1:Romance类型,2:Action类型,3:Unkown类型
filmType = (1, 1, 1, 2, 2, 2, 3)
# 画散点图
plt.scatter(fight, kiss, c=filmType)
# 显示散点图
plt.show()
如果我们想要判断黄球(unknown)是属于两者之间的哪一类,那么很显然,由于黄球距离紫色球更近一点,所以,黄球有很大可能性是属于紫色类,所以距离远近可以作为分类的一个很好地切入点。
-
最近邻算法(NN):为判定未知样本的类别,以全部训练样本作为代表点,计算未知样本与所有训练样本的距离,并以最邻近者的类别作为决策未知样本的唯一依据。
但是,最近邻算法存在明显缺陷
- 当周边只有一个最近点但是存在多个其他样本点时,所判定分类不太合理,所以最近邻算法对噪声过于敏感
- 为了解决这个问题,我们可以把未知样本周边的多个最近样本计算在内,扩大参与决策的样本量,以避免个别数据直接决定决策结果,由此衍生出 K-近邻算法
-
K-近邻算法:KNN算法的原理就是当预测一个新的值x的时候,根据它距离最近的K个点是什么类别来判断x属于哪个类别,其步骤为:
-
计算测试对象与训练集中的每个对象的距离。计算距离主要用到欧几里得距离和曼哈顿距离
-
欧式距离公式为:

-
曼哈顿距离公式为:

-
-
选取近邻:将距离升序排序,选择距离最近的K个样本点
-
分类决策:根据这K个近邻归属的类别,采用多数表决的方法,由这K个点来投票决定测试对象归为哪一类
- 准备数据,分析数据,对数据进行预处理,归一化处理
- 划分训练集和测试集
- 计算未知样本和每个训练集样本的距离
- 设定参数,K值
- 将距离升序排序
- 选取距离最小的K个点
- 统计前K个最近邻样本点所在类别出现的次数
- 多数表决,选择出现频率最大的类别作为未知样本的类别
- kNN算法没有进行数据的训练,直接使用未知数据与已知数据进行比较,得到结果。因此,KNN算法不具有显式的学习过程
思考:如果采用多数表决的话,到最后那决定权似乎只是K样本点中各个类别样本点距离未知点的的个数了,而距离似乎只是用来判断某一个点是不是样本点,这样分出来的类别似乎不太严谨,所以,能不能把样本点个数作为一个比重或者是可调控参数,K样本点距未知点的距离占剩下的比重,两者以某一个模型来共同决定未知点的分类
import matplotlib.pyplot as plt import numpy as np fight = (3, 2, 1, 101, 99, 98) kiss = (104, 100, 81, 10, 5, 2) # 1:Romance类型,2:Action类型,3:Unkown类型 filmType = (1, 1, 1, 2, 2, 2) # 画散点图 plt.scatter(fight, kiss, c=filmType) # 显示散点图 plt.show() x = np.array([fight, kiss]) y = np.array(filmType) x = x.T print(x) print(y) xx = np.array([18, 90]) # 此处sum()中的参数可以为0或者是1,若为0,则按列求和,若为1,则按行求和 dist = (((x-xx)**2).sum(1))**0.5 print(dist) sortedDist = dist.argsort() print(sortedDist) # 在k=4的范围内寻找哪一类样本点距离未知类型点最多 k = 4 # 定义一个字典,其作用是为了判断前k-1个样本中每个种类出现了几次 classCount = {} for i in range(k): voteLable = y[sortedDist[i]] # get()方法中第二个属性的意思是若关键字不存在于字典中,则返回0 classCount[voteLable] = classCount.get(voteLable, 0) + 1 print("key:value", classCount) # 在字典中寻找哪一类出现的次数最多 maxType = 0 maxCount = -1 # 这种遍历方式是在字典中遍历的方式,直接用key和value取字典中的键值对即可 for key, value in classCount.items(): if value> maxCount: maxType = key maxCount = value print('outPut:', maxType) 输出: [[ 3 104] [ 2 100] [ 1 81] [101 10] [ 99 5] [ 98 2]] [1 1 1 2 2 2] [ 20.51828453 18.86796226 19.23538406 115.27792503 117.41379817 118.92854998] [1 2 0 3 4 5] key:value {1: 3, 2: 1} outPut: 1加一个知识点,函数的调用方式:
-
直接在本模块中调用
import matplotlib.pyplot as plt import numpy as np # 个模块是从Classify.py中抽离然后封装来的 class KnnSort: def __init__(self, inX, dataSet, labels, k): self.inX = inX self.dataSet = dataSet self.labels = labels self.k = k # inX:未知类型数据; dataSet:训练集;labels:训练集标签项(每个数据所属类型); k:样本所属范围 def knn(self): # 此处sum()中的参数可以为0或者是1,若为0,则按列求和,若为1,则按行求和 dist = (((self.inX - self.dataSet) ** 2).sum(1)) ** 0.5 sortedDist = dist.argsort() # 定义一个字典,其作用是为了判断前k-1个样本中每个种类出现了几次 classCount = {} for i in range(self.k): voteLable = self.labels[sortedDist[i]] # get()方法中第二个属性的意思是若关键字不存在于字典中,则返回0 classCount[voteLable] = classCount.get(voteLable, 0) + 1 # 在字典中寻找哪一类出现的次数最多 maxType = 0 maxCount = -1 # 这种遍历方式是在字典中遍历的方式,直接用key和value取字典中的键值对即可 for key, value in classCount.items(): if value > maxCount: maxType = key maxCount = value return maxType if __name__ == '__main__': fight = (3, 2, 1, 101, 99, 98) kiss = (104, 100, 81, 10, 5, 2) # 1:Romance类型,2:Action类型,3:Unkown类型 filmType = (1, 1, 1, 2, 2, 2) x = np.array([fight, kiss]) y = np.array(filmType) x = x.T xx = np.array([18, 90]) # 直接调用类即可,在调用类的时候传入参数,然后直接调用函数即可 result = KnnSort(xx, x, y, 4).knn() print(result) -
在其他文件中调用
import Knn as k import matplotlib.pyplot as plt import numpy as np fight = (3, 2, 1, 101, 99, 98) kiss = (104, 100, 81, 10, 5, 2) # 1:Romance类型,2:Action类型,3:Unkown类型 filmType = (1, 1, 1, 2, 2, 2) x = np.array([fight, kiss]) y = np.array(filmType) x = x.T xx = np.array([18, 90]) # 上面 import Knn as k 中引入的k是Knn文件名称,KnnSort是类名 result = k.KnnSort(xx, x, y, 4).knn() print(result) -
大量存在于文件中的数据进行数据集的构建
# -*- coding: utf-8 -*- # @Time : 2021/7/15 10:43 # @Author : wcc # @FileName: KnnLargeData.py # @Software: PyCharm # @Blog :https://blog.csdn.net/qq_41575517?spm=1000.2115.3001.5343 import numpy as np import matplotlib.pyplot as plt import pandas as pd class ProcessData: def __init__(self, file_name): self.filename = file_name # 构建训练集 def file2matrix(self): # 打开文件 fr = open(self.filename) # 计算文件行数,readlines() 方法用于读取所有行(直到结束符 EOF)并返回列表,该列表可以由 Python 的 # for... in ... 结构进行处理。如果碰到结束符 EOF 则返回空字符串。 numberOfLines = len(fr.readlines()) # 生成一个三列的全0矩阵 returnMat = np.zeros((numberOfLines, 3)) classLabelVector = [] # 此处再写一次 fr = open(self.filename) 语句的原因是当使用 fr.readlines() 遍历过一次之后其光标 # 移动到了最后,若再需要从头遍历数据,则此处需要重新设定光标位置,需要将其设置为(0,0),所以此处用 # seek()方法重新设置光标位置亦可 # fr = open(self.filename) fr.seek(0, 0) index = 0 for line in fr.readlines(): # str.strip()就是把字符串(str)的头和尾的空格,以及位于头尾的\n \t之类给删掉 line = line.strip() # 由于文本数据是以一个制表位来区分的,所以将遍历到的文本的一行按制表位分割成一个1*3的矩阵 listFormLine = line.split('\t') # 将遍历到的一行数据赋给returnMat的第index行的所有列位(因为上面定义的returnMat也只有3列,所以等号前面的列的范围直接可以省略) returnMat[index, :] = listFormLine[0:3] # 这以上做的所有工作全是为了得到一个1000*3的矩阵 # 1:代表不喜欢;2:代表一点喜欢;3:代表非常喜欢 if listFormLine[-1] == 'didntLike': # 用append()方法可以得到一个list,而不是一个array classLabelVector.append(1) if listFormLine[-1] == 'smallDoses': classLabelVector.append(2) if listFormLine[-1] == 'largeDoses': classLabelVector.append(3) index += 1 x = returnMat[:, 0] y = returnMat[:, 1] z = returnMat[:, 2] classify = classLabelVector # 本例需要将三个变量两两进行比较 # plt.scatter(x, y, c=classify) plt.scatter(x, z, c=classify) # plt.scatter(y, z, c=classify) # # 显示散点图 plt.show() fr.close() return returnMat, classLabelVector if __name__ == '__main__': datingDataMat, datingLables = ProcessData('datingTestSet.txt').file2matrix() print(datingDataMat) print(datingLables)
-
-
数据归一化:
当有多个属性共同作用于结果且某一个属性的数值远大于其他属性时,经计算所取得的结果必定是不精确的,所以就需要削弱这个属性对结果所产生的影响,所以需要进行数据的归一化
-
0—1标准化:将当前值映射到0—1区间之间

上式的意思是:(当前值 — 整个序列中的最小值) / (整个序列的最大值 — 整个序列的最小值)
-
Z—score标准化
-
sigmoid压缩法
-
-
鸢尾花数据使用knn算法分类
# -*- coding: utf-8 -*- # @Time : 2021/7/16 21:45 # @Author : wcc # @FileName: KnnIris.py # @Software: PyCharm # @Blog :https://blog.csdn.net/qq_41575517?spm=1000.2115.3001.5343 import numpy as np import matplotlib.pyplot as plt import pandas as pd class Iris: def __init__(self, file_name, data_set, labels_set, normal_data_set, sample_range, data_division): self.fileName = file_name self.dataMat = data_set self.labelsMat = labels_set self.normalDataSet = normal_data_set self.k = sample_range self.dataDivision = data_division # 数据预处理 def iris_processData(self): fr = open(self.fileName) numOfLines = len(fr.readlines()) # 此处一定是除标签列以外的数据列数 dataMat = np.zeros((numOfLines, 4)) # 标签单独成一列 labelsMat = [] fr.seek(0, 0) index = 0 for line in fr.readlines(): line = line.strip() listLine = line.split(',') dataMat[index, :] = listLine[0:4] if listLine[-1] == 'Iris-setosa': labelsMat.append(1) if listLine[-1] == 'Iris-versicolor': labelsMat.append(2) if listLine[-1] == 'Iris-virginica': labelsMat.append(3) index += 1 labelsMat = np.array(labelsMat) self.dataMat = dataMat self.labelsMat = labelsMat # 数据归一化(0-1归一化) def iris_normal(self): colDataMax = self.dataMat.max(0) colDatamin = self.dataMat.min(0) normalDataSet = np.zeros(self.dataMat.shape) normalDataSet = (self.dataMat - colDatamin)/(colDataMax - colDatamin) self.normalDataSet = normalDataSet # knn算法对测试集进行测试 def iris_knn(self): trainSize = int(self.normalDataSet.shape[0]*self.dataDivision) testSize = int(self.normalDataSet.shape[0]*(1-self.dataDivision)) result = [] errorCount = 0 errorRecords = {} correctRecords = {} index = 0 for i in range(testSize): count = {} dist = (((self.normalDataSet[trainSize+i, :]-self.normalDataSet[0:trainSize, :])**2).sum(1))**0.5 sortDisk = dist.argsort() for j in range(self.k): voteLable = self.labelsMat[sortDisk[j]] count[voteLable] = count.get(voteLable, 0) + 1 maxType = 0 maxCount = -1 for key, value in count.items(): if value>maxCount: maxType = key maxCount = value if self.labelsMat[trainSize+i] != maxType: errorRecords[trainSize+i] = maxType correctRecords[trainSize+i] = self.labelsMat[trainSize+i] errorCount +=1 print('错误个数:') print(errorCount) print('错误位置及错误值:') print(errorRecords) print('相应位置的正确值:') print(correctRecords) # %%为转义,为了输出后面的% print('正确率:%f%%' % ((1-errorCount/testSize)*100)) if __name__ == '__main__': fileName = 'iris.txt' # 'datingTestSet.txt'# 文件路径 dataMat = [] # 数据集(自己读取) labelsMat = [] # 标签集(自己读取) normalDataSet = [] #归一化后的数据集 sampleRange = 5 # 范围取值 dataDivision = 0.8 # 数据集中训练集和测试集的划分比例 iris = Iris(file_name=fileName, data_set=dataMat, labels_set=labelsMat, normal_data_set=normalDataSet, sample_range=sampleRange, data_division=dataDivision) iris.iris_processData() iris.iris_normal() iris.iris_knn()
更多推荐



所有评论(0)