朴素贝叶斯
1. 原理
朴素贝叶斯的原理是基于贝叶斯定理的,我们要求的就是后验概率P(Cj|x),这里x就是特征向量,Cj就是类别j,后验概率最大的P(Cj|x)对于的类j就是样本特征为x对于的类别,其中我认为它的假设是最影响它的分类效果的原因,这就是我们看到朴素贝叶斯在不同样本分类的效果会有很大区别,见下图:
2.常见模型
其实这两种常见模型的具体区别就在于P(c)和先验概率的计算不同,解释也不同:
2.1多项式模型
在多项式模型中,设某文档d=(t1,t2,…,tk),tk是该文档中出现过的单词,允许重复,则先验概率P©= 类c下单词总数/整个训练样本的单词总数。类条件概率P(tk|c)=(类c下单词tk在各个文档中出现过的次数之和+1)/(类c下单词总数+|V|)。
2.2不努力模型
P©= 类c下文件总数/整个训练样本的文件总数
P(tk|c)=(类c下包含单词tk的文件数+1)/(类c下包含的文件+2)
2.2高斯模型
上文看出,计算各个划分的条件概率P(a|y)是朴素贝叶斯分类的关键性步骤,当特征属性为离散值时,只要很方便的统计训练样本中各个划分在每个类别中出现的频率即可用来估计P(xi|c),下面重点讨论特征属性是连续值的情况。
当特征属性为连续值时,通常假定其值服从高斯分布(也称正态分布)。即:
因此只要计算出训练样本中各个类别中此特征项划分的各均值和标准差,代入上述公式即可得到需要的估计值。
ps:
1 朴素贝叶斯处理数值型数据的方法:
(1) 区间离散化,设阈值,分段。
(2) 高斯化:求出概率密度函数,假设变量服从正态分布,根据已有变量统计均值和方差,
得出概率密度函数,这样就解决了计算连续值作为分类的条件概率值。
参考:http://blog.mythsman.com/?p=2683
2 除0问题:
Laplace校准 所有计算均加一,总类别数目加n;
3 下溢出:很小的值相乘,四舍五入误差
采用log 乘法变相加;
4移除停用词:也可以提高文本分类的性能
2.代码实践
参考代码:https://www.cnblogs.com/rongyux/p/5602037.html
多项式模型:
1.创建数据集
import numpy as np
from numpy import *
# 1.创建数据集
def loadDataSet():
postingList=[['my', 'dog', 'has', 'flea', 'problems', 'help', 'please'],
['maybe', 'not', 'take', 'him', 'to', 'dog', 'park', 'stupid'],
['my', 'dalmation', 'is', 'so', 'cute', 'I', 'love', 'him'],
['stop', 'posting', 'stupid', 'worthless', 'garbage'],
['mr', 'licks', 'ate', 'my', 'steak', 'how', 'to', 'stop', 'him'],
['quit', 'buying', 'worthless', 'dog', 'food', 'stupid']]
classVec = [0,1,0,1,0,1] #1 is abusive, 0 not
return postingList,classVec
# 2.创造词汇表
def createVocabList(dataSet):
vocabSet = set([]) #create empty set
for document in dataSet:
vocabSet = vocabSet | set(document) #union of the two sets
return list(vocabSet)
#3.将词汇表转换成01的形式
def setOfWords2Vec(vocabList, inputSet):
returnVec = [0]*len(vocabList)
for word in inputSet:
if word in vocabList:
returnVec[vocabList.index(word)] = 1
return returnVec
# 4.训练模型
def trainNB0(trainMatrix,trainCategory,len_vocab):
numTrainDocs = len(trainMatrix)
numWords = len(trainMatrix[0])
pAbusive = sum(trainCategory)/float(numTrainDocs)
p0Num = np.ones(numWords); p1Num = np.ones(numWords) #change to ones()
p0Denom = len_vocab; p1Denom = len_vocab #多项式模型
#计算每一个样本
for i in range(numTrainDocs):
#标签为1
if trainCategory[i] == 1:
p1Num += trainMatrix[i]
p1Denom += sum(trainMatrix[i])
else:
p0Num += trainMatrix[i]
p0Denom += sum(trainMatrix[i])
p1Vect = np.log(p1Num/p1Denom) #change to log()
p0Vect = np.log(p0Num/p0Denom) #change to log()
return p0Vect,p1Vect,pAbusive
# 5.分类
def classifyNB(vec2Classify, p0Vec, p1Vec, pClass1):
p1 = sum(vec2Classify * p1Vec) + np.log(pClass1) #element-wise mult 这里点乘
p0 = sum(vec2Classify * p0Vec) + np.log(1.0 - pClass1)
if p1 > p0:
return 1
else:
return 0
# 6.测试
def testingNB():
listOPosts,listClasses = loadDataSet()
myVocabList = createVocabList(listOPosts)
trainMat=[]
for postinDoc in listOPosts:
trainMat.append(setOfWords2Vec(myVocabList, postinDoc))
#计算
p0V,p1V,pAb = trainNB0(array(trainMat),array(listClasses),len(myVocabList))
testEntry = ['love', 'my', 'dalmation']
thisDoc = array(setOfWords2Vec(myVocabList, testEntry))
print (testEntry,'classified as: ',classifyNB(thisDoc,p0V,p1V,pAb))
testEntry = ['stupid', 'garbage']
thisDoc = array(setOfWords2Vec(myVocabList, testEntry))
print (testEntry,'classified as: ',classifyNB(thisDoc,p0V,p1V,pAb))
testingNB()
使用sklearn中的库:
from sklearn.naive_bayes import MultinomialNB
listOPosts, listClasses = loadDataSet()
myVocabList = createVocabList(listOPosts)
trainMat = []
for postinDoc in listOPosts:
trainMat.append(setOfWords2Vec(myVocabList, postinDoc))
clf=MultinomialNB()
clf.fit(np.array(trainMat),listClasses)
testEntry = ['love', 'my', 'dalmation']
thisDoc = array(setOfWords2Vec(myVocabList, testEntry))
print(clf.predict(thisDoc.reshape(1,-1)))
svm
1.原理:参考 https://zhuanlan.zhihu.com/p/49331510
2.代码实践:https://blog.youkuaiyun.com/m0_37870649/article/details/81747614
import numpy as np
import pandas as pd
from keras_preprocessing.sequence import pad_sequences
from keras_preprocessing.text import Tokenizer
from sklearn import decomposition, preprocessing
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.svm import SVC
train_prepeared_path='../data/train_prepared.csv'
val_prepeared_path='../data/val_prepared.csv'
test_prepeared_path='../data/test_prepared.csv'
print('加载分词后的数据')
train=pd.read_csv(train_prepeared_path,sep=',',engine='python',encoding='utf-8').sample(frac=0.2,random_state=24)
val=pd.read_csv(val_prepeared_path,sep=',',engine='python',encoding='utf-8').sample(frac=0.1,random_state=24)
test=pd.read_csv(test_prepeared_path,sep=',',engine='python',encoding='utf-8').sample(frac=0.1,random_state=24)
print(train.shape)
all_content=pd.concat([train['content'],val['content']],axis=0,ignore_index=True)
vectorizer=TfidfVectorizer(min_df=2)
vectorizer.fit(all_content)
X_all=vectorizer.transform(all_content).toarray()
test_x=vectorizer.transform(test['content']).toarray()
train_x=X_all[:len(train),:]
val_x=X_all[len(train):,:]
from sklearn.naive_bayes import MultinomialNB
def multiclass_logloss(actual, predicted, eps=1e-15):
"""对数损失度量(Logarithmic Loss Metric)的多分类版本。
:param actual: 包含actual target classes的数组
:param predicted: 分类预测结果矩阵, 每个类别都有一个概率
"""
# Convert 'actual' to a binary array if it's not already:
if len(actual.shape) == 1:
actual2 = np.zeros((actual.shape[0], predicted.shape[1]))
for i, val in enumerate(actual):
actual2[i, val] = 1
actual = actual2
clip = np.clip(predicted, eps, 1 - eps)
rows = actual.shape[0]
vsota = np.sum(actual * np.log(clip))
return -1.0 / rows * vsota
clf=MultinomialNB()
clf.fit(train_x,train['label'])
label=clf.predict_proba(val_x)
label2=clf.predict_proba(test_x)
print(multiclass_logloss(val['label'],label))
print(multiclass_logloss(test['label'],label2))
#先降维再用svm
svd = decomposition.TruncatedSVD(n_components=120)
svd.fit(train_x)
xtrain_svd = svd.transform(train_x)
xvalid_svd = svd.transform(val_x)
xtest_svd = svd.transform(test_x)
scl = preprocessing.StandardScaler()
scl.fit(xtrain_svd)
xtrain_svd_scl = scl.transform(xtrain_svd)
xvalid_svd_scl = scl.transform(xvalid_svd)
xtest_svd_scl = scl.transform(xtest_svd)
# 调用下SVM模型
clf = SVC(C=1.0, probability=True) # since we need probabilities
clf.fit(xtrain_svd_scl, train['label'].values)
predictions = clf.predict_proba(xvalid_svd_scl)
predictions2 = clf.predict_proba(xtest_svd_scl)
print ("logloss: %0.3f " % multiclass_logloss(val['label'].values, predictions))
print ("logloss: %0.3f " % multiclass_logloss(test['label'].values, predictions2))
LDA主题模型 :参考文章:https://blog.youkuaiyun.com/u013710265/article/details/73480332
from sklearn.decomposition import LatentDirichletAllocation
from sklearn.feature_extraction.text import CountVectorizer
corpus=['沙瑞金 赞叹 易学习 的 胸怀 , 是 金山 的 百姓 有福 , 可是 这件 事对 李达康 的 触动 很大 。 易学习 又 回忆起 他们 三人 分开 的 前一晚 , 大家 一起 喝酒 话别 , 易学习 被 降职 到 道口 县当 县长 , 王大路 下海经商 , 李达康 连连 赔礼道歉 , 觉得 对不起 大家 , 他 最 对不起 的 是 王大路 , 就 和 易学习 一起 给 王大路 凑 了 5 万块 钱 , 王大路 自己 东挪西撮 了 5 万块 , 开始 下海经商 。 没想到 后来 王大路 竟然 做 得 风生水 起 。 沙瑞金 觉得 他们 三人 , 在 困难 时期 还 能 以沫 相助 , 很 不 容易 。'
,'沙瑞金 向 毛娅 打听 他们 家 在 京州 的 别墅 , 毛娅 笑 着 说 , 王大路 事业有成 之后 , 要 给 欧阳 菁 和 她 公司 的 股权 , 她们 没有 要 , 王大路 就 在 京州 帝豪园 买 了 三套 别墅 , 可是 李达康 和 易学习 都 不要 , 这些 房子 都 在 王大路 的 名下 , 欧阳 菁 好像 去 住 过 , 毛娅 不想 去 , 她 觉得 房子 太大 很 浪费 , 自己 家住 得 就 很 踏实 。',
'347 年 ( 永和 三年 ) 三月 , 桓温 兵至 彭模 ( 今 四川 彭山 东南 ) , 留下 参军 周楚 、 孙盛 看守 辎重 , 自己 亲率 步兵 直攻 成都 。 同月 , 成汉 将领 李福 袭击 彭模 , 结果 被 孙盛 等 人 击退 ; 而 桓温 三 战三胜 , 一直 逼近 成都 。']
stpwrdpath = "../data/stop_words.txt"
stop_words=[line.strip() for line in open(stpwrdpath,encoding='utf-8').readlines()]
#将停用词表转换为list
cntVector = CountVectorizer(stop_words=stop_words)
cntTf = cntVector.fit_transform(corpus)
lda = LatentDirichletAllocation(n_topics=2,
learning_offset=50.,
random_state=0)
docres = lda.fit_transform(cntTf)
print(docres)