机器学习实战笔记(1)——kNN(k Nearest Neighbor)算法
2017-07-26 14:10
555 查看
简述
kNN算法(中文翻译:k-近邻算法)是机器学习分类算法的基础部分,也是比较简单的算法之一。它的内容和原理并不复杂,但是计算量比较大,即时间复杂度和空间复杂度都比较高。书中以约会网站和手写数字识别系统为例。在这里,笔者也将从这两个例子下手,但是对部分代码进行了改进,以便适应Python3的编程环境。算法描述
kNN的k指的是在新数据与样本数据进行比对时,只选取前k个最相近的数据。kNN算法就是对未知类别属性的数据集中的每个点依次执行以下操作:
计算已知类别数据集中的点与当前点之间的距离(欧氏距离:d=(xA−xB)2+(yA−yB)2−−−−−−−−−−−−−−−−−−−√
);
按照距离递增次序排序;
选取与当前点距离最小的k个点;
确定前k个点所在类别的出现频率;
返回前k个点出现频率最高的类别作为当前点的预测分类。
特点
优点:精度高,对异常值不敏感,无数据输入假定。缺点:计算复杂度较高,空间复杂度较高。
适用范围:数值型和标称型。数据需带有目标数据,即人工标签。标签形式可以是文件名,也可以是文档内的某一列。
算法处理一般流程
收集数据准备数据:结构化的数据格式,有自己的数据格式即可。
分析数据
训练算法:此步骤不适用于kNN,但是为了明确一般流程,仍然加上。
测试算法:计算错误率。
使用算法:首先输入样本数据和结构化的输出结果,然后运行kNN算法判定数据分别属于哪一个分类,最后应用于分类的后续处理。
module
from numpy import * # numpy matrix and array process import operator # sorted() function's 'key'parameter from os import listdir # used to list the folder files
收集、解析数据
以文本文件的数据为例,提取其中的矩阵数据(一般以二维数据居多)和标签信息。def file2matrix(filename): """ txt file data change to matrix @param filename: filename @return: the read_matrix and the labels """ with open(filename, mode='r') as fr: array_lines = fr.readlines() number_of_lines = len(array_lines) return_mat = zeros((number_of_lines, 3)) class_label_vector = [] index = 0 for line in array_lines: line = line.strip() list_from_line = line.split('\t') return_mat[index, :] = list_from_line[0:3] class_label_vector.append(int(list_from_line[-1])) index += 1 return return_mat, class_label_vector
算法核心代码实现
def classify0(inX, dataset, labels, k): """ knn classify @param inX: the input vector which is ready to be classified @param dataset: the training data set @param labels: labels vector @param k: the k-th @return: sorted result """ dataset_size = dataset.shape[0] # calculate the number of lines diff_mat = tile(inX, (dataset_size, 1)) - dataset sq_diff_mat = diff_mat**2 sq_distances = sq_diff_mat.sum(axis=1) distances = sq_distances**0.5 sorted_distance_indices = distances.argsort() class_count = {} for i in range(k): vote_i_label = labels[sorted_distance_indices[i]] class_count[vote_i_label] = class_count.get(vote_i_label, 0) + 1 sorted_class_count = sorted(class_count.items(), key=operator.itemgetter(1), reverse=True) return sorted_class_count[0][0]
示例1:约会数据的分类
女主角Helen要在自己打了标签的数据里面得到一个模型,用以判断今后遇到的男生对她的魅力值和吸引力。我们先来看一部分她打过标签的格式化数据:
40920 8.326976 0.953952 3 14488 7.153469 1.673904 2 26052 1.441871 0.805124 1 75136 13.147394 0.428964 1 38344 1.669788 0.134296 1 72993 10.141740 1.032955 1 35948 6.830792 1.213192 3 42666 13.276369 0.543880 3 67497 8.631577 0.749278 1 35483 12.273169 1.508053 3 50242 3.723498 0.831917 1 63275 8.385879 1.669485 1 5569 4.875435 0.728658 2 51052 4.680098 0.625224 1
从左至右依次是年飞行里程数、玩儿视频游戏所耗时间的百分比、每周消耗的冰激凌公升数以及最后的标签(1-3依次是不喜欢、喜欢和非常喜欢)PS. 话说貌似打会儿游戏还是很受欢迎的哈~
可将其绘制为“冰激凌-游戏时间图”如下:
准备数据:归一化
归一化就是把数据范围限制在某个明确的范围之内,比如接下来我们就需要把数据统一到(0,1)范围内,方便后续的数据处理。代码如下:def autonorm(dataset): """ dataset normalization @param dataset: cd64 np.array @return: dataset after norm, ranges, minimal value """ min_val = dataset.min(0) max_val = dataset.max(0) ranges = max_val - min_val norm_dataset = zeros(shape(dataset)) m = dataset.shape[0] norm_dataset = dataset - tile(min_val, (m, 1)) norm_dataset = norm_dataset/tile(ranges, (m, 1)) return norm_dataset, ranges, min_val
测试算法
编写针对此示例的算法测试代码:def dating_class_test(): """ dating data test and see the error ratio @return: the output on screen which shows the result and the error rate """ ho_ratio = 0.1 # the ratio of test data dating_data_mat, dating_labels = file2matrix('datingTestSet2.txt') norm_mat, ranges, min_val = autonorm(dating_data_mat) m = norm_mat.shape[0] num_test_vec = int(m*ho_ratio) error_count = 0.0 for i in range(num_test_vec): # large scale data is used to be trained and small data is used to be test. 0:num_test_vec is small and # num_test_vec:m is large classify_result = classify0(norm_mat[i, :], norm_mat[num_test_vec:m, :], dating_labels[num_test_vec:m], 3) print("the classifier came back with: %d, the real answer is %d" % (classify_result, dating_labels[i])) if classify_result != dating_labels[i]: error_count += 1.0 print("the total error rate is: %f%%" % (error_count/float(num_test_vec)*100.0))
代码结果演示如下:
使用算法
将此算法应用于具体的应用之内,根据一个人的三个标签特征判断他对Helen的吸引力程度:def classify_person(): """ Test the charm of a person to you @return: print the result """ result_list = ['not at all', 'in small doses', 'in large doses'] percent_games = float(input('Percentage of time spent playing video games: ')) length_miles = float(input('Frequent flier miles earned per year: ')) ice_cream = float(input('Liters of ice cream consumed per year: ')) dating_data_mat, dating_labels = file2matrix('datingTestSet2.txt') norm_mat, ranges, min_val = autonorm(dating_data_mat) in_arr = array([length_miles, percent_games, ice_cream]) class_fier_result = classify0((in_arr - min_val)/ranges, norm_mat, dating_labels, 3) print('You will probably like this person: ', result_list[class_fier_result-1])
算法运行结果如下:
怎么样,你是否也能捕获Helen的芳心呢(坏笑…)
示例2:手写识别系统
通过kNN算法将如下图所示的32*32数据进行判断:准备数据:图像转换为测试向量
在这里,需要将数据从32*32转换为1*1024,有两种方法可行,第一种是书中的方法,即通过循环直接进行前后连接,第二种是直接使用numpy的flatten()方法,如下图所示:这里以书中的方法为例:
def img2vector(filename): """ change the 32*32 image matrix to 1*1024 array @param filename: the data set filename @return: the 1*1024 array """ return_vect = zeros((1, 1024)) with open(filename) as fr: for i in range(32): line_str = fr.readline() for j in range(32): return_vect[0, 32*i+j] = int(line_str[j]) return return_vect
测试算法:使用kNN算法识别手写数字
def handwriting_class_test(): """ handwriting test @return: screen output """ hw_labels = [] training_file_list = listdir('trainingDigits') m = len(training_file_list) training_mat = zeros((m, 1024)) for i in range(m): file_name_str = training_file_list[i] file_str = file_name_str.split('.')[0] class_num_str = int(file_str.split('_')[0]) hw_labels.append(class_num_str) training_mat[i, :] = img2vector('trainingDigits/%s' % file_name_str) test_file_list = listdir('testDigits') error_count = 0.0 m_test = len(test_file_list) for i in range(m_test): file_name_str = test_file_list[i] file_str = file_name_str.split('.')[0] class_num_str = int(file_str.split('_')[0]) vector_under_test = img2vector('trainingDigits/%s' % file_name_str) classifier_result = classify0(vector_under_test, training_mat, hw_labels, 3) print('the classifier came back with: %d, the real answer is: %d' % (classifier_result, class_num_str)) if classifier_result != class_num_str: error_count += 1.0 print('\nthe total number of errors is %d' % error_count) print('\nthe total error rate is %f' % (error_count/float(m_test)))
运行结果如下:
更改数据量及k值可改变错误率。实测将k值缩小后错误率可降低至0.0%。
测试代码
# coding=utf-8 """ knn algorithm test file """ import kNN import numpy as np import matplotlib import matplotlib.pyplot as plt group, labels = kNN.create_dataset() print(kNN.classify0([0, 0], group, labels, 3)) dating_data_mat, dating_labels = kNN.file2matrix('datingTestSet2.txt') print(dating_data_mat) print(dating_labels) fig = plt.figure() ax = fig.add_subplot(111) # ax.scatter(dating_data_mat[:, 1], dating_data_mat[:, 2], 10*np.array(dating_labels), 10*np.array(dating_labels)) type1_x = [] type1_y = [] type2_x = [] type2_y = [] type3_x = [] type3_y = [] for i in range(len(dating_labels)): if dating_labels[i] == 1: # unlike type1_x.append(dating_data_mat[i][1]) type1_y.append(dating_data_mat[i][2]) if dating_labels[i] == 2: # like type2_x.append(dating_data_mat[i][1]) type2_y.append(dating_data_mat[i][2]) if dating_labels[i] == 3: # very like type3_x.append(dating_data_mat[i][1]) type3_y.append(dating_data_mat[i][2]) type1 = ax.scatter(type1_x, type1_y, s=20) type2 = ax.scatter(type2_x, type2_y, s=30) type3 = ax.scatter(type3_x, type3_y, s=40) ax.legend((type1, type2, type3), ('unlike', 'like', 'very_like')) plt.xlabel('the Percentage of Playing Games') plt.ylabel('the Cost of Ice-Creams per Week') plt.title('the Data Set Distribution Figure') plt.legend() plt.show(fig) norm_mat, ranges, min_val = kNN.autonorm(dating_data_mat) print(norm_mat) print(ranges) print(min_val) # kNN.dating_class_test() # kNN.classify_person() # kNN.handwriting_class_test()
不定期更新,未完待续。。。
相关文章推荐
- Python 学习笔记(Machine Learning In Action)K-近邻算法(KNN)机器学习实战
- 机器学习笔记--KNN算法2-实战部分
- 机器学习实战笔记--kNN
- 机器学习实战之kNN算法
- 机器学习实战之knn算法pandas实现
- 机器学习实战 kNN算法
- 机器学习实战笔记(3.1)-朴素贝叶斯算法(原理分析)
- 机器学习实战之KNN算法
- 机器学习实战第二章——KNN算法(源码解析)
- 机器学习实战第二章 KNN算法的实现
- 机器学习实战笔记(1)——k-近邻算法
- 机器学习实战学习笔记 一 k-近邻算法
- <机器学习实战 >KNN算法 改进约会网站的配对效果
- 机器学习实战-kNN笔记
- 机器学习实战python版归一化数值和测试kNN算法以及构建完整可用系统
- 机器学习实战笔记 k-近邻算法
- 机器学习实战笔记之二(k-近邻算法)
- 机器学习实战-kNN算法 学习随手记
- 机器学习实战学习笔记11——FP-growth 算法
- 机器学习实战——python实现knn算法