Naive Bayes classfier的文档术语矩阵:意外结果R.

for*_*joe 6 r bayesian tm

我有一些非常烦人的问题让Naive Bayes分类器与文档术语矩阵一起工作.我确定我犯了一个非常简单的错误,但无法弄清楚它是什么.我的数据来自帐户电子表格.我被要求弄清楚哪些类别(文本格式:主要是部门名称或预算名称)更有可能在慈善机构上花钱,哪些(或者只是)花在私人公司上.他们建议我使用朴素贝叶斯分类器来做到这一点.我有大量的数据来训练一个模型和数十万行来测试模型.我已经准备好了字符串,用下划线替换了空格,用&+替换了&s,然后将每个类别视为一个术语:所以'酒精和毒瘾'成为:酒精+药物滥用.

一些示例行:

"environment+housing strategy+commissioning third_party_payments supporting_ppl_block_gross_chargeable" -> This row went to a charity
"west_north_west customer+tenancy premises h.r.a._special_maintenance" -> This row went to a private company.
Run Code Online (Sandbox Code Playgroud)

使用此示例作为模板,我编写了以下函数来提出我的文档术语矩阵(使用tm),用于训练和测试数据.

library(tm)
library(e1071) 

getMatrix <- function(chrVect){
    testsource <- VectorSource(chrVect)
    testcorpus <- Corpus(testsource)
    testcorpus <- tm_map(testcorpus,stripWhitespace)
    testcorpus <- tm_map(testcorpus, removeWords,stopwords("english"))
    testmatrix <- t(TermDocumentMatrix(testcorpus))
}

trainmatrix <- getMatrix(traindata$cats)
testmatrix <- getMatrix(testdata$cats)
Run Code Online (Sandbox Code Playgroud)

到现在为止还挺好.问题是当我尝试a)应用朴素贝叶斯模型和b)从该模型预测时.使用klar包 - 我得到零概率错误,因为许多术语只有一个类别的零实例并且使用laplace术语似乎不能解决这个问题.使用e1071,该模型有效,但是当我使用以下方法测试模型时:

model <- naiveBayes(as.matrix(trainmatrix),as.factor(traindata$Code))
rs<- predict(model, as.matrix(testdata$cats))
Run Code Online (Sandbox Code Playgroud)

......每个项目预测相同的类别,即使它们应该大致相等.模型中的某些东西显然不起作用.看一下模型$表中的一些术语 - 我可以看到许多私有的值和慈善的零值,反之亦然.我使用as.factor代码.

output:
rs   1  2
  1  0  0
  2 19  17
Run Code Online (Sandbox Code Playgroud)

什么是错误的任何想法?dtm矩阵不能和naivebayes一起玩吗?我是否错过了准备数据的一步?我完全没有想法.希望这一切都清楚.如果没有,很高兴澄清.任何建议将不胜感激.

Den*_*sch 4

我自己已经遇到这个问题了。你已经完成了(据我所知)一切正确,e1071(以及 klar)中的朴素贝叶斯实现有错误。

\n\n

但是有一个简单快速的修复方法可以使 e1071 中实现的朴素贝叶斯再次发挥作用:您应该将文本向量更改为类别变量,即as.factor。您已经对目标变量执行了此操作traindata$Code,但您还必须为您的目标变量执行此操作trainmatrix,并且肯定是您的testdata.

\n\n

我无法 100% 追踪该错误,但它位于 e1071 的朴素贝叶斯实现的这一部分中(我可能会注意到,klar 只是 e1071 的包装器):

\n\n
L <- log(object$apriori) + apply(log(sapply(seq_along(attribs),\n            function(v) {\n                nd <- ndata[attribs[v]]\n                ## nd is now a cell, row i, column attribs[v]\n                if (is.na(nd) || nd == 0) {\n                    rep(1, length(object$apriori))\n                } else {\n                    prob <- if (isnumeric[attribs[v]]) {\n                        ## we select table for attribute\n                        msd <- object$tables[[v]]\n                        ## if stddev is eqlt eps, assign threshold\n                        msd[, 2][msd[, 2] <= eps] <- threshold\n                        dnorm(nd, msd[, 1], msd[, 2])\n                    } else {\n                        object$tables[[v]][, nd]\n                    }\n                    prob[prob <= eps] <- threshold\n                    prob\n                }\n            })), 1, sum)\n
Run Code Online (Sandbox Code Playgroud)\n\n

您会看到有一个 if-else 条件:如果我们没有数字,则按照我们期望的方式使用朴素贝叶斯。如果我们有数字——错误就来了——这个朴素贝叶斯会自动假设正态分布。如果文本中只有 0 和 1,则 dnorm 就很糟糕。我假设由于 dnorm 创建的值非常低,所以问题是这样的。总是被替换threshold,因此具有较高先验因子的变量将始终为 \xe2\x80\x9ewin\xe2\x80\x9c。

\n\n

然而,如果我正确理解你的问题,你甚至不需要预测,而是需要确定哪个部门给谁钱的先验因素。然后您所要做的就是深入研究您的模型。在您的每个术语的模型中,都会出现先验概率,这就是我假设您正在寻找的。让我们使用示例的稍微修改版本来执行此操作和上述操作:

\n\n
## i have changed the vectors slightly\nfirst <- "environment+housing strategy+commissioning third_party_payments supporting_ppl_block_gross_chargeable"\nsecond <- "west_north_west customer+tenancy premises h.r.a._special_maintenance"\n\ncategories <- c("charity", "private")\n\nlibrary(tm)\nlibrary(e1071)\n\ngetMatrix <- function(chrVect){\n    testsource <- VectorSource(chrVect)\n    testcorpus <- Corpus(testsource)\n    testcorpus <- tm_map(testcorpus,stripWhitespace)\n    testcorpus <- tm_map(testcorpus, removeWords,stopwords("english"))\n    ## testmatrix <- t(TermDocumentMatrix(testcorpus))\n    ## instead just use DocumentTermMatrix, the assignment is superflous\n    return(DocumentTermMatrix(testcorpus))\n}\n\n## since you did not supply some more data, I cannot do anything about these lines\n## trainmatrix <- getMatrix(traindata$cats)\n## testmatrix <- getMatrix(testdata$cats)\n## instead only\ntrainmatrix <- getMatrix(c(first, second))\n\n## I prefer running this instead of as.matrix as i can add categories more easily\ntraindf <- data.frame(categories, as.data.frame(inspect(trainmatrix)))\n\n## now transform everything to a character vector since factors produce an error\nfor (cols in names(traindf[-1])) traindf[[cols]] <- factor(traindf[[cols]])\n## traindf <- apply(traindf, 2, as.factor) did not result in factors\n\n## check if it\'s as we wished\nstr(traindf)\n\n## it is\n## let\'s create a model  (with formula syntax)\nmodel <- naiveBayes(categories~., data=traindf)\n\n## if you look at the output (doubled to see it more clearly)\npredict(model, newdata=rbind(traindf[-1], traindf[-1]))\n
Run Code Online (Sandbox Code Playgroud)\n\n

但正如我已经说过的,你不需要预测。看一下模型就可以了,例如,model$tables$premises您将获得该场所向私营公司提供资金的可能性:100%。

\n\n

如果您正在处理非常大的数据集,则应在模型中指定阈值和 eps。Eps 定义了应提供阈值的限制。例如eps = 0threshold = 0.000001可以使用。

\n\n

此外,您应该坚持使用术语频率加权。由于朴素贝叶斯中的 dnorm,tf*idv 例如将不起作用。

\n\n

希望我最终能获得 50 声望 :P

\n