ML(3.1): NavieBayes在R中的应用

朴素贝叶斯方法是一种使用先验概率去计算后验概率的方法, 具体见上一节。

算法包:e1071

函数:navieBayes(formule,data,laplace=0,...,subset,na.action=na.pass)

  • Formule: 公式的形式:class~x1 + x2 + .....  相互作用是不允许的
  • data: 数据集
  • lapace: 正面双控制拉普拉期平滑。默认值(0)禁用拉普拉斯平滑。它的思想非常简单,就是对没类别下所有划分的计数为1,这样如果训练样本集数量充分大时,并不会对结果产生影响,并且解决了上述频率为0的局面。【在训练样本中,某一特征的属性值可能没有出现,为了保证一个属性出现次数为0时,能够得到一个很小但是非0的概率值】

模型常用评判标准

  • 正确率
  • 错误率
  • 灵敏度:所有正例中被分对的比例
  • 特效度: 负例中被分对的比例
  • 精度: 表示 被分为正例的示例中实际为正例的比例
  • 召回率:度量有多个正例被分为正例

R手机短信过滤示例



数据下载地址: https://github.com/stedy/Machine-Learning-with-R-datasets/tree/72e6b6cc91bc2bb08eb6f99f52c033677cb70c1a

参考:https://zhuanlan.zhihu.com/p/22615168

数据导入


  • 首先,导入数据(注:第二列文本中带“...”会导制后面的数据读不进来)

    setwd("E:\\RML")
    sms <- read.csv("sms.csv",header=TRUE,stringsAsFactors=FALSE)
  • 将sms$type设置为因子变量,再查看sms结构,若type中有其他类型的文本,那么factor会大于2个,正好验证数据是否有误读
    sms$type <- factor(sms$type)
    str(sms)
  • 统计垃圾短信与非垃圾短信在这个数据集中各占了多少
    > table(sms$type)
    
     ham spam
    4827  747 

数据清洗


  • sms$text 文本中包含着数字、缩略的短语和标点符号等,对于NaiveBayesClassifier而言,这些信息是有干扰的,因此,在建模之前需要在语料库中对数据进行清洗。
  • 添加tm包 【参见tm包使用: http://www.cnblogs.com/tgzhu/p/6680525.html】,创建语料库,如下:语料库包含5574个document

    > library(NLP)
    > library(tm)
    > sms_corpus <- Corpus(VectorSource(sms$text))
    > print(sms_corpus)
    <<SimpleCorpus>>
    Metadata:  corpus specific: 1, document level (indexed): 0
    Content:  documents: 5574
  • 清理语料库
    > # 所有字母转换成小写
    > corpus_clean <- tm_map(sms_corpus, tolower)
    > # 去除text中的数字
    > corpus_clean <- tm_map(corpus_clean, removeNumbers)
    > # 去除停用词,例如and,or,until...
    > corpus_clean <- tm_map(corpus_clean, removeWords, stopwords())
    > # 去除标点符号
    > corpus_clean <- tm_map(corpus_clean, removePunctuation)
    > # 去除多余的空格,使单词之间只保留一个空格
    > corpus_clean <- tm_map(corpus_clean, stripWhitespace)
    > #查看一下清理后的语料库文本
    > inspect(corpus_clean[1])
    <<SimpleCorpus>>
    Metadata:  corpus specific: 1, document level (indexed): 0
    Content:  documents: 1
    
    [1] go jurong point crazy available bugis n great world la e buffet cine got amore wat
    >
  • 注:inspect 是tm包的函数,display detailed information on a corpus, a term-document matrix, or a text document

标记化


  • 将文本分解成由单个单词组成的组,实际就是实现语料库向稀疏矩阵的转变 corpus_clean -> sms_dtm

    > #将文本信息转化成DocumentTermMatrix类型的稀疏矩阵
    > dtm <- DocumentTermMatrix(corpus_clean)
    > dtm[1:3,]
    <<DocumentTermMatrix (documents: 3, terms: 7928)>>
    Non-/sparse entries: 31/23753
    Sparsity           : 100%
    Error in nchar(Terms(x), type = "chars") :
      invalid multibyte string, element 183
  • 解决异常的方法,执行如下语句
    > Sys.setlocale(category = "LC_ALL", locale = "us")
    [1] "LC_COLLATE=English_United States.1252;LC_CTYPE=English_United States.1252;LC_MONETARY=English_United States.1252;LC_NUMERIC=C;LC_TIME=English_United States.1252"
    > dtm[1:3,]
    <<DocumentTermMatrix (documents: 3, terms: 7928)>>
    Non-/sparse entries: 31/23753
    Sparsity           : 100%
    Maximal term length: 40
    Weighting          : term frequency (tf)

建立训练集和测试集数据


  • 训练集和测试集数据,查看垃圾与正常邮件占比

    > #训练集和测试集数据,查看垃圾与正常邮件占比
    > trainSet <- sms[1:4169,]
    > testset <- sms[4170:5574,]
    > prop.table(table(trainSet$type))
    
          ham      spam
    0.8647158 0.1352842
    > prop.table(table(testset$type))
    
          ham      spam
    0.8697509 0.1302491 
  • 创建可视化词云,通过词云可以大致浏览一下哪些词在spam中经常出现,哪些词在ham中经常出现。当然,前者对于垃圾短信的过滤相对重要一点。绘制词云可以通过添加包wordcloud实现  install.packages("wordcloud")
  • 为了查看spam和ham各自的多频词,首先取trainset的子集,如下:

    > #创建可视化词云,大致浏览一下哪些词在spam中经常出现
    > library(RColorBrewer)
    > library(wordcloud)
    > #取trainset对spam和ham的子集
    > spam <- subset(trainSet, type == "spam")
    > ham <- subset(trainSet, type == "ham")
    > #创建词云
    > wordcloud(spam$text, max.words=40, scale=c(3,0.5))
  • 显示结果如下:
  • 缩减特征:在面临问题是稀疏矩阵的特征太多了,而且很多词在所有text中可能都没怎么出现过,为减少运算量对特征瘦瘦身。先留下来在所有text中出现至少5次的词

    dtm_train <- dtm[1:4169,]
    > dtm_test <- dtm[4170:5574,]
    > findFreqTerms(dtm_train,5)
       [1] "available"       "bugis"           "cine"            "crazy"           "got"             "great"           "point"           "wat"
       [9] "world"           "lar"             "wif"             "apply"           "comp"            "cup"             "entry"           "final"
      [17] "free"            "may"             "receive"         "text"            "txt"             "win"             "wkly"            "already"
      [25] "dun"             "early"           "say"             "around"          "goes"            "nah"             "think"           "though"
      [33] "usf"             "back"            "freemsg"         "fun"             "hey"             "like"            "now"             "send"
      [41] "std"             "still"           "weeks"           "word"            "xxx"             "brother"         "even"            "speak"
      [49] "treat"           "callers"         "callertune"      "copy"            "friends"         "melle"           "per"             "press"
    ........................
  • 将这些词设置成指示标识,下面建模时用这个指示标识提示模型只对这些词进行计算
    > #缩减特征
    > d <- findFreqTerms(dtm,5)
    > corpus_train = sms_corpus[1:4169]
    > corpus_test = sms_corpus[4170:5574]
    > dtm_train <- DocumentTermMatrix(corpus_train,list(dictionary=d))
    > dtm_test <- DocumentTermMatrix(corpus_test,list(dictionary=d))
  • train和test都是计数矩阵,如果一条text中某个单词出现2次,那么这个单词在这条文本下会被记上2,NB只想知道这个单词出现了或者没出现,因此需要对矩阵进行转化成因子矩阵。
    > #对矩阵进行转化成因子矩阵
    > convert_counts <- function(x){
    +   x <- ifelse(x>0,1,0)
    +   x <- factor(x, levels=c(0,1),labels=c("No","Yes"))
    +   return(x)
    + }
    > dtm_train <- apply(dtm_train, MARGIN=2, convert_counts)
    > dtm_test <- apply(dtm_test, MARGIN=2, convert_counts)

训练模型


  • 需要的包是e1071,主要步骤包含两步:
    1. 建立NaiveBayesClassifier
    2. 测试Classifier
  • 示例代码如下:

    > #需要的包是e1071
    > #install.packages("e1071")
    > library(e1071)
    > sms_classifier <- naiveBayes(dtm_train,trainSet$type)
    > sms_prediction <- predict(sms_classifier, dtm_test)
    >

评估模型


  • 用交叉表来看看test中多少预测对了

    > library(gmodels)
    > CrossTable(sms_prediction,testset$type,prop.chisq=TRUE,prop.t=FALSE, dnn=c("predicted","actual"))
    
       Cell Contents
    |-------------------------|
    |                       N |
    | Chi-square contribution |
    |           N / Row Total |
    |           N / Col Total |
    |-------------------------|
    
    Total Observations in Table:  1405 
    
                 | actual
       predicted |       ham |      spam | Row Total |
    -------------|-----------|-----------|-----------|
             ham |      1124 |       150 |      1274 |
                 |     0.229 |     1.531 |           |
                 |     0.882 |     0.118 |     0.907 |
                 |     0.920 |     0.820 |           |
    -------------|-----------|-----------|-----------|
            spam |        98 |        33 |       131 |
                 |     2.229 |    14.886 |           |
                 |     0.748 |     0.252 |     0.093 |
                 |     0.080 |     0.180 |           |
    -------------|-----------|-----------|-----------|
    Column Total |      1222 |       183 |      1405 |
                 |     0.870 |     0.130 |           |
    -------------|-----------|-----------|-----------|
  • ham-ham和spam-spam是预测正确的,spam-ham:本身不是垃圾短信却被认为是垃圾短信过滤掉,由于Classifier1没有设置拉普拉斯估计,下面再尝试建立classifier2,看结果是否被优化。
    > #设置拉普拉斯估计
    > sms_classifier <- naiveBayes(dtm_train,trainSet$type,laplace = 1)
    > sms_prediction <- predict(sms_classifier, dtm_test)
    > CrossTable(sms_prediction,testset$type,prop.chisq=TRUE,prop.t=FALSE, dnn=c("predicted","actual"))
    
       Cell Contents
    |-------------------------|
    |                       N |
    | Chi-square contribution |
    |           N / Row Total |
    |           N / Col Total |
    |-------------------------|
    
    Total Observations in Table:  1405 
    
                 | actual
       predicted |       ham |      spam | Row Total |
    -------------|-----------|-----------|-----------|
             ham |      1105 |       132 |      1237 |
                 |     0.788 |     5.262 |           |
                 |     0.893 |     0.107 |     0.880 |
                 |     0.904 |     0.721 |           |
    -------------|-----------|-----------|-----------|
            spam |       117 |        51 |       168 |
                 |     5.803 |    38.747 |           |
                 |     0.696 |     0.304 |     0.120 |
                 |     0.096 |     0.279 |           |
    -------------|-----------|-----------|-----------|
    Column Total |      1222 |       183 |      1405 |
                 |     0.870 |     0.130 |           |
    -------------|-----------|-----------|-----------|
  • spam人预测结果有改进,尝试继续优化,下一步以评论分类进行中文分类模拟

完整代码


  • setwd("E:\\RML")
    #数据导入
    sms <- read.csv("sms.csv",header=TRUE,stringsAsFactors=FALSE)
    
    #查看结构: data.frame 3498 obs. 2 variables:
    str(sms)
    
    #将sms_raw$type设置为因子变量
    sms$type <- factor(sms$type)
    str(sms)
    
    #垃圾短信与非垃圾短信在这个数据集中各占了多少
    table(sms$type)
    
    #创建语料库
    library(NLP)
    library(tm)
    sms_corpus <- Corpus(VectorSource(sms$text))
    print(sms_corpus)
    
    #clear corpus
    sms_corpus <- tm_map(sms_corpus, PlainTextDocument)
    # 所有字母转换成小写
    sms_corpus <- tm_map(sms_corpus, tolower)
    # 去除text中的数字
    sms_corpus <- tm_map(sms_corpus, removeNumbers)
    # 去除停用词,例如and,or,until...
    sms_corpus <- tm_map(sms_corpus, removeWords, stopwords())
    # 去除标点符号
    sms_corpus <- tm_map(sms_corpus, removePunctuation)
    # 去除多余的空格,使单词之间只保留一个空格
    sms_corpus <- tm_map(sms_corpus, stripWhitespace)
    #查看一下清理后的语料库文本
    inspect(sms_corpus[1])
    
    #将文本信息转化成DocumentTermMatrix类型的稀疏矩阵
    dtm <- DocumentTermMatrix(sms_corpus)
    Sys.setlocale(category = "LC_ALL", locale = "us")
    
    #训练集和测试集数据,查看垃圾与正常邮件占比
    trainSet <- sms[1:4169,]
    testset <- sms[4170:5574,]
    prop.table(table(trainSet$type))
    prop.table(table(testset$type))
    
    #创建可视化词云,大致浏览一下哪些词在spam中经常出现
    library(RColorBrewer)
    library(wordcloud)
    #取trainset对spam和ham的子集
    spam <- subset(trainSet, type == "spam")
    ham <- subset(trainSet, type == "ham")
    #创建词云
    wordcloud(spam$text, max.words=40, scale=c(3,0.5))
    
    #缩减特征
    d <- findFreqTerms(dtm,5)
    corpus_train = sms_corpus[1:4169]
    corpus_test = sms_corpus[4170:5574]
    dtm_train <- DocumentTermMatrix(corpus_train,list(dictionary=d))
    dtm_test <- DocumentTermMatrix(corpus_test,list(dictionary=d))
    dtm_train$ncol
    dtm_test$ncol
    
    #对矩阵进行转化成因子矩阵
    convert_counts <- function(x){
      x <- ifelse(x>0,1,0)
      x <- factor(x, levels=c(0,1),labels=c("No","Yes"))
      return(x)
    }
    dtm_train <- apply(dtm_train, MARGIN=2, convert_counts)
    dtm_test <- apply(dtm_test, MARGIN=2, convert_counts)
    
    #需要的包是e1071
    #install.packages("e1071")
    library(e1071)
    sms_classifier <- naiveBayes(dtm_train,trainSet$type)
    sms_prediction <- predict(sms_classifier, dtm_test)
    
    #评估模型:用交叉表来看看test中多少预测对了
    #install.packages("gmodels")
    library(gmodels)
    CrossTable(sms_prediction,testset$type,prop.chisq=TRUE,prop.t=FALSE, dnn=c("predicted","actual"))
    
    #设置拉普拉斯估计laplace=1
    sms_classifier <- naiveBayes(dtm_train,trainSet$type,laplace = 1)
    sms_prediction <- predict(sms_classifier, dtm_test)
    CrossTable(sms_prediction,testset$type,prop.chisq=TRUE,prop.t=FALSE, dnn=c("predicted","actual"))
时间: 2024-10-19 07:04:05

ML(3.1): NavieBayes在R中的应用的相关文章

ML(4.1): CART在R中应用

CART模型 :即Classification And Regression Trees.它和一般回归分析类似,是用来对变量进行解释和预测的工具,也是数据挖掘中的一种常用算法.如果因变量是连续数据,相对应的分析称为回归树,如果因变量是分类数据,则相应的分析称为分类树.决策树是一种倒立的树结构,它由内部节点.叶子节点和边组成.其中最上面的一个节点叫根节点. 构造一棵决策树需要一个训练集,一些例子组成,每个例子用一些属性(或特征)和一个类别标记来描述.构造决策树的目的是找出属性和类别间的关系,一旦这

R中读取EXCEL 数据的方法

最近初学R语言,在R语言读入EXCEL数据格式文件的问题上遇到了困难,经过在网上搜索解决了这一问题,下面归纳几种方法,供大家分享: 第一:R中读取excel文件中的数据的路径: 假定在您的电脑有一个excel文件,原始的文件路径是:D:\work\data\1 如果直接把这个路径拷贝到R中,就会出现错误,原因是: \是escape character(转义符),\\才是真正的\字符,或者用/ 因此,在R中有两种方法读取该路径: 1:在R中输入一下路径:D:\\work\\data\\1     

【转】R中有关数据挖掘的包

下面列出了可用于数据挖掘的R包和函数的集合.其中一些不是专门为了数据挖掘而开发,但数据挖掘过程中这些包能帮我们不少忙,所以也包含进来. 1.聚类 常用的包: fpc,cluster,pvclust,mclust 基于划分的方法: kmeans, pam, pamk, clara 基于层次的方法: hclust, pvclust, agnes, diana 基于模型的方法: mclust 基于密度的方法: dbscan 基于画图的方法: plotcluster, plot.hclust 基于验证的

R语言编程艺术(2)R中的数据结构

本文对应<R语言编程艺术>第2章:向量:第3章:矩阵和数组:第4章:列表:第5章:数据框:第6章:因子和表 ========================================================================= R语言最基本的数据类型就是向量(vector),单个数值和矩阵都是向量的一种特例. 声明:R中不需要声明变量,但是注意函数式语言的特性,如果读写向量中的元素时,R事先不知道对象是向量的话,则函数没有执行的对象.如下代码是无法工作的: y[1]

R中按组数据分析

如下的一组数据: age group 1 23.0883 1 2 25.8344 1 3 29.4648 1 4 32.7858 2 5 33.6372 1 6 34.9350 1 7 35.2115 2 8 35.2115 2 9 35.2115 2 10 36.7803 1 如果想要对两组数据分别进行均值和求和,最简单的想法是按类做分组的子矩阵,但是太麻烦. 如果要得到下面的结果:group mean sd 1 34.5 5.6 2 32.3 4.2 ...今天学到的方法是:plyr包中的d

R 中正则

在R中使用正则,可以指定perl=True 构造复杂正则,这也是本人比较熟悉在方式 > word <- c('a1:23asdfjaskldjf<->aa:112xzvasoiffncx909<->bb:23asdfjaskldjfAAA') > pattern<- 'bb.*(?=(<->|$))' > (gregout <- gregexpr(pattern,word,perl=TRUE)) [[1]] [1] 45 attr(,

简单介绍一下R中的几种统计分布

统计学上分布有很多,在R中基本都有描述.因能力有限,我们就挑选几个常用的.比较重要的简单介绍一下每种分布的定义,公式,以及在R中的展示. 下面先列举各种分布: rnorm(n, mean=0, sd=1) 高斯(正态)分布rexp(n, rate=1) ?指数分布rgamma(n, shape, scale=1) γ分布 rpois(n, lambda) Poisson分布rweibull(n, shape, scale=1) Weibull分布 rcauchy(n, location=0, s

R语言学习中的小bug:R中矩阵相乘错误于A %*% B: 需要数值/复数矩阵/矢量参数

遇到了小bug: R中矩阵相乘错误于A %*% B: 需要数值/复数矩阵/矢量参数 看到网上别人的做法,发现了用class(A)和class(B)之后才发现,是因为读入的时候数据的类型不对,A.B的类型并不是matrix,才导致了这个问题. 用as.matrix来变型一下,就OK了. R语言学习中的小bug:R中矩阵相乘错误于A %*% B: 需要数值/复数矩阵/矢量参数,布布扣,bubuko.com

R语言基础知识学习(四):R中的画图函数--plot()函数

plot()函数是R中基本的画x-y两个变量的函数,其用法如下为:plot(x, y, ...) 例如:首先我用runif()函数产生了两列随机数:x1,y1,然后用plot()函数直接画图: > x1 <- round(runif(20,min = 0 ,max = 100))> x1 [1] 90 84 86 86 28 43 86 76 90 76 14 62 40 52 87 57 88 17[19] 10 27> y1 <- round(runif(20,min =