• 机器学习实战_KNN(一)


    【是什么】

    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('	')
            # 将文本中的前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%% 
    " %((1 - error_count / numTestData)*100))

     从结果看 识别率还是很低的,目前k值为4 ,可以改变k值看看正确率的变化

    完整代码

      1 #!/usr/bin/python
      2 # -*- coding: UTF-8 -*-
      3 """
      4    【KNN 实战】
      5 
      6 """
      7 import  numpy as np
      8 import matplotlib.pyplot as plt
      9 import matplotlib.lines as mlines
     10 from matplotlib.font_manager import FontProperties
     11 import operator
     12 
     13 # 提取文件中的数据 转换成矩阵
     14 def file2matric(filename):
     15     """
     16     disc:
     17     param: filename: 导入数据文本
     18     return: 数据矩阵
     19     """
     20     f = open(filename,'r',encoding= 'utf-8')
     21     # 获取文件的行数
     22     lines_list = f.readlines()
     23     num_of_lines = len(lines_list)
     24     # 创建存放标签的列表
     25     class_label_list = []
     26     # 生成对应的空矩阵 zeros(2,3) 就是生成2行3列的0矩阵
     27     returnMat = np.zeros((num_of_lines,3))
     28     # 将文本中的数据放到矩阵中
     29     for i in range(num_of_lines):
     30         lines = lines_list[i].strip().split('	')
     31         # 将文本中的前3个数据放到矩阵中
     32         returnMat[i,:] = lines[0:3]
     33         # 将标签存到列表中
     34         class_label_list.append(int(lines[-1]))
     35 
     36     # print(returnMat)
     37     return returnMat, class_label_list
     38 
     39 def DrawScatter(dataMat,label_list):
     40     # 导入中文字体,及字体大小
     41     zhfont = FontProperties(fname='C:/Windows/Fonts/simsun.ttc', size=14)
     42     # 绘制绘图窗口 2行2列
     43     fig,ax = plt.subplots(2,2,figsize=(13,8))
     44     # 不同标签赋予不同颜色
     45     label_color = []
     46     for i in label_list:
     47         if i == 1:
     48             label_color.append('black')
     49         elif i == 2:
     50             label_color.append('orange')
     51         elif i == 3:
     52             label_color.append('red')
     53     # 开始绘制散点图 设定散点尺寸与透明度
     54     scatter_size = 12
     55     scatter_alpha = 0.5
     56     # ===================散点图========================
     57     ax[0][0].scatter(dataMat[:,0], dataMat[:,1],color = label_color,s = scatter_size ,alpha = scatter_alpha)
     58     ax[0][1].scatter(dataMat[:, 1], dataMat[:, 2], color=label_color, s=scatter_size , alpha=scatter_alpha)
     59     ax[1][0].scatter(dataMat[:, 0], dataMat[:, 2], color=label_color, s=scatter_size , alpha=scatter_alpha)
     60 
     61     # 坐标轴标题
     62     title_list = ['每年获得的飞行常客里程数和玩视频游戏所消耗时间占比',
     63                   '每年获得的飞行常客里程数和每周消费的冰激淋公升数',
     64                   '玩视频游戏所消耗时间占比和每周消费的冰激淋公升数']
     65     x_name_list = ['每年获得的飞行常客里程数','玩视频游戏所消耗时间占比','每周消费的冰激淋公升数']
     66     y_name_list = ['玩视频游戏所消耗时间占比','每周消费的冰激淋公升数','每年获得的飞行常客里程数']
     67     #设置图例
     68     didntLike = mlines.Line2D([], [], color='black', marker='.',
     69                       markersize=6, label='didntLike')
     70     smallDoses = mlines.Line2D([], [], color='orange', marker='.',
     71                       markersize=6, label='smallDoses')
     72     largeDoses = mlines.Line2D([], [], color='red', marker='.',
     73                       markersize=6, label='largeDoses')
     74 
     75     p = 0
     76     for i in range(2):
     77         for j in range(2):
     78             if p > 2:
     79                 break
     80             # 设置坐标轴名称和标题
     81             plt.setp(ax[i][j].set_title(u'%s'%(title_list[p]),FontProperties = zhfont),size=9, weight='bold', color='red')
     82             plt.setp(ax[i][j].set_xlabel(u'%s'%(x_name_list[p]),FontProperties = zhfont), size=7, weight='bold', color='black')
     83             plt.setp(ax[i][j].set_ylabel(u'%s'%(y_name_list[p]),FontProperties = zhfont), size=7, weight='bold', color='black')
     84             p+=1
     85     # 添加图例
     86     ax[0][0].legend(handles=[didntLike, smallDoses, largeDoses])
     87     ax[0][1].legend(handles=[didntLike, smallDoses, largeDoses])
     88     ax[1][0].legend(handles=[didntLike, smallDoses, largeDoses])
     89     plt.savefig('.\123.png', bbox_inches='tight')
     90     plt.show()
     91 
     92 # 对矩阵进行归一化处理
     93 def dataNorm(dataMat):
     94     """
     95     :param dataMat:
     96     :return: 归一化后的数据集
     97     归一化公式: Y = (X - Xmin)/(Xmax - Xmin)
     98     """
     99     # max(0) min(0) 求出每列的最大值和最小值
    100     d_min = dataMat.min(0)
    101     d_max = dataMat.max(0)
    102     # 计算极差
    103     d_ranges = d_max - d_min
    104     # 创建输出矩阵
    105     normDataSet = np.zeros(np.shape(dataMat))
    106     print(normDataSet)
    107     # 获得矩阵行数 .shape 获取矩阵的大小  3x3
    108     m = dataMat.shape[0]
    109     # 计算 (X - Xmin) 这部分 首先要创建Xmin矩阵 将d_min扩展到m行
    110     # 需要使用np.tile 函数进行扩展   将d_min扩展成m行1列 变成m x 3 矩阵
    111     normDataSet = dataMat - np.tile(d_min,(m,1))
    112     print(normDataSet)
    113     # 计算Y
    114     normDataSet = normDataSet / np.tile(d_ranges,(m,1))
    115 
    116     print(normDataSet)
    117     return normDataSet
    118 
    119 def classfy_fun(test_data, train_data, labels, k):
    120     """
    121 
    122     :param test_data: 测试集
    123     :param train_data: 训练集
    124     :param labels: 训练集标签
    125     :param k:  KNN 算法参数 选择距离最小的个数
    126     :return:  分类结果
    127     """
    128     # 计算训练集的矩阵行数
    129     train_size = train_data.shape[0]
    130     # 接下来按照欧氏距离进行元素距离计算 公式
    131     #     将测试集扩充成与训练集相同行数 求差
    132     diffMat = np.tile(test_data,(train_size,1)) - train_data
    133     # 将差值矩阵的每个元素平方
    134     sq_diffMat = diffMat**2
    135     # 差值平方矩阵每行元素相加 axis = 1 是按行相加
    136     sum_diffMat = sq_diffMat.sum(axis = 1)
    137     # 对新的求和矩阵进行开方 得到距离值
    138     distances = sum_diffMat ** 0.5
    139     # 获得距离值中从小到大值的索引
    140     sorted_distant = distances.argsort()
    141     # 定义一个字典 存放标签 与 出现的数量
    142     class_count = {}
    143     for i in range(k):
    144         # 找出前k个距离值最小的对应标签
    145         temp_label = labels[sorted_distant[i]]
    146         # 将标签作为 key 存放到字典中 出现次数作为 value
    147         class_count[temp_label] = class_count.get(temp_label,0) + 1
    148     # 将字典按照value 大小进行排序
    149     sort_class_count = sorted(class_count.items(),key = operator.itemgetter(1))
    150     return sort_class_count[0][0]
    151     pass
    152 # 创建分类器函数
    153 def dating_class_test():
    154 
    155     # 首先获取文件,将文件分成测试集和训练集
    156     dating_Mat, dating_label = file2matric('datingdata.txt')
    157     # 设置测试集的比例
    158     test_ratio = 0.1
    159     # 数据归一化
    160     normMat = dataNorm(dating_Mat)
    161     #获得矩阵的行数
    162     m = normMat.shape[0]
    163     # 计算测试集的数量
    164     numTestData = int(m * test_ratio)
    165     # 错误分类的数量
    166     error_count = 0.0
    167 
    168     for i in range(numTestData):
    169         class_result = classfy_fun(dating_Mat[i,:], dating_Mat[numTestData:m,:],
    170                                    dating_label[numTestData:m],4 )
    171         print("分类结果:%s,实际分类:%s"%(class_result,dating_label[i]))
    172         if class_result != dating_label[i]:
    173             error_count += 1
    174     # print("错误识别的数量:%f" %error_count)
    175     print("正确率:%f%% 
    " %((1 - error_count / numTestData)*100))
    176 
    177 def main():
    178     # reMat, label = file2matric('datingdata.txt')
    179     # DrawScatter(reMat,label )
    180     # dataNorm(reMat)
    181     # 测试分类情况
    182     dating_class_test()
    183     pass
    184 
    185 
    186 if __name__ =='__main__':
    187     main()
    View Code
  • 相关阅读:
    unity3D相机缓慢看向目标物体
    设计原则
    unity3D中GUI标题内文字滚动效果
    python3.6中安装PyQt报错
    codeforces 515B.Drazil and His Happy Friends
    HDU 1029 Ignatius and the Princess IV
    POJ 1052 Plato's Blocks
    Uva220 Othello
    uva201 Squares
    uva1587 Box
  • 原文地址:https://www.cnblogs.com/wangxiaobei2019/p/11612787.html
Copyright © 2020-2023  润新知