待思考的问题
- KNN的基本思想是什么?
- 举一个现实生活的例子(非机器学习领域),说明KNN的应用
- KNN的优点和缺点分别是什么?
- 不同属性的值域大小不同(如有的跨度为500,而有的跨度为0.1),会导致什么问题,应如何解决?
- KNN算法的时间复杂度是多少?
- 用什么办法可以降低其时间复杂度?
1. KNN基本思想
比较官方的说法:给定一个训练数据集,对新的输入实例,在训练数据集中找到与该实例最邻近的K个实例(也说K个邻居), 这K个实例的多数属于某个类,就把该输入实例分类到这个类中。
比较易理解的说法:近朱者赤,近墨者黑,即根据数据的相似性进行学习。
常言道,物以类聚,人以群分。有一种说法是判别一个人是一个什么样品质特征的人,可以从他/她身边的朋友入手。如下图,若要判别图中绿色的圆是属于哪一类数据,即从其邻居入手。但是,一次性看多少个邻居呢?
- 如果K=3,绿色圆点的最近的3个邻居是2个红色小三角形和1个蓝色小正方形,少数从属于多数,基于统计的方法,判定绿色的这个待分类点属于红色的三角形一类。
- 如果K=5,绿色圆点的最近的5个邻居是2个红色三角形和3个蓝色的正方形,还是少数从属于多数,基于统计的方法,判定绿色的这个待分类点属于蓝色的正方形一类。
由此可见,当我们没法判定当前点属于已知分类中的哪一类时,可以依据统计学的理论看它所处的位置特征,衡量它周围邻居的权重,而把它归为(或分配)到权重更大的那一类。
2. KNN算法流程
简单理解为:
- 找出每个测试数据最相似的k个训练数据
- 投票决定
具体流程:
- 计算已知类别数据集中的点与当前点之间的距离
- 按照距离递增次序排序;
- 选取与当前点距离最小的 k 个点;
- 确定前 k 个点所在类别的出现频率;
- 返回前 k 个点出现频率最高的类别作为当前点的预测类别
3. KNN算法三要素
- 距离度量
- 确定K值
- 分类规则
3.1 距离度量
- 曼哈顿距离
- 欧氏距离
- 闵可夫斯基距离
3.2 确定K值
K值:表示在待预测点周围取几个临近的点来预测;
对于k值的选择,一般选择一个较小的值,然后通过交叉验证选择一个合适的k值。
k值过小会使得整体模型变复杂,容易发生过拟合。
k值过大会使得整体模型变简单,容易发生欠拟合。
通常K是不大于20的整数
3.3 分类规则
k 近邻算法中的分类规则往往采取多数表决,即由输入实例的k个邻近的训练实例中的多数类决定输入实例的类。
4. Python实现KNN算法
4.1 鸢尾花数据集分析
首先,通过比较经典的鸢尾花(Iris)数据集来进行学习。
1. 数据集介绍
该数据集一共包含150条记录,这150条记录被平均分成了3类,其中每一条数据有4种特征(feature):花萼长度,花萼宽度,花瓣长度,花瓣宽度。我们需要通过花萼长度,花萼宽度,花瓣长度,花瓣宽度这4个特征来预测鸢尾花卉属于iris-setosa, iris-versicolour, iris-virginica3个种类中的哪一类。
2. 实现步骤
- 首先,通过调包载入鸢尾花数据集
- 接着,对该数据集进行划分,划分成训练集和测试集
- 对训练集进行训练
- 通过测试集进行测试
需要调的包
import sklearn.datasets, sklearn.neighbors, sklearn.model_selection
代码实现
def sklearnKnnTest():
"""1. Load the dataset(通过调包载入数据)"""
tempDataset = sklearn.datasets.load_iris()
print("The number of sample and feature: ", tempDataset.data.shape)
x = tempDataset.data
y = tempDataset.target
# x是一个矩阵,有150行4列,即有150个样本,每个样本都具有4种特征
# print("x = ", x)
# y有0,1,2三类,每类50个
# print("y = ", y)
"""2. Split the data(划分数据集,分成训练集和测试集)"""
# test_size表示作为测试的数据的占比,即20%作为测试,80%作为训练
x1, x2, y1, y2 = sklearn.model_selection.train_test_split(x, y, test_size=0.2)
# x1, y1组成了训练集
print("x1 = ", x1)
print("y1 = ", y1)
# x2, y2组成了测试集
print("x2 = ", x2)
print("y2 = ", y2)
"""3. Indicate the training set"""
# n_neighbors即KNN算法中的K值,此处设为5
tempClassifier = sklearn.neighbors.KNeighborsClassifier(n_neighbors=5)
tempClassifier.fit(x1, y1)
"""4. Test"""
tempScore = tempClassifier.score(x2, y2)
print("The score is: ", tempScore)
运行截图
注意:由于我们每一次对测试数据和训练数据的划分是不同的,所以在预测的时候,预测的准确率也会有差别。
以上实现过程是通过调包实现的,先从 sklearn 中导入了 鸢尾花的数据集,并通过train_test_split方法对该数据集进行了划分,再通过kNN 的分类算法函数 KNeighborsClassifier 建立模型,设置最近的 K 个样本数量 n_neighbors 为 5。再 fit 训练模型,最后 predict 预测模型得到分类结果 。并且预测结果可能会因为每次划分的测试数据集的不同而不同。
虽然这种调包的方式比较简单,但是对于其内部过程的实现还需要进一步学习,对于python代码实现的内容会记录在后续的几篇博客中。
5. KNN算法的优缺点
- 优点
精度高、对异常值不敏感、无数据输入假定
简单易用,且预测效果不错 - 缺点
计算复杂度高(对高维数据计算量很大,预测阶段可能很慢)
空间复杂度高(对内存要求高,该算法存储了所有训练数据)