貝葉斯分類算法基於托馬斯貝葉斯發明的貝葉斯定理,他提出的貝葉斯定理對於現代機率論和數理統計的發展有重要的影響。算法
貝葉斯定理:ui
對於隨機事件A和B:A發生的機率爲P(A),B發生的機率爲P(B),在B發生的狀況下,A發生的機率爲P(A|B)。A和B一塊兒發生的聯合機率爲P(AB)。有:P(A|B) X P(B) = P(AB) = P(B|A) X P(A),則有:this
P(A|B) = P(B|A)P(A) / P(B)spa
文本分類(Text Categorization)是指計算機將一片文檔歸於預先給定的某一類或幾類的過程。文本分類的特徵提取過程是分詞。目前比較好的中文分詞器有中科院的ictclas,庖丁,IK等等。通過分詞後,每一個詞就是一個特徵。分詞中能夠本身配置停用詞庫,擴展詞庫等。特徵選擇有諸如TF-IDF,CHI等特徵選擇算法,就不在此贅述。orm
樸素貝葉斯計算先驗機率P(C)和條件機率P(X|C)的方法有兩種:多項式模型和伯努利模型。二者在計算的時候有兩點差異:多項式會統計詞頻,而伯努利認爲單詞出現就記爲1,沒出現記爲0,能夠看到一個是基於詞頻,一個是基於文檔頻率;伯努利在分類時,將詞庫中的沒有出如今待分類文本的詞做爲反方考慮。索引
在計算條件機率時,當待分類文本中的某個詞沒有出如今詞庫中時,機率爲0,會致使很嚴重的問題,須要考慮拉普拉斯平滑(laplace smoothing):它是將全部詞出現的次數+1,再進行統計。事件
再一個問題就是機率過小而詞數太多,會超double,用log將乘法轉成加法。文檔
多項式樸素貝葉斯算法僞代碼以下:get
public class NaiveBayesManager { it
/**關鍵詞索引 關鍵詞-索引*/
private Map<String, Integer> termIndex;
/**類的索引 類名稱-索引*/
private Map<String, Integer> classIndex;
/** 類名 */
private List<String> className;
/**某類的文檔中全部特徵出現的總次數*/
private int classTermsCount[];
/**某類的文檔中某特徵出現的次數之和*/
private int classKeyMap[][];
/**類的個數*/
private int numClasses = 0;
/**訓練樣本的全部特徵(出現屢次只算一個)*/
private int vocabulary = 0;
/**訓練樣本的特徵總次數*/
private int totalTermsCount = 0;
/** 創建類名和特徵名的索引 */
private void buildIndex(List<Corpus> orignCorpus) {
classIndex = new HashMap<String, Integer>();
termIndex = new HashMap<String, Integer>();
className = new ArrayList<String>();
Integer idTerm = new Integer(-1);
Integer idClass = new Integer(-1);
for (int i = 0; i < orignCorpus.size(); ++i) {
Corpus corpus = orignCorpus.get(i);
List<String> terms = corpus.getSegments();
String label = corpus.getCat();
if (!classIndex.containsKey(label)) {
idClass++;
classIndex.put(label, idClass);
className.add(label);
}
for (String term : terms) {
totalTermsCount++;
if (!termIndex.containsKey(term)) {
idTerm++;
termIndex.put(term, idTerm);
}
}
}
vocabulary = termIndex.size();
numClasses = classIndex.size();
}
/**
* 訓練
* */
public void startTraining(List<Corpus> orignCorpus) {
buildIndex(orignCorpus);
classTermsCount = new int[numClasses + 1];
classKeyMap = new int[numClasses + 1][vocabulary + 1];
for (int i = 0; i < orignCorpus.size(); ++i) {
Corpus corpus = orignCorpus.get(i);
List<String> terms = corpus.getSegments();
String label = corpus.getCat();
Integer labelIndex = classIndex.get(label);
for (String term : terms) {
Integer wordIndex = termIndex.get(term);
classTermsCount[labelIndex]++;
classKeyMap[labelIndex][wordIndex]++;
}
}
}
public String classify(List<String> terms) {
int result = 0;
double maxPro = Double.NEGATIVE_INFINITY;
for (int cIndex = 0; cIndex < numClasses; ++cIndex) {
double pro = Math.log10(getPreProbability(cIndex));
for (String term : terms) {
pro += Math.log10(getClassConditonalProbability(cIndex, term));
}
if (maxPro < pro) {
maxPro = pro;
result = cIndex;
}
}
return className.get(result);
}
private double getPreProbability(int classIndex) {
double ret = 0;
int NC = classTermsCount[classIndex];
int N = totalTermsCount;
ret = 1.0 * NC / N;
return ret;
}
private double getClassConditonalProbability(int classIndex, String term) {
double ret = 0;
int NCX = 0;
int N = 0;
int V = 0;
Integer wordIndex = termIndex.get(term);
if (wordIndex != null)
NCX = classKeyMap[classIndex][wordIndex];
N = classTermsCount[classIndex];
V = vocabulary;
ret = (NCX + 1.0) / (N + V); //laplace smoothing. 拉普拉斯平滑處理
return ret;
}
public Map<String, Integer> getTermIndex() {
return termIndex;
}
public void setTermIndex(Map<String, Integer> termIndex) {
this.termIndex = termIndex;
}
public Map<String, Integer> getClassIndex() {
return classIndex;
}
public void setClassIndex(Map<String, Integer> classIndex) {
this.classIndex = classIndex;
}
public List<String> getClassName() {
return className;
}
public void setClassName(List<String> className) {
this.className = className;
}
public int[] getClassTermsCount() {
return classTermsCount;
}
public void setClassTermsCount(int[] classTermsCount) {
this.classTermsCount = classTermsCount;
}
public int[][] getClassKeyMap() {
return classKeyMap;
}
public void setClassKeyMap(int[][] classKeyMap) {
this.classKeyMap = classKeyMap;
}
public int getNumClasses() {
return numClasses;
}
public void setNumClasses(int numClasses) {
this.numClasses = numClasses;
}
public int getVocabulary() {
return vocabulary;
}
public void setVocabulary(int vocabulary) {
this.vocabulary = vocabulary;
}
public int getTotalTermsCount() {
return totalTermsCount;
}
public void setTotalTermsCount(int totalTermsCount) {
this.totalTermsCount = totalTermsCount;
}
public static String getSplitword() {
return splitWord;
}
}