美文网首页
实验四、数据挖掘之KNN,Naive Bayes

实验四、数据挖掘之KNN,Naive Bayes

作者: keeeeeenon | 来源:发表于2019-06-28 20:19 被阅读0次

    实验四、数据挖掘之KNN,Naive Bayes

    一、实验目的

    1. 掌握KNN的原理

    2. 掌握Naive Bayes的原理

    3. 学会利用KNN与Navie Bayes解决分类问题

    二、实验工具

    1. Anaconda

    2. sklearn

    三、实验简介

    1. KNN

    KNN(K-Nearest Neighbor)工作原理:存在一个样本数据集合,也称为训练样本集,并且样本集中每个数据都存在标签,即我们知道样本集中每一数据与所属分类对应的关系。输入没有标签的数据后,将新数据中的每个特征与样本集中数据对应的特征进行比较,提取出样本集中特征最相似数据(最近邻)的分类标签。一般来说,我们只选择样本数据集中前k个最相似的数据,这就是k近邻算法中k的出处,通常k是不大于20的整数。最后选择k个最相似数据中出现次数最多的分类作为新数据的分类。

    说明:KNN没有显示的训练过程,它是“懒惰学习”的代表,它在训练阶段只是把数据保存下来,训练时间开销为0,等收到测试样本后进行处理。

    2. Navie Bayes

    朴素贝叶斯分类器中最核心的便是贝叶斯准则,他用如下的公式表示:
    p(c|x)= \frac{p(x|c)p(c)}{p(x)}

    在机器学习中,朴素贝叶斯分类器是一个基于贝叶斯定理的比较简单的概率分类器,其中 naive(朴素)是指的对于模型中各个 feature(特征) 有强独立性的假设,并未将 feature 间的相关性纳入考虑中。

    朴素贝叶斯分类器一个比较著名的应用是用于对垃圾邮件分类,通常用文字特征来识别垃圾邮件,是文本分类中比较常用的一种方法。朴素贝叶斯分类通过选择 token(通常是邮件中的单词)来得到垃圾邮件和非垃圾邮件间的关联,再通过贝叶斯定理来计算概率从而对邮件进行分类。

    四、实验内容

    1. 利用KNN对鸢尾花数据进行分类。

    (1) 调用数据的方法如下:

    from sklearn.datasets import load_iris
    iris = load_iris()# 从sklearn 数据集中获取鸢尾花数据。
    

    (2)数据进行KNN分类

    from sklearn.datasets import load_iris
    iris = load_iris()
    #第一步:读取Iris数据集资料
    
    #查看数据规模
    print (iris.data.shape)
    #查看数据说明,要养成看数据说明的好习惯
    print (iris.DESCR)
    #由数据描述可知,iris数据集中共有150多鸢尾花,每朵花都有四个特征值,并均匀分布在3个不同的亚种。
    
    #第二步:对原始数据进行数据分割
    from sklearn.cross_validation import train_test_split
    X_train,X_test,y_train,y_test=train_test_split(iris.data,iris.target,test_size=0.25,random_state=33)
    
    #第三步: 使用KNN分类器训练模型并预测
    from sklearn.preprocessing import StandardScaler
    ss = StandardScaler()
    X_train = ss.fit_transform(X_train)
    X_test = ss.transform(X_test)
    #导入knn分类器
    from sklearn.neighbors import KNeighborsClassifier
    knc = KNeighborsClassifier()
    knc.fit(X_train,y_train)
    y_predict = knc.predict(X_test)
    
    #第四步:对KNN分类器的预测性能进行评估
    from sklearn.metrics import classification_report
    print( 'Accuracy of knc:',knc.score(X_test,y_test))
    print( classification_report(y_predict,y_test,target_names=iris.target_names))
    
    image.png

    2. 利用Navie Bayes对鸢尾花数据建模

    # 通过朴素贝叶斯对鸢尾花数据进行分类
    
    from sklearn import datasets
    from sklearn.model_selection import train_test_split
    from sklearn.naive_bayes import MultinomialNB, GaussianNB
    import matplotlib.pyplot as plt
    import numpy as np
    import matplotlib as mpl
    from sklearn.preprocessing import StandardScaler
    from sklearn.pipeline import Pipeline
    
    iris = datasets.load_iris() # 加载鸢尾花数据
    iris_x = iris.data  # 获取数据
    # print(iris_x)
    iris_x = iris_x[:, :2]  # 取前两个特征值
    # print(iris_x)
    iris_y = iris.target    # 0, 1, 2
    x_train, x_test, y_train, y_test = train_test_split(iris_x, iris_y, test_size=0.75, random_state=1) # 对数据进行分类 一部分最为训练一部分作为测试
    # clf = GaussianNB()
    # ir = clf.fit(x_train, y_train)
    clf = Pipeline([
            ('sc', StandardScaler()),
            ('clf', GaussianNB())])     # 管道这个没深入理解 所以不知所以然
    ir = clf.fit(x_train, y_train.ravel())  # 利用训练数据进行拟合
    
    # 画图:   
    x1_max, x1_min = max(x_test[:, 0]), min(x_test[:, 0])   # 取0列特征得最大最小值
    x2_max, x2_min = max(x_test[:, 1]), min(x_test[:, 1])   # 取1列特征得最大最小值
    t1 = np.linspace(x1_min, x1_max, 500)   # 生成500个测试点
    t2 = np.linspace(x2_min, x2_max, 500)   
    x1, x2 = np.meshgrid(t1, t2)  # 生成网格采样点
    x_test1 = np.stack((x1.flat, x2.flat), axis=1)
    y_hat = ir.predict(x_test1) # 预测
    mpl.rcParams['font.sans-serif'] = [u'simHei']   # 识别中文保证不乱吗
    mpl.rcParams['axes.unicode_minus'] = False
    cm_light = mpl.colors.ListedColormap(['#77E0A0', '#FF8080', '#A0A0FF']) # 测试分类的颜色
    cm_dark = mpl.colors.ListedColormap(['g', 'r', 'b'])    # 样本点的颜色
    plt.figure(facecolor='w')
    plt.pcolormesh(x1, x2, y_hat.reshape(x1.shape), cmap=cm_light)  # y_hat  25000个样本点的画图,
    plt.scatter(x_test[:, 0], x_test[:, 1], edgecolors='k', s=50, c=y_test, cmap=cm_dark)   # 测试数据的真实的样本点(散点) 参数自行百度
    plt.xlabel(u'花萼长度', fontsize=14)
    plt.ylabel(u'花萼宽度', fontsize=14)
    plt.title(u'GaussianNB对鸢尾花数据的分类结果', fontsize=18)
    plt.grid(True)
    plt.xlim(x1_min, x1_max)
    plt.ylim(x2_min, x2_max)
    plt.show()
    y_hat1 = ir.predict(x_test)
    result = y_hat1 == y_test
    print(result)
    acc = np.mean(result)
    print('准确度: %.2f%%' % (100 * acc))
    
    image.png
    image.png

    3. 不使用sklearn中的分类方法,自己编写KNN程序(建议用python语言),并对鸢尾花数据进行分类。

    
    import numpy as np
    import pandas as pd
    from sklearn.datasets import load_iris
    iris = load_iris()# 从sklearn 数据集中获取鸢尾花数据。
    #读取数据集,header参数来指定参数标题的行,默认为0,第一行,如果没有标题使用None
    data = iris.data
    #data = pd.read_csv('iris.csv',header=0)
    #对文本进行处理,将Species列的文本映射成数值类型
    #data['Species'] = data['Species'].map({'Iris-virginica':0,'Iris-setosa':1,'Iris-versicolor':2})
    #data.head(20)
    #显示末尾行数
    # data.tail(20)
    #随机显示,默认为1条
    data.sample(10)
    #删除不需要的列
    data.drop("id",axis=1,inplace=True)
    #重复值检查,any(),一旦有重复值,就返回True
    data.duplicated().any()
    #删除重复的数据
    data.drop_duplicates(inplace=True)
    #查看各类别的数据条数
    data['Species'].value_counts()
    #编写KNN类
    class KNN:
        """使用python实现K近邻算法"""
        def __init__(self,k):
            """初始化方法
            
            Parameters:
            ----
            k:int
                邻居的个数
            """
            self.k = k
        
        def fit(self, X, y):
            """训练方法
            Parameters
            ----
                X:类似数组类型,list,ndarray……形状:[样本的数量,特征的数量]
                y:类似数组类型,形状为[样本数量]
                    每个样本的目标值,也是就是标签
            """
            #将X转换成ndarray类型,如果X已经是ndarray则不进行转换
            self.X = np.asarray(X)
            self.y = np.asarray(y)
        
        def predict(self, X):
            """根据参数传递的样本,对样本数据进行预测,返回预测之后的结果
            
            Parameters
            ----
            X:类似数组类型,list,ndarray……形状:[样本的数量,特征的数量]
            
            Return
            ----
            result:数类型,预测的结果。
            """
            
            #将测试的X转换为ndarray结构
            X = np.asarray(X)
            result = []
            
            for x in X:
                #ndarray相减为对应元素相减,测试的X的每一行与self.X 相减
                #求欧氏距离:每个元素都取平方值
                dis = np.sqrt(np.sum((x - self.X) ** 2,axis = 1))
                #求最近的k个点的距离,sort()排序不适用,因为排序后打乱了顺序
                #argsort(),返回每个元素在排序之前原数组的索引
                index = dis.argsort()
                #取前k个元素,距离最近的k的元素
                index = index[:self.k]
                #返回数组中每个元素出现的次数,元素必须是非负整数
                count = np.bincount(self.y[index])
                #返回ndarray之最大的元素的索引,该索引就是我们判定的类别
                result.append(count.argmax())
            return np.asarray(result)
        
        def predict2(self, X):
            """根据参数传递的样本,对样本数据进行预测(考虑权重,使用距离的倒数作为权重),返回预测之后的结果
            
            Parameters
            ----
            X:类似数组类型,list,ndarray……形状:[样本的数量,特征的数量]
            
            Return
            ----
            result:数类型,预测的结果。
            """
            
            #将测试的X转换为ndarray结构
            X = np.asarray(X)
            result = []
            
            for x in X:
                #ndarray相减为对应元素相减,测试的X的每一行与self.X 相减
                #求欧氏距离:每个元素都取平方值
                dis = np.sqrt(np.sum((x - self.X) ** 2,axis = 1))
                #求最近的k个点的距离,sort()排序不适用,因为排序后打乱了顺序
                #argsort(),返回每个元素在排序之前原数组的索引
                index = dis.argsort()
                #取前k个元素,距离最近的k的元素
                index = index[:self.k]
                #返回数组中每个元素出现的次数,元素必须是非负整数,【使用weight考虑权重,权重为距离的倒数】
                count = np.bincount(self.y[index],weights=1/dis[index])
                #返回ndarray之最大的元素的索引,该索引就是我们判定的类别
                result.append(count.argmax())
            return np.asarray(result)
        
    #数据集拆分成训练集和测试集
    #1、提取每个类别鸢尾花的数量
    t0 = data[data['Species']==0]
    t1 = data[data['Species']==1]
    t2 = data[data['Species']==2]
     
    #打乱顺序,random_state ,记住打乱的顺序
    t0 = t0.sample(len(t0),random_state=0)
    t1 = t1.sample(len(t1),random_state=0)
    t2 = t2.sample(len(t2),random_state=0)
    train_X = pd.concat([t0.iloc[:40,:-1],t1.iloc[:40,:-1],t2.iloc[:40,:-1]],axis=0)
    train_Y = pd.concat([t0.iloc[:40,-1],t1.iloc[:40,-1],t2.iloc[:40,-1]],axis=0)
    test_X = pd.concat([t0.iloc[40:,:-1],t1.iloc[40:,:-1],t2.iloc[40:,:-1]],axis=0)
    test_Y = pd.concat([t0.iloc[40:,-1],t1.iloc[40:,-1],t2.iloc[40:,-1]],axis=0)
     
    #进行训练与测试
    knn = KNN(k=3)
    #进行训练
    knn.fit(train_X,train_Y)
    #进行测试
    result = knn.predict(test_X)
    # display(result)
    # display(test_Y)
    #查看预测结果
    display(np.sum(result == test_Y))
    #对计算结果进行可视化展示
    import matplotlib as mpl
    import matplotlib.pyplot as plt
    #设置matplotlib 支持中文显示
    mpl.rcParams['font.family'] = 'SimHei' #设置字体为黑体
    mpl.rcParams['axes.unicode_minus'] = False #设置在中文字体是能够正常显示负号(“-”)
     
    #设置画布大小
    plt.figure(figsize=(10,10))
    #挑选维度进行散点图显示
    #绘制训练集的散点图'Iris-virginica':0,'Iris-setosa':1,'Iris-versicolor':2
    plt.scatter(x=t0['SepalLengthCm'][:40],y=t0['PetalLengthCm'][:40],color='r',label='Iris-virginica')
    plt.scatter(x=t1['SepalLengthCm'][:40],y=t1['PetalLengthCm'][:40],color='g',label='Iris-setosa')
    plt.scatter(x=t2['SepalLengthCm'][:40],y=t2['PetalLengthCm'][:40],color='b',label='Iris-versicolor')
     
    #绘制测试集数据,使用不同的图案显示预测正确和错误的结果
    right = test_X[result == test_Y]
    wrong = test_X[result != test_Y]
    plt.scatter(x=right['SepalLengthCm'],y=right['PetalLengthCm'],color='c',marker='x',label='right')
    plt.scatter(x=wrong['SepalLengthCm'],y=wrong['PetalLengthCm'],color='m',marker='>',label='wrong')
     
    #显示额外信息
    plt.xlabel("花萼长度")
    plt.ylabel("花瓣长度")
    plt.title("KNN分类显示结果")
    plt.legend(loc="best")
    plt.show()
    

    4. (选做) 不使用sklearn中的分类方法,自己编写Navie Bayes程序(建议用python语言),并对鸢尾花数据进行分类。

    五、实验总结(写出本次实验的收获,遇到的问题等)

    KNN计算步骤

    1)算距离:给定测试对象,计算它与训练集中的每个对象的距离

    2)找邻居:圈定距离最近的k个训练对象,作为测试对象的近邻

    3)做分类:根据这k个近邻归属的主要类别,来对测试对象分类
    在实验过程中发现knn样本不平衡容易导致结果错误,而且计算量较大

    相关文章

      网友评论

          本文标题:实验四、数据挖掘之KNN,Naive Bayes

          本文链接:https://www.haomeiwen.com/subject/cjfycctx.html