完整代码地址:https://github.com/cqulun123/Machine-Learning-in-Action
0 k-近邻算法概述
简单地说, k-近邻算法采用测量不同特征值之间的距离方法进行分类。
优点:精度高、对异常值不敏感、无数据输入假定。
缺点:计算复杂度高、空间复杂度高。
适用数据范围:数值型和标称型。
缺点:计算复杂度高、空间复杂度高。
适用数据范围:数值型和标称型。
工作原理
存在一个样本数据集合,也称作训练样本集,并且样本集中每个数据都存在标签,即我们知道样本集中每一数据与所属分类的对应关系。输入没有标签的新数据后,将新数据的每个特征与样本集中数据对应的特征进行比较,然后算法提取样本集中特征最相似数据(最近邻)的分类标签。一般来说,我们只选择样本数据集中前
k个最相似的数据,这就是k-近邻算法中k的出处,通常k是不大于20的整数。最后,选择k个最相似数据中出现次数最多的分类,作为新数据的分类。
k-近邻算法的一般流程 |
(1) 收集数据:可以使用任何方法。 (2) 准备数据:距离计算所需要的数值,最好是结构化的数据格式。 (3) 分析数据:可以使用任何方法。 (4) 训练算法:此步骤不适用于k-近邻算法。 (5) 测试算法:计算错误率。 (6) 使用算法:首先需要输入样本数据和结构化的输出结果,然后运行k-近邻算法判定输入数据分别属于哪个分类,最后应用对计算出的分类执行后续的处理。 |
1 准备:使用 Python 导入数据
import numpy as np
import operator
def create_data_set():
"""
函数作用:创建数据集和标签
set_group:数据集
set_labels:数据集对应的标签
"""
set_group = np.array([[1.0, 1.1], [1.0, 1.0], [0, 0], [0, 0.1]])
set_labels = ['A', 'A', 'B', 'B']
return set_group, set_labels
现在我们已经知道
Python如何解析数据,如何加载数据,以及kNN算法的工作原理,接下来我们将使用这些方法完成分类任务。
2 实施 kNN 算法
其伪代码如下:
对未知类别属性的数据集中的每个点依次执行以下操作:
(1) 计算已知类别数据集中的点与当前点之间的距离;
(2) 按照距离递增次序排序;
(3) 选取与当前点距离最小的k个点;
(4) 确定前k个点所在类别的出现频率;
(5) 返回前k个点出现频率最高的类别作为当前点的预测分类。
(1) 计算已知类别数据集中的点与当前点之间的距离;
(2) 按照距离递增次序排序;
(3) 选取与当前点距离最小的k个点;
(4) 确定前k个点所在类别的出现频率;
(5) 返回前k个点出现频率最高的类别作为当前点的预测分类。
def classify0(input_data, data_set, labels_set, k):
"""
函数作用:使用k-近邻算法将每组数据划分到某个类中
:param input_data:用于分类的输入数据(测试集)
:param data_set:输入的训练样本集
:param labels_set:训练样本标签
:param k:用于选择最近邻居的数目,即kNN算法参数,选择距离最小的k个点
:return:返回分类结果
"""
# data_set.shape[0]返回训练样本集的行数
data_set_size = data_set.shape[0]
# 在列方向上重复input_data,1次,行方向上重复input_data,data_set_size次
diff_mat = np.tile(input_data, (data_set_size, 1)) - data_set
# diff_mat:输入样本与每个训练样本的差值,然后对其每个x和y的差值进行平方运算
sq_diff_mat = diff_mat ** 2
# 按行进行累加,axis=1表示按行。
sq_distances = sq_diff_mat.sum(axis=1)
# 开方运算,求出距离
distances = sq_distances ** 0.5
# 返回distances中元素从小到大排序后的索引值
sorted_dist_indices = distances.argsort()
# 定一个字典:统计类别次数
class_count = {}
for i in range(k):
# 取出前k个元素的类别
vote_index_label = labels_set[sorted_dist_indices[i]]
# 统计类别次数
class_count[vote_index_label] = class_count.get(vote_index_label, 0) + 1
# 把分类结果进行降序排序,然后返回得票数最多的分类结果
sorted_class_count = sorted(class_count.items(), key=operator.itemgetter(1), reverse=True)
return sorted_class_count[0][0]
3 预测数据
if __name__ == '__main__':
# 创建数据集
group, labels = create_data_set()
# 测试集
test = [3, 0.3]
# kNN算法进行分类
test_class = classify0(test, group, labels, 3)
# 显示分类结果
print(test_class)
输出结果为
A,大家也可以改变输入[3, 0.3]为其他值,测试程序的运行结果。
完整代码如下:
# encoding: utf-8
"""
@author:max bay
@version: python 3.6
@time: 2018/5/5 0:25
"""
import numpy as np
import operator
def create_data_set():
"""
函数作用:创建数据集和标签
set_group:数据集
set_labels:数据集对应的标签
"""
set_group = np.array([[1.0, 1.1], [1.0, 1.0], [0, 0], [0, 0.1]])
set_labels = ['A', 'A', 'B', 'B']
return set_group, set_labels
def classify0(input_data, data_set, labels_set, k):
"""
函数作用:使用k-近邻算法将每组数据划分到某个类中
:param input_data:用于分类的输入数据(测试集)
:param data_set:输入的训练样本集
:param labels_set:训练样本标签
:param k:用于选择最近邻居的数目,即kNN算法参数,选择距离最小的k个点
:return:返回分类结果
"""
# data_set.shape[0]返回训练样本集的行数
data_set_size = data_set.shape[0]
# 在列方向上重复input_data,1次,行方向上重复input_data,data_set_size次
diff_mat = np.tile(input_data, (data_set_size, 1)) - data_set
# diff_mat:输入样本与每个训练样本的差值,然后对其每个x和y的差值进行平方运算
sq_diff_mat = diff_mat ** 2
# 按行进行累加,axis=1表示按行。
sq_distances = sq_diff_mat.sum(axis=1)
# 开方运算,求出距离
distances = sq_distances ** 0.5
# 返回distances中元素从小到大排序后的索引值
sorted_dist_indices = distances.argsort()
# 定一个字典:统计类别次数
class_count = {}
for i in range(k):
# 取出前k个元素的类别
vote_index_label = labels_set[sorted_dist_indices[i]]
# 统计类别次数
class_count[vote_index_label] = class_count.get(vote_index_label, 0) + 1
# 把分类结果进行降序排序,然后返回得票数最多的分类结果
sorted_class_count = sorted(class_count.items(), key=operator.itemgetter(1), reverse=True)
return sorted_class_count[0][0]
if __name__ == '__main__':
# 创建数据集
group, labels = create_data_set()
# 测试集
test = [3, 0.3]
# kNN算法进行分类
test_class = classify0(test, group, labels, 3)
# 显示分类结果
print(test_class)
4 参考资料
[1] 机器学习实战
[2] 机器学习实战笔记(Python实现)-02-k近邻算法(kNN)