机器学习实战_KNN(一)

匿名 (未验证) 提交于 2019-12-03 00:13:02

【是什么】

KNN 即 k_近邻算法(k- nearest neighbor) ,就是寻找K个邻居作为该样本的特征,近朱者赤,近墨者黑,你的邻居是什么特征,那么就认为你也具备该特征核心公式为:

 

 

数据来源:https://github.com/apachecn/AiLearning/blob/master/data/2.KNN/datingTestSet2.txt

读取数据转换成矩阵

# 提取文件中的数据 转换成矩阵 def file2matric(filename):     """     disc:     param: filename: 导入数据文本     return: 数据矩阵     """     f = open(filename,'r',encoding= 'utf-8')     # 获取文件的行数     lines_list = f.readlines()     num_of_lines = len(lines_list)     # 创建存放标签的列表     class_label_list = []     # 生成对应的空矩阵 zeros(2,3) 就是生成2行3列的0矩阵     returnMat = np.zeros((num_of_lines,3))     # 将文本中的数据放到矩阵中     for i in range(num_of_lines):         lines = lines_list[i].strip().split('\t')         # 将文本中的前3个数据放到矩阵中         returnMat[i,:] = lines[0:3]         # 将标签存到列表中         class_label_list.append(int(lines[-1]))      # print(returnMat)     return returnMat, class_label_list

 

利用 matplotlib 绘制散点图

def DrawScatter(dataMat,label_list):     # 导入中文字体,及字体大小     zhfont = FontProperties(fname='C:/Windows/Fonts/simsun.ttc', size=14)     # 绘制绘图窗口 2行2列     fig,ax = plt.subplots(2,2,figsize=(13,8))     # 不同标签赋予不同颜色     label_color = []     for i in label_list:         if i == 1:             label_color.append('black')         elif i == 2:             label_color.append('orange')         elif i == 3:             label_color.append('red')     # 开始绘制散点图 设定散点尺寸与透明度     scatter_size = 12     scatter_alpha = 0.5     # ===================散点图========================     ax[0][0].scatter(dataMat[:,0], dataMat[:,1],color = label_color,s = scatter_size ,alpha = scatter_alpha)     ax[0][1].scatter(dataMat[:, 1], dataMat[:, 2], color=label_color, s=scatter_size , alpha=scatter_alpha)     ax[1][0].scatter(dataMat[:, 0], dataMat[:, 2], color=label_color, s=scatter_size , alpha=scatter_alpha)      # 坐标轴标题     title_list = ['每年获得的飞行常客里程数和玩视频游戏所消耗时间占比',                   '每年获得的飞行常客里程数和每周消费的冰激淋公升数',                   '玩视频游戏所消耗时间占比和每周消费的冰激淋公升数']     x_name_list = ['每年获得的飞行常客里程数','玩视频游戏所消耗时间占比','每周消费的冰激淋公升数']     y_name_list = ['玩视频游戏所消耗时间占比','每周消费的冰激淋公升数','每年获得的飞行常客里程数']     #设置图例     didntLike = mlines.Line2D([], [], color='black', marker='.',                       markersize=6, label='didntLike')     smallDoses = mlines.Line2D([], [], color='orange', marker='.',                       markersize=6, label='smallDoses')     largeDoses = mlines.Line2D([], [], color='red', marker='.',                       markersize=6, label='largeDoses')      p = 0     for i in range(2):         for j in range(2):             if p > 2:                 break             # 设置坐标轴名称和标题             plt.setp(ax[i][j].set_title(u'%s'%(title_list[p]),FontProperties = zhfont),size=9, weight='bold', color='red')             plt.setp(ax[i][j].set_xlabel(u'%s'%(x_name_list[p]),FontProperties = zhfont), size=7, weight='bold', color='black')             plt.setp(ax[i][j].set_ylabel(u'%s'%(y_name_list[p]),FontProperties = zhfont), size=7, weight='bold', color='black')             p+=1     # 添加图例     ax[0][0].legend(handles=[didntLike, smallDoses, largeDoses])     ax[0][1].legend(handles=[didntLike, smallDoses, largeDoses])     ax[1][0].legend(handles=[didntLike, smallDoses, largeDoses])      plt.show()

 

 

 对数据进行归一化处理

由于不同数据的范围波动不同,在权重一样的情况下,需要进行归一化,即将数据转换成0-1之间

# 对矩阵进行归一化处理 def dataNorm(dataMat):     """     :param dataMat:     :return: 归一化后的数据集     归一化公式: Y = (X - Xmin)/(Xmax - Xmin)     """     # max(0) min(0) 求出每列的最大值和最小值     d_min = dataMat.min(0)     d_max = dataMat.max(0)     # 计算极差     d_ranges = d_max - d_min     # 创建输出矩阵     normDataSet = np.zeros(np.shape(dataMat))     print(normDataSet)     # 获得矩阵行数 .shape 获取矩阵的大小  3x3     m = dataMat.shape[0]     # 计算 (X - Xmin) 这部分 首先要创建Xmin矩阵 将d_min扩展到m行     # 需要使用np.tile 函数进行扩展   将d_min扩展成m行1列 变成m x 3 矩阵     normDataSet = dataMat - np.tile(d_min,(m,1))     print(normDataSet)     # 计算Y     normDataSet = normDataSet / np.tile(d_ranges,(m,1))      print(normDataSet)     return normDataSet

创建分类函数与分类器(kNN算法的实现)

  (ps:每次都需要将测试数据与所有训练数据进行对比,感觉比较繁琐)

def classfy_fun(test_data, train_data, labels, k):     """      :param test_data: 测试集     :param train_data: 训练集     :param labels: 训练集标签     :param k:  KNN 算法参数 选择距离最小的个数     :return:  分类结果     """     # 计算训练集的矩阵行数     train_size = train_data.shape[0]     # 接下来按照欧氏距离进行元素距离计算 公式     #     将测试集扩充成与训练集相同行数 求差     diffMat = np.tile(test_data,(train_size,1)) - train_data     # 将差值矩阵的每个元素平方     sq_diffMat = diffMat**2     # 差值平方矩阵每行元素相加 axis = 1 是按行相加     sum_diffMat = sq_diffMat.sum(axis = 1)     # 对新的求和矩阵进行开方 得到距离值     distances = sum_diffMat ** 0.5     # 获得距离值中从小到大值的索引     sorted_distant = distances.argsort()     # 定义一个字典 存放标签 与 出现的数量     class_count = {}     for i in range(k):         # 找出前k个距离值最小的对应标签         temp_label = labels[sorted_distant[i]]         # 将标签作为 key 存放到字典中 出现次数作为 value         class_count[temp_label] = class_count.get(temp_label,0) + 1     # 将字典按照value 大小进行排序     sort_class_count = sorted(class_count.items(),key = operator.itemgetter(1))     return sort_class_count[0][0]     pass # 创建分类器函数 def dating_class_test():      # 首先获取文件,将文件分成测试集和训练集     dating_Mat, dating_label = file2matric('datingdata.txt')     # 设置测试集的比例     test_ratio = 0.1     # 数据归一化     normMat = dataNorm(dating_Mat)     #获得矩阵的行数     m = normMat.shape[0]     # 计算测试集的数量     numTestData = int(m * test_ratio)     # 错误分类的数量     error_count = 0.0      for i in range(numTestData):         class_result = classfy_fun(dating_Mat[i,:], dating_Mat[numTestData:m,:],                                    dating_label[numTestData:m],4 )         print("分类结果:%s,实际分类:%s"%(class_result,dating_label[i]))         if class_result != dating_label[i]:             error_count += 1     # print("错误识别的数量:%f" %error_count)     print("正确率:%f%% \n" %((1 - error_count / numTestData)*100))

 

 从结果看 识别率还是很低的,

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!