飞道的博客

机器学习_第三天(朴素贝叶斯+决策树+随机深林)

216人阅读  评论(0)

1、朴素贝叶斯算法

1.1 概率基础

1.1.1 联合概率

包含多个条件,且所有条件同时成立的概率
记作:P(A,B) = P(A) * P(B)

1.1.2 条件概率

事件A在满足事件B的前提下发生的概率
记作:P(A|B)
P(A1,A2|B) = P(A1|B)P(A2|B)
注意: 此条件概率的成立前提是A1,A2相互独立,即A1,A2两个特征之间不互相影响

1.2 朴素贝叶斯

朴素贝叶斯最常用于文档分类,使用算法的前提条件是特征独立
朴素贝叶斯-贝叶斯公式

注:w为给定文档的特征值,c为文档类别
公式可以理解为:

公式分为三个部分,其中c可以是不同类别

  • P( C ):某个文档类别的概率 = 某文档类别词数 / 总文档词数
  • P(W│C):给定类别下特征(被预测文档中出现的词)的概率
      计算方法:P(Fi│C)=Ni/N(训练文档中去计算)
      Ni为词Fi在C类别所有文档中出现的次数
      N为所属类别C下的文档所有词出现的次数和
  • P(F1,F2,…):预测文档中每个词的概率
    e.g

    属于某个类别的概率为0不合理!!!

1.2.1 拉普拉斯平滑

从以上例子得到为娱乐类概率是0,这不合理。如果词频列表里其他词在娱乐类出现概率很高,但个别词没有在娱乐类中出现,整体概率计算得到0,可能出现分类错误,解决方法拉普拉斯平滑系数
拉普拉斯平滑

  • P(F1│C)=(Ni+α)/(N+αm)
  • α为指定的系数默认值为1,m为训练文档中统计出的特征词个数。

经过拉普拉斯平滑处理,上一案例则变为

1.2.2 朴素贝叶斯API

sklearn朴素贝叶斯API:sklearn.naive_bayes.MultinomialNB(alpha = 1.0)

  • alpha:拉普拉斯平滑系数,默认为1

1.2.3 20类新闻分类案例

sklearn20类新闻分类:20个新闻组数据集包含20个主题的18000个新闻组帖子
流程
1、加载20类新闻数据,并进行分割
2、生成文章特征词
3、朴素贝叶斯estimator流程进行预估

from sklearn.naive_bayes import MultinomialNB
from sklearn.datasets import fetch_20newsgroups
from sklearn.model_selection import train_test_split
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics import classification_report

def NB():
    '''
    朴素贝叶斯算法分类,按类别概率大小确认类别
    :return: None
    '''
    # 1.加载数据
    news = fetch_20newsgroups(subset='all')
    data = news.data  # 特征值
    target = news.target  # 目标值
    # 2.分割数据集
    x_train, x_test, y_train, y_test = train_test_split(data, target, test_size=0.25)
    # 3.特征工程,重要性文本特征抽取
    tf = TfidfVectorizer()
    # 以训练集当中的词的列表进行每篇文章词的重要性统计
    x_train = tf.fit_transform(x_train)
    print(tf.get_feature_names())  # 特征字段名
    x_test = tf.transform(x_test)
    # 4.进行朴素贝叶斯算法预测
    nb = MultinomialNB(alpha=1.0)
    nb.fit(x_train, y_train)
    y_predict = nb.predict(x_test)
    print('测试集的预测值为:', y_predict)
    print('测试集预测的准确率为:', nb.score(x_test, y_test))
    # target_names文章类别的字符串
    print('每个类别的精确率与召回率:', classification_report(y_test, y_predict, target_names=news.target_names))
    return None

if __name__ == "__main__":
    NB()

1.2.4 总结

优点

  • 朴素贝叶斯模型发源于古典数学理论,有稳定的分类效率
  • 对缺失数据不太敏感,算法也比较简单,常用于文本分类
  • 数据量大的情况下,分类准确度高,速度快
  • 朴素贝叶斯算法不需要调超参数

缺点

  • 概率P(C|F1,F2,…) = P(F1,F2,…|C)P( C )/P(F1,F2,…)的前提条件是特征独立。朴素贝叶斯算法假设文章中出现的词语之间是独立关系,但有些词语之间有一定联系,则假设不成立,从而导致预测效果不佳。
  • 朴素贝叶斯算法准确率取决于训练集的选择。训练集文章更具有代表性、重要性特征词的选择更准确,都会提高算法的准确性。

2、分类模型的评估

2.1 estimator.score()

最常见使用的是准确率,即预测结果正确的百分比

2.2 混淆矩阵

在分类任务下,每一个目标值的预测结果(Predicted Condition)与正确标记(True Condition)之间存在四种不同的组合,构成混淆矩阵。

2.2.1 精确率(Precision)与召回率(Recall)

  • 精确率:预测结果为正例样本中真实为正例的比例(查得准)
  • 召回率:真实为正例的样本中预测结果为正例的比例(查的全,对正样本的区分能力)
  • F1-score,反映了模型的稳健型

2.3 分类模型评估API

分类模型评估API:sklearn.metrics.classification_report(y_true, y_pred, target_names=None)

  • y_true:真实目标值
  • y_pred:估计器预测目标值
  • target_names:目标类别名称
  • return:每个类别精确率与召回率

3、模型的选择与调优

3.1 交叉验证

交叉验证的目的是为了让被评估的模型更加准确、可信。
交叉验证作为网格搜索的参数,与网格搜索一起使用进行参数调优。
交叉验证先将数据自定义成n等分,选其中一份作为验证集(验证集与测试集无关),其余n-1份作为训练集,得出该组准确率。经过n次操作得出n组准确率的平均值作为最终准确率。这种方法称为n折交叉验证,最常用的是10折交叉验证。
以下图为例:
将数据分成5等份,其中一份作为验证集。然后经过5组测试,每次都更换不同的验证集,得到5组模型的准确率结果。取5组模型准确率的平均值作为最终结果,称为5折交叉验证。

3.2 网格搜索

3.2.1 超参数搜索–网格搜索

通常情况下,有很多参数需要被指定(如k-近邻算法中的K值),此类参数叫超参数。但是手动指定繁杂,所以模型预设了几种超参数组合,每组超参数都采用交叉验证来进行评估,最后选出最优参数组合建立模型。

3.2.2 超参数搜索–网格搜索API

超参数搜索-网格搜索API:sklearn.model_selection.GridSearchCV(estimator, param_grid=None,cv=None)
对估计器的指定参数值进行详尽搜索

  • estimator:估计器对象,如kn,kn=KNeighborsClassifier()
  • param_grid:估计器参数(字典格式传入),如param_grid = {“n_neighbors”:[1,3,5]}
  • cv:指定几折交叉验证,最常使用10折交叉验证
  • .fit(x_train,y_train):输入训练数据
  • .score(x_test,y_test):预测准确率

结果分析:

  • .best_score_:在交叉验证中测试的最好准确率结果
  • .best_estimator_:最优参数模型
  • .cv_results_:每次交叉验证后的验证集准确率结果和训练集准确率结果

3.2.3 K-近邻网格搜索案例

K近邻算法实例:预测入住位置

from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import train_test_split
from sklearn.model_selection import GridSearchCV
from sklearn.neighbors import KNeighborsClassifier
import pandas as pd

def knn():
    '''
    k近邻算法:预测用户签到位置
   :return: None
    '''
    data = pd.read_csv(r".\data\02.facebook-v-predicting-check-ins\train.csv")
    # print(data.head(10))
    data = data.query('x>1.0 & x<1.25 & y>2.5 & y<2.75')
    time_value = pd.to_datetime(data['time'], unit='s')
    time_key = pd.DatetimeIndex(time_value)
    data['day'] = time_key.day
    data['hour'] = time_key.hour
    data['weekday'] = time_key.weekday
    data = data.drop(['time'], axis=1)
    # print(data.head(10))
    place_count = data.groupby('place_id').count()
    # print(place_count.head(10))
    place_nid = place_count[place_count['row_id'] > 3].index
    # print(place_nid)
    data = data[data['place_id'].isin(place_nid)]
    # print(data)
    y = data['place_id']
    x = data.drop(['place_id', 'row_id'], axis=1)
    x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.25)
    std = StandardScaler()
    x_train = std.fit_transform(x_train)
    x_test = std.transform(x_test)

    # 进行算法流程
    knn = KNeighborsClassifier()  # 用网格搜索进行调参,在实例化算法时不设定参数
    # 构造一些参数的值进行搜索
    param = {
   'n_neighbors': [3, 5, 10]}
    # 进行网格搜索
    cv = GridSearchCV(knn, param_grid=param, cv=10)  # 通过10折交叉验证和网格搜索,优选参数n_neighbors
    cv.fit(x_train, y_train)
    print('测试集的准确率为:', cv.score(x_test, y_test))
    print('在交叉验证中测试的最好结果:', cv.best_score_)
    print('最好的参数模型:', cv.best_estimator_)
    print('各个超参数每次交叉验证的结果:', cv.cv_results_)
    return None

if __name__ == '__main__':
    knn()

4、 决策树、随机森林

4.1 决策树

决策树程序设计中的条件分支结构就是if-then结构,最早的决策树就是利用这类结构分割数据的一种分类学习方法。

4.1.1 信息熵

H的专业术语称之为信息熵,表示不确定信息量,单位为比特。信息熵在传送压缩中用的比较多,信息熵越大则信息不确定性越大,信息和消除不确定性是相联系的。
公式:H = -(p1logp1 + p2logp2 + … + p32log32)

4.1.2 决策树的划分依据之一:信息增益

特征A对训练数据集D的信息增益g(D,A),定义为集合D的信息熵H(D)与特征A给定条件下D的信息条件熵H(D|A)之差,即公式为:
注:决策树分类特征的先后顺序由减少不确定性的大小来排序,信息增益即表示得知一个特征条件之后,减少不确定(信息熵)的⼤小。
e.g

目标值结果分类成是/否,则总体熵:H(D) = -(9/15log9/15 + 6/15log(6/15))=0.971
年龄作为第一个特征条件时的信息增益
g(D, 年龄) = H(D) - H(D|年龄) =0.971- [1/3H(⻘年)+1/3H(中年)+1/3H(老年)]=0.083

  • H(青年) = -(2/5log(2/5)+ 3/5log(3/5))=0.971
  • H(中年) = -(2/5log(2/5)+ 3/5log(3/5))=0.971
  • H(老年) = -(4/5log(4/5)+ 1/5log(1/5))=0.722

同理: g(D, 工作)=0.324,g(D, 房子)=0.420,g(D, 信用)=0.363
g(D, 房子)的信息增益最大,所以以房子作为首要特征(第一个判定标准)

4.1.3 常见决策树使用的算法

ID3:信息增益最大的准则
C4.5:信息增益比最大的准则
CART

  • 回归树: 平方误差最小
  • 分类树: 基尼系数最小的准则(sklearn中的默认划分原则,其划分更加仔细且准确)

4.1.4 sklearn决策树API

sklearn.tree.DecisionTreeClassifier(criterion=’gini’, max_depth=None,random_state=None)

  • criterion:默认是’gini’系数,也可以选择信息增益熵’entropy’
  • max_depth:树的深度,是个自定义超参数,取值会影响预测准确率
  • random_state:随机数种子

4.1.5 本地保存决策树的结构

sklearn.tree.export_graphviz(estimator,out_file=‘路径/文件.dot’,feature_names=[’’,…])
导出DOT格式决策树结构(二进制格式)

  • estimator:估计器
  • out_file:输出的存储路径+文件名
  • feature_names:指定各节点显示的名字

安装graphviz(将dot文件转换为pdf、png)
 pip install graphviz
运行命令(将二进制文件转换成图片)
 dot -Tpng 文件名.dot -o 文件名.png

4.1.6 泰坦尼克号乘客生存分类案例

泰坦尼克号乘客生存分类案例:(pclass的1st,2st,3st代表社会经济阶层,其中age数据存在缺失

流程

  1. pd读取数据
  2. 选择有影响的特征,处理缺失值
  3. 分割训练集与测试集
  4. 进行特征工程(pd按记录逐行转换字典格式数据,x_train.to_dict(orient=“records”),转换后将分类字段进行字典特征值抽取)
  5. 决策树估计器流程
import pandas as pd
from sklearn.feature_extraction import DictVectorizer
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier
# 决策树算法的一大优点,可以导出树结构
from sklearn.tree import export_graphviz

def decision():
    '''
    用决策树算法,预测泰坦尼克号乘客生存情况
    :return:None
    '''
    # 1. 获取数据
    titan = pd.read_csv(r"E:\working\Pycharm_project\machine_learn\data\03.Titanic\train.csv")
    # print(titan)
    # 2. 处理数据,找出特征值与目标值
    x = titan[['Pclass', 'Age', 'Sex']]  # 特征值
    y = titan['Survived']  # 目标值
    # print(x)
    # age缺失值处理,null与任意值运算都为null
    x['Age'].fillna(x['Age'].mean(), inplace=True)  # inplace=True,用均值替换原先null值
    # 3. 分割训练集与测试集
    x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.25)
    # 4. 特征工程:'pclass'和'sex'为string类型,是类别需要用one_hot编码进行处理
    dict = DictVectorizer(sparse=False)  # 返回ndarray数组
    x_train_dict = x_train.to_dict(orient='records')
    x_test_dict = x_test.to_dict(orient='records')
    # orient='records'将数据按每条记录转换成字典格式,字典特征抽取分类string数据
    # print(x_train_dict)
    x_train = dict.fit_transform(x_train_dict)
    print(dict.get_feature_names())
    x_test = dict.transform(x_test_dict)
    #print(x_train)  # 转换成字典后的训练集特征值
    # 5. 运行决策树算法
    tree = DecisionTreeClassifier()
    # 分类特征值都是转化为字典形的数据
    tree.fit(x_train, y_train)
    print('预测的准确率为:', tree.score(x_test, y_test))

    # 导出决策树的结构,feature_names指定展示的节点名
    # 需要安装graphviz(将dot二进制文件转换为pdf/png)
    export_graphviz(tree, out_file=r".\data\03.Titanic\decision_tree.dot",
                    feature_names=['年龄', '社会等级', '女性', '男性'])
    return None

if __name__ == '__main__':
    decision()

4.1.7 决策树的优缺点以及改进

优点:

  • 原理简单,条件分类
  • 决策树结构可导出从而实现可视化,更直观、清晰
  • 对数值型数据前期准备简单,无强制标准化要求
  • 能够评估各个特征在分类问题上的重要性(分类条件约靠上,信息增益越大)

缺点:

  • 训练集得出的复杂决策树用于测试集未必预测准确率高,可能存在过拟合情况
  • 决策树不稳定,数据的小变化可能生成完全不同的树

改进:

  • 减枝cart算法
    决策树的参数可以设置枝干上样本数的下限,从而达成减枝效果和减小异常值对树影响。
  • 随机森林

4.2 集成学习方法-随机森林

集成学习通过建立几个模型组合,来解决单一预测问题。工作原理是生成多个分类器/模型,各自独立地学习和作出预测。这些预测最后结合成单预测,因此优于任何一个单分类的做出预测。
在机器学习中,随机森林是一个包含多个决策树(用不同训练集建立起来的不同决策树)的分类器,并且其输出的类别是由个别树输出的类别的众数而定。

4.2.1 建⽴多个决策树的过程

单个树的建⽴过程:(总共N个样本, M个特征)

  1. 随机在N个样本中以有放回抽样的方式,取样N次,形成一个训练集(即bootstrap取样),样本数据有可能重复。
  2. 随机在M个特征中选出m个特征(m<<M)

注意:随机抽样是为了避免每一棵决策树模型都一样;有放回的抽样则是为了保证每棵决策树之间有交集,使得最终输出的众数有说服力。

4.2.2 集成学习-随机森林API

sklearn.ensemble.RandomForestClassifier(n_estimators=10,criterion=‘gini’,max_depth=None,bootstrap=True,random_state=None)

  • n_estimators:可选,默认n_estimators = 10,随机森林里的决策树的数量
    经验值:120,200,300,500,800,1200
  • criteria:可选,默认criterion=‘gini’,分割特征的方法,基尼系数划分更仔细且准确
  • max_depth:可选,默认max_depth=None,树的最大深度,是个超参数
    经验值:5,8,15,25,30
  • bootstrap:可选,默认bootstrap=True,是否在构建树时使用有放回抽样
  • max_features:每棵决策树的最大特征数量,处理过拟合情况
    max_features=‘auro’:最大特征数量不超过sqrt(总特征数量)
    max_features=‘log2’:最大特征数量不超过log2(总特征数量)
    max_features=‘None’:最大特征数量不超过总特征数量

4.2.3 泰坦尼克号乘客生存分类案例

import pandas as pd
from sklearn.feature_extraction import DictVectorizer
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import GridSearchCV

def random_forest():
    '''
    随机森林+网格搜索参数调优
    :return:None
    '''
    titan = pd.read_csv(r".\data\03.Titanic\train.csv")
    x = titan[['Pclass', 'Age', 'Sex']]  # 特征值
    y = titan['Survived']  # 目标值
    x['Age'].fillna(x['Age'].mean(), inplace=True)
    x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.25)
    dict = DictVectorizer(sparse=False)
    x_train_dict = x_train.to_dict(orient='records')
    x_test_dict = x_test.to_dict(orient='records')
    x_train = dict.fit_transform(x_train_dict)
    x_test = dict.transform(x_test_dict)
    # 随机森林进行预测(网格搜索进行超参数调优)
    rf = RandomForestClassifier()
    # 网格搜索调优
    # 需要调优的参数
    param = {
   'n_estimators': [120, 200, 300, 500, 800, 1200], 'max_depth': [5, 8, 15, 25, 30]}
    gc = GridSearchCV(rf, param_grid=param, cv=10)
    gc.fit(x_train, y_train)
    print('预测准确率为:', gc.score(x_test, y_test))
    print('查看选择的参数模型:', gc.best_params_)
    return None

if __name__ == '__main__':
    random_forest()

注意:随机森林不支持导出决策树结构

4.2.4 随机森林的优点

  • 具有极好的准确率
  • 能够有效地运行在大数据集上(大样本+大特征数)
  • 能够处理高维特征的数据集,而且不需要降维

转载:https://blog.csdn.net/weixin_44454872/article/details/116297508
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场