zoukankan      html  css  js  c++  java
  • 人工智能_4_k近邻_贝叶斯_模型评估

    机器学习常用算法
    k近邻算法
      求出未知点 与周围最近的 k个点的距离
      查看这k个点中大多数是哪一类
      根号((x已知-x未知)^2+(y已知-y未知)^2)  即平面间2点距离公式
      收异常点影响较大,因此需要做标准化处理
      API:sklearn.neighbors.KNeighborsClassifier(n_neighbors=5,algorithm="auto")
          algorithm:{"auto","ball_tree","kd_tree","brute"}
              效率不同
              ball_tree:会使用BallTree
              kd_tree:会使用KdTree
              auto:尝试根据传递的fit方法的值决定最适合的算法
          n_neighbors: 邻居数,默认为5
    处理:
      时间特征:需要转为年,月,日,时,分,秒 ,当做几个新的特征处理,并不是全部要加入,要根据结果选择加入
      目标值:可以去掉某些目标值
    from sklearn.neighbors import KNeighborsClassifier
    def knnCls():
        """
        预测鸢尾花的种类
        :return:
        """
        # 读取数据
        from sklearn.datasets import load_iris
        iris = load_iris()
        print(iris.feature_names)
        print(iris.data[0:5,:])
        print(iris.data)
    
        # 处理数据
        # 1,缩小数据  对于csv中的数据可使用 data.query("id>8 & money <2000") 等过滤掉一些数据
        # 2,时间处理
        #   time_value = pd.to_datetime(data中的时间列,unit="s") unit 表示时间最小的单位
        #        time_value格式为 1970-01-01 00:00:00 注意不能单独获取年月日
        #   time_value=pd.DatatimeIndex(time_value) 此时转换为字典格式的时间
        #   增加特征,例如年相同,就不能当做特征
        #       data['day'] = time_value.day,weekday,hour等不建议使用 此方式
        #           建议使用data.loc["day"] = xxx
        #       pandas使用data.drop(["time"],axis=1) 删除原来的时间戳,
        #       数组使用np.delete(data,[1,2,3等列],axis=1) 删除原来的时间戳
        # 3,目标值处理
        #     目标值过多,单有的目标值数量太少,可以忽略
        #     分组求和,本例中 可表示为 把数量少于n个的种类删除(虽然本类中目标值只有3个,其实不用删除,只为演示效果)
        #     group = data.groupby("目标值列名").count()
        #     此时返回结果 列数不变,目标值列名列为所有的目标值,其他列不再是值,而是分组后该组的个数
        #     tf = group[group['非目标值列列名']>n].reset_index()
        #     data = data[data[目标列列名].isin(tf.目标列列名)]
        #     取出目标值 y =data["目标列"]
        #     取出目标值 x =data.drop(["目标列"],axis=1)
        #     x_train,y_train,x_test,y_test数据分割 train_test_spilt
        # 特征工程(标准化)
        #   x_train 进行fit_transform
        #   注意 也需要对 x_test进行标准化,注意使用 transform即可, 即 使用 训练集的参数进行标准化
        #   标准化对数据最后结果影响很大
        # 算法处理
        knn = KNeighborsClassifier(n_neighbors=5)
        # fit ,predict,score
        knn.fit(x_train,y_train)
        # 得出结果
        y_predict = knn.predict(x_test) # 得出预测目标值
        # 得出准确率
        knn.score(x_test,y_test) # 也可以使用y_predict与y_test 得出
        return None
    问题1:k的取值问题,很大,很小?
        很大:易受异常点影响
        很小:容易受k值(数量)波动
    性能问题:每一个未知数来都需要与全部数据进行计算
        很费时间
    调参:n_neighbors 的合适值
    
    优点:易于理解,易实现,无需参数(算法里边的参数)估计,无需训练
    缺点:计算慢,耗内存,必须有k
    
    朴素(条件独立)贝叶斯算法 (需要学习概率相关内容)
    概率:
      条件概率:P(A1,A2|B) = P(A1|B)*P(A2|B)  A1,A2 不能相互影响  应该是条件独立
      联合概率 P(A,B) = P(A)*P(B)
    例:常用与对于文章的分类
      每个文章会计算属于每个分类的概率,比较数据那个的概率较大,就是该分类
    P(科技|文章1)  文档
    P(科技|词1,词2.....)  文档:词1,词2....  (多个条件下 x的概率)
    朴素贝叶斯-贝叶斯公式

     P(A|B)=P(B|A)P(A)/P(B)

    =====================================
    个人体会:例 有两个箱子 A:两黑,两白球 B两黑球,1白球
      随机从两个盒子中拿出一个球,是白球, 求是从A中拿出的概率
      P(A|白) = (P(白|A)P(A))/P(白) = 0.5*0.5/(1/2*1/2+1/2*1/3)=7/12
      P(B|白) = (P(白|B)P(B))/P(白) = 1/3*0.5/(1/2*1/2+1/2*2/3)=5/12
    贝叶斯推导:https://www.cnblogs.com/lliuye/p/9178090.html ===================================== 求在包含这些词的情况下是科技类的概率=在科技分类下这些词(这个文档)出现的概率*科技类的概率/在所有文档中,这些词的概率 P(C|W)=(P(W|C)P(C))/P(W) W为给定文档的特征值(频数统计,预测文档提供),C为文档类别 可理解为:P(C|F1,F2.....)=(P(F1,F2..|C)P(C))/P(F1,F2,....) P(C):每个文档类别的概率(某类文档数/文档总数) P(W|C):给定列别下 特征(词)的概率 P(F1|C) = Ni/N (表示该次出现在科技文章中的概率) F1,F2.....的概率乘积 表示 科技类文章中这些词都出现的概率 Ni为F1词在c类所有文档中出现的次数,(科技类文章中改词的次数) N为c类文档下所有词的总和 .(科技类文章中 所有的词 和) 有些情况下得到文章属于某类的概率为0,不合理 解决办法:拉普拉斯平滑系数 P(F1|C) = (Ni+a)/N+am a:指定系数一般为1,m为训练文档中出现的特征词的个数 算法API sklearn.native_bayes.MultinomiaNB sklearn.native_bayes.MultinomiaNB(alpha=1.0) 拉普拉斯平滑系数,不属于超参数 例:新闻分类 from sklearn.datasets import fetch_20newsgroups from sklearn.model_selection import train_test_split def naviebayes(): """ 朴素贝叶斯进行文章分类 :return: """ # 加载数据,进行分割 news = fetch_20newsgroups(subset="all") x_train,x_test,y_train,y_test = train_test_split(news.data,news.target,test_size=0.25) # 生成文章特征词 from sklearn.feature_extraction.text import TfidfVectorizer from sklearn.metrics.classification import classification_report tf = TfidfVectorizer() #以训练集中词的列表进行 每篇文章重要性统计 x_train = tf.fit_transform(x_train) # print(tf.get_feature_names()) # 全部文章中所有的词 x_test = tf.transform(x_test) # 朴素贝叶斯进行评估 from sklearn.naive_bayes import MultinomialNB mlt = MultinomialNB(alpha=1.0) #print(x_train) # .toarray 可转化为二维数组 """ (0, 122986) 0.1189432263044612 # 第一篇文章中 feature_names下标122986的这个词 出现的频率 (0, 139798) 0.25782353561208343 (0, 117722) 0.12774899257629055 """ mlt.fit(x_train,y_train) y_predict = mlt.predict(x_test) print(classification_report(y_test,y_predict,target_names=news.target_names)) # 算出准确率,由于文章词的数量确定,数据的正确性,因此 准确率不易提高 # print(mlt.score(x_test,y_test)) 优点: 发源于古典数学,有稳定的分类效率 速度快,效率高 对数据缺失不敏感,常用于文本分类 缺点: 前提是一个词的出现与另一个无关,当词之间出现关联时,效果不好 if __name__ == "__main__": # knnCls() naviebayes() pass 模型评估(不仅靠准确率,还有召回率) 准确率:estimator.score() 最常见是预测结果的准确率,即百分比 混淆矩阵 准确率 35%,但召回率 75% """ 预测结果 正例(猫) 假例(不是猫) 真实结果 20正例(猫) 真正例(15) 伪反例(5) 真实结果 80假例(不是猫) 伪正例(60) 真反例(20) """ 精确率:预测为正例的样本中,真正例的比例 召回率:真实值正例中,预测为正例的比例 15/20 越高越好 其他分类标准F1-SCORE 反映了模型的稳健性 F1 = 2*精确率*召回率/(精确率+召回率) API sklearn.metrics.classification_reportly(y_true,y_pred,target_names=None) y_true:真实目标值 y_pred:估计器预测目标值 terget_names:目标类别名称 return:每个类(目标值)的精确率与召回率 模型选择与调优 交叉验证:让别评估模型更加准确 训练集分为n份:训练集(n-1)份+验证集1份 得出一个准确率 模型一 再次训练集分为n份:训练集(n-1)份+验证集1份(就是修改验证集,可能此时第一份为验证集) 得出一个准确率 模型二 ..... 依次进行 得出n个准确率 求平均 即可以作为可信一点的模型结果 分为n份就称为n折交叉验证 网格搜索(超参数搜索):调参数(k近邻) 与交叉验证组合k = 3,5,7 10折交叉验证 k=3 时的平均,k=5的平均... 比较即可得出比较可信的k值 当有两个找参数时:两两组合 API sklearn.model_selection.GridSearchCV(estimator,param_grid=none,cv=None) estimator:估计器(knn) 此时估计器中不用再写超参数 param_grid:估计参数 {"n_neighbors":[1,2,3,4,5]} cv:几折交叉验证 不用 knn.fit predict 此时返回的实例 fit(x_train,y_train):输入训练数据 score(x_test,y_test):准确率 best_score_:在交叉验证中最好的结果 best_estimator_:在交叉验证中最好的参数模型 cv_results_:每次交叉验证后验证集集准确率和训练集准确率(验证集平均值) from sklearn.model_selection import GridSearchCV gc = GridSearchCV(KNeighborsClassifier(),param_grid={"n_neighbors":[1,2,3,4,5]}) gc.fit(x_train,y_train)
    机器学习常用算法
    k近邻算法
    求出未知点 与周围最近的 k个点的距离
    查看这k个点中大多数是哪一类
    根号((x已知-x未知)^2+(y已知-y未知)^2) 即平面间2点距离公式
    收异常点影响较大,因此需要做标准化处理
    API:sklearn.neighbors.KNeighborsClassifier(n_neighbors=5,algorithm="auto")
    algorithm:{"auto","ball_tree","kd_tree","brute"}
    效率不同
    ball_tree:会使用BallTree
    kd_tree:会使用KdTree
    auto:尝试根据传递的fit方法的值决定最适合的算法
    n_neighbors: 邻居数,默认为5
    处理:
    时间特征:需要转为年,,,,,,当做几个新的特征处理,并不是全部要加入,要根据结果选择加入
    目标值:可以去掉某些目标值
    from sklearn.neighbors import KNeighborsClassifier
    def knnCls():
    """
    预测鸢尾花的种类
    :return:
    """
    #
    from sklearn.datasets import load_iris
    iris = load_iris()
    print(iris.feature_names)
    print(iris.data[0:5,:])
    print(iris.data)

    #
    # 1,csv中的据可使用 data.query("id>8 & money <2000") 过滤掉一些
    # 2,时间处
    # time_value = pd.to_datetime(data中的时间,unit="s") unit 表示时间最小的
    # time_value格式 1970-01-01 00:00:00 注意不能单独获取年月日
    # time_value=pd.DatatimeIndex(time_value) 时转换为字典格式的时间
    # 增加特征,例如年相同,就不能做特征
    # data['day'] = time_value.day,weekday,hour等不建使用 此方式
    # 使用data.loc["day"] = xxx
    # pandas使用data.drop(["time"],axis=1) 除原时间,
    # 数组使用np.delete(data,[1,2,3等列],axis=1) 除原时间
    # 3,标值处
    # 标值过,有的目标值数量太少,可以忽略
    # 求和,本例中 可表示量少于n种类删(然本中目标值只有3,不用,演示效果)
    # group = data.groupby("标值列名").count()
    # 返回果 列,标值列名列所有的目标值,其他列不再是,而是分该组个数
    # tf = group[group['非目标值列列名']>n].reset_index()
    # data = data[data[列列名].isin(tf.列列名)]
    # 取出目标值 y =data[""]
    # 取出目标值 x =data.drop([""],axis=1)
    # x_train,y_train,x_test,y_test据分割 train_test_spilt
    # 特征工程(准化)
    # x_train fit_transform
    # 注意 也需要 x_test准化,注意使用 transform即可, 即 使用 训练集的参数进准化
    # 准化对数据最后果影很大
    # 算法
    knn = KNeighborsClassifier(n_neighbors=5)
    # fit ,predict,score
    knn.fit(x_train,y_train)
    # 得出
    y_predict = knn.predict(x_test) # 得出预测标值
    # 得出准确率
    knn.score(x_test,y_test) # 也可以使用y_predicty_test 得出
    return None
    问题1:k的取值问题,很大,很小?
    很大:易受异常点影响
    很小:容易受k(数量)波动
    性能问题:每一个未知数来都需要与全部数据进行计算
    很费时间
    调参:n_neighbors 的合适值

    优点:易于理解,易实现,无需参数(算法里边的参数)估计,无需训练
    缺点:计算慢,耗内存,必须有k

    朴素(条件独立)贝叶斯算法 (需要学习概率相关内容)
    概率:
    条件概率:P(A1,A2|B) = P(A1|B)*P(A2|B) A1,A2 不能相互影响 应该是条件独立
    联合概率 P(A,B) = P(A)*P(B)
    :常用与对于文章的分类
    每个文章会计算属于每个分类的概率,比较数据那个的概率较大,就是该分类
    P(科技|文章1) 文档
    P(科技|1,2.....) 文档:1,2.... (多个条件下 x的概率)
    朴素贝叶斯-贝叶斯公式
    =====================================
    个人体会:例 有两个箱子 A:两黑,两白球 B两黑球,1白球
    随机从两个盒子中拿出一个球,是白球, 求是从A中拿出的概率
    P(A|) = (P(|A)P(A))/P() = 0.5*0.5/(1/2*1/2+1/2*1/3)=7/12
    P(B|) = (P(|B)P(B))/P() = 1/3*0.5/(1/2*1/2+1/2*2/3)=5/12
    =====================================
    求在包含这些词的情况下是科技类的概率=在科技分类下这些词(这个文档)出现的概率*科技类的概率/在所有文档中,这些词的概率
    P(C|W)=(P(W|C)P(C))/P(W)
    W为给定文档的特征值(频数统计,预测文档提供),C为文档类别
    可理解为:P(C|F1,F2.....)=(P(F1,F2..|C)P(C))/P(F1,F2,....)
    P(C):每个文档类别的概率(某类文档数/文档总数)
    P(W|C):给定列别下 特征()的概率
    P(F1|C) = Ni/N (表示该次出现在科技文章中的概率) F1,F2.....的概率乘积 表示 科技类文章中这些词都出现的概率
    NiF1词在c类所有文档中出现的次数,(科技类文章中改词的次数)
    Nc类文档下所有词的总和 .(科技类文章中 所有的词 和)
    有些情况下得到文章属于某类的概率为0,不合理
    解决办法:拉普拉斯平滑系数 P(F1|C) = (Ni+a)/N+am
    a:指定系数一般为1,m为训练文档中出现的特征词的个数
    算法API sklearn.native_bayes.MultinomiaNB
    sklearn.native_bayes.MultinomiaNB(alpha=1.0) 拉普拉斯平滑系数,不属于超参数
    :新闻分类
    from sklearn.datasets import fetch_20newsgroups
    from sklearn.model_selection import train_test_split
    def naviebayes():
    """
    朴素叶斯行文章分
    :return:
    """
    # 载数,行分割
    news = fetch_20newsgroups(subset="all")
    x_train,x_test,y_train,y_test = train_test_split(news.data,news.target,test_size=0.25)
    # 生成文章特征
    from sklearn.feature_extraction.text import TfidfVectorizer
    from sklearn.metrics.classification import classification_report
    tf = TfidfVectorizer()

    #训练集中的列表行 每篇文章重要性统计
    x_train = tf.fit_transform(x_train)
    # print(tf.get_feature_names()) # 全部文章中所有的
    x_test = tf.transform(x_test)
    # 朴素叶斯
    from sklearn.naive_bayes import MultinomialNB
    mlt = MultinomialNB(alpha=1.0)
    #print(x_train) # .toarray 维数组
    """
    (0, 122986) 0.1189432263044612 # 第一篇文章中 feature_names122986这个词
    (0, 139798) 0.25782353561208343
    (0, 117722) 0.12774899257629055
    """
    mlt.fit(x_train,y_train)
    y_predict = mlt.predict(x_test)
    print(classification_report(y_test,y_predict,target_names=news.target_names))
    # 算出准确率,由于文章量确定,据的正确性,因此 准确率不易提高
    # print(mlt.score(x_test,y_test))
    优点:
    发源于古典数学,有稳定的分类效率
    速度快,效率高
    对数据缺失不敏感,常用于文本分类
    缺点:
    前提是一个词的出现与另一个无关,当词之间出现关联时,效果不好
    if __name__ == "__main__":
    # knnCls()
    naviebayes()
    pass
    模型评估(不仅靠准确率,还有召回率)
    准确率:estimator.score() 最常见是预测结果的准确率,即百分比
    混淆矩阵
    准确率 35%,但召回率 75%
    """ 预测结
    正例() 假例(不是猫)
    真实结 20正例() 正例(15) 反例(5)
    真实结 80假例(不是猫) 正例(60) 反例(20)
    """
    精确率:预测为正例的样本中,真正例的比例
    召回率:真实值正例中,预测为正例的比例 15/20 越高越好
    其他分类标准F1-SCORE 反映了模型的稳健性
    F1 = 2*精确率*召回率/(精确率+召回率)
    API sklearn.metrics.classification_reportly(y_true,y_pred,target_names=None)
    y_true:真实目标值
    y_pred:估计器预测目标值
    terget_names:目标类别名称
    return:每个类(目标值)的精确率与召回率
    模型选择与调优
    交叉验证:让别评估模型更加准确
    训练集分为n:训练集(n-1)+验证集1份 得出一个准确率 模型一
    再次训练集分为n:训练集(n-1)+验证集1(就是修改验证集,可能此时第一份为验证集) 得出一个准确率 模型二
    ..... 依次进行 得出n个准确率 求平均 即可以作为可信一点的模型结果
    分为n份就称为n折交叉验证
    网格搜索(超参数搜索):调参数(k近邻)
    与交叉验证组合k = 3,5,7 10折交叉验证
    k=3 时的平均,k=5的平均... 比较即可得出比较可信的k
    当有两个找参数时:两两组合
    API sklearn.model_selection.GridSearchCV(estimator,param_grid=none,cv=None)
    estimator:估计器(knn) 此时估计器中不用再写超参数
    param_grid:估计参数 {"n_neighbors":[1,2,3,4,5]}
    cv:几折交叉验证
    不用 knn.fit predict
    此时返回的实例
    fit(x_train,y_train):输入训练数据
    score(x_test,y_test):准确率
    best_score_:在交叉验证中最好的结果
    best_estimator_:在交叉验证中最好的参数模型
    cv_results_:每次交叉验证后验证集集准确率和训练集准确率(验证集平均值)
    from sklearn.model_selection import GridSearchCV
    gc = GridSearchCV(KNeighborsClassifier(),param_grid={"n_neighbors":[1,2,3,4,5]})
    gc.fit(x_train,y_train)
  • 相关阅读:
    12.1
    我的火车头
    头文件优化时间
    一些姿势
    CodeForces
    CodeForces
    [SDOI 2015] 约数个数和
    BZOJ
    [国家集训队] middle
    鹅的问题
  • 原文地址:https://www.cnblogs.com/Dean0731/p/11610394.html
Copyright © 2011-2022 走看看