2014-01-16 7 views
6

Ich habe einige sehr ärgerliche Probleme bekommen einen Naive Bayes Classifier mit einer Dokument-Term-Matrix zu arbeiten. Ich bin mir sicher, dass ich einen sehr einfachen Fehler mache, aber ich kann nicht herausfinden, was es ist. Meine Daten stammen aus Account-Tabellen. Ich wurde gebeten, herauszufinden, welche Kategorien (im Textformat: meist Namen von Abteilungen oder Namen von Budgets) eher Geld für Wohltätigkeitsorganisationen ausgeben und welche meistens (oder nur) für private Unternehmen ausgegeben werden. Sie schlugen vor, dass ich Naive Bayes-Klassifikatoren verwende, um dies zu tun. Ich habe etwa tausend Datenzeilen, um ein Modell und viele hunderttausend Zeilen zu trainieren, um das Modell zu testen. Ich habe die Strings vorbereitet, Leerzeichen durch Unterstriche und ands/& s durch + ersetzt, dann jede Kategorie als einen Begriff behandelt: so wird 'Alkohol- und Drogensucht': Alkohol + Drogensucht.Dokument Term Matrix für Naive Bayes classfier: unerwartete Ergebnisse R

Einige Beispiel Reihen:

"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. 

this example als Vorlage verwenden, schrieb ich die folgende Funktion mit meinem Dokument Begriff Matrix zu kommen (tm verwenden), sowohl für Trainings- und Testdaten.

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) 

So weit, so gut. Das Problem ist, wenn ich versuche, a) ein naives Bayes-Modell anzuwenden und b) von diesem Modell vorherzusagen. Verwenden klar Paket - Ich bekomme eine Null Wahrscheinlichkeit Fehler, da viele der Begriffe Null Instanzen einer Kategorie haben und herumspielen mit den Laplace-Bedingungen scheint dies nicht zu beheben. Mit E1071 arbeitete das Modell, aber wenn ich dann getestet unter Verwendung des Modells:

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

... jeder einzelne Artikel der gleichen Kategorie vorhergesagt, obwohl sie in etwa gleich sein sollte. Etwas im Modell funktioniert eindeutig nicht. Betrachtet man einige der Begriffe in Modell $ -Tabellen - kann ich sehen, dass viele hohe Werte für private und null für Wohltätigkeit und andere umgekehrt haben. Ich habe als Faktor für den Code verwendet.

output: 
rs 1 2 
    1 0 0 
    2 19 17 

Irgendwelche Ideen, was schief läuft? Spielen dtm Matrizen nicht gut mit naivebayes? Habe ich bei der Aufbereitung der Daten einen Schritt verpasst? Ich habe keine Ideen mehr. Hoffe das ist alles klar. Glücklich zu klären, wenn nicht. Irgendwelche Vorschläge würden sehr geschätzt.

+0

ich mit einem multinomial Bayes-Klassifikator ein identisches Problem habe. Einige Daten werden korrekt zugewiesen, aber die meisten enden in einer Klasse. Die Klasse, die falsch gefüllt wird, wechselt abhängig von der Größe der Eingabedaten. Ich habe auch versucht, die Daten zu wiederholen, um [dieses] Problem zu vermeiden (http://stackoverflow.com/questions/17904190/why-does-naivebayes-return-all-nas-for-multiclass-classification-in-r) aber die Mehrheit endet immer noch in einer Klasse – christopherlovell

Antwort

2

Ich habe das Problem schon selbst gehabt. Du hast (soweit ich es sehe) alles richtig gemacht, die Naive Bayes Implementierung in e1071 (und damit Klar) ist fehlerhaft.

Aber es gibt eine einfache und schnelle Lösung, so dass Naive Bayes wie in e1071 implementiert wieder funktioniert: Sie sollten Ihre Text-Vektoren zu kategorialen Variablen, d. H. as.factor ändern. Sie haben dies bereits mit Ihrer Zielvariable traindata$Code gemacht, aber Sie müssen dies auch für Ihre trainmatrix und sicher dann Ihre testdata tun.

ich nicht den Fehler zu 100% Prozent verfolgen konnte nach unten, aber es liegt in der Naive Bayes-Implementierung von E1071 in diesem Teil (I beachten kann, ist klar nur ein Wrapper um E1071):

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

Sie sehen, dass es eine If-else-Bedingung gibt: Wenn wir keine Numerik haben, wird naive Bayes verwendet, wie wir es erwarten. Wenn wir Numerik haben - und hier kommt der Fehler -, nimmt diese naive Bucht automatisch eine Normalverteilung an. Wenn du nur 0 und 1 in deinem Text hast, ist dnorm ziemlich nervtötend. Ich gehe davon aus, dass aufgrund von sehr niedrigen Werten, die durch dnorm erzeugt werden, das Prob.werden immer durch die threshold ersetzt und somit wird die Variable mit dem höheren a priori-Faktor immer "gewinnen".

Allerdings, wenn ich Ihr Problem richtig verstehe, brauchen Sie nicht einmal Vorhersage, sondern den a priori-Faktor für die Identifizierung, welche Abteilung Geld an wen gibt. Dann müssen Sie nur Ihr Modell genau betrachten. In Ihrem Modell erscheint für jeden Ausdruck die Apriori-Wahrscheinlichkeit, die ich vermute, nach der Sie suchen. Lassen Sie uns dies tun und die zuvor erwähnte mit einer leicht modifizierten Version Ihrer Probe:

## i have changed the vectors slightly 
first <- "environment+housing strategy+commissioning third_party_payments supporting_ppl_block_gross_chargeable" 
second <- "west_north_west customer+tenancy premises h.r.a._special_maintenance" 

categories <- c("charity", "private") 

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)) 
    ## instead just use DocumentTermMatrix, the assignment is superflous 
    return(DocumentTermMatrix(testcorpus)) 
} 

## since you did not supply some more data, I cannot do anything about these lines 
## trainmatrix <- getMatrix(traindata$cats) 
## testmatrix <- getMatrix(testdata$cats) 
## instead only 
trainmatrix <- getMatrix(c(first, second)) 

## I prefer running this instead of as.matrix as i can add categories more easily 
traindf <- data.frame(categories, as.data.frame(inspect(trainmatrix))) 

## now transform everything to a character vector since factors produce an error 
for (cols in names(traindf[-1])) traindf[[cols]] <- factor(traindf[[cols]]) 
## traindf <- apply(traindf, 2, as.factor) did not result in factors 

## check if it's as we wished 
str(traindf) 

## it is 
## let's create a model (with formula syntax) 
model <- naiveBayes(categories~., data=traindf) 

## if you look at the output (doubled to see it more clearly) 
predict(model, newdata=rbind(traindf[-1], traindf[-1])) 

Aber wie ich bereits gesagt habe, brauchen Sie nicht vorhersagen. Ein Blick auf das Modell ist in Ordnung, z.B. model$tables$premises gibt Ihnen die Wahrscheinlichkeit für die Räumlichkeiten geben Geld an private Unternehmen: 100%.

Wenn Sie mit sehr großen Datensätzen arbeiten, sollten Sie in Ihrem Modell Schwellenwert und Eps angeben. Eps definiert das Limit, wann der Schwellenwert geliefert werden soll. Z.B. eps = 0 und threshold = 0.000001 können von Nutzen sein.

Darüber hinaus sollten Sie bei der Verwendung der Term-Frequenz-Gewichtung bleiben. tf * idv z.B. funktioniert nicht wegen der dnorm in den naiven bayes.

Hoffnung kann ich endlich meinen 50 Ruf bekommen: P

Verwandte Themen