算法原理
在一个高的角度来看监督学习,都是通过反反复复看或者是从以往的数据中提取出某种共同的特征,然后通过将这种拿到新的数据上进行对比是否存在这种特征。
让我们来看贝叶斯,我第一次接触这个名次是在概率论中听到的,公式本身计算也是比较简单的,但他内在的逻辑真的是让人拍案叫绝🦶。
p
(
c
∣
x
i
)
=
p
(
x
i
∣
c
)
p
(
c
)
p
(
x
i
)
p(c|x_i) = \frac{p(x_i|c)p(c)}{p(x_i)}
p(c∣xi?)=p(xi?)p(xi?∣c)p(c)? 其中c表示的是一个类别,x表示已知条件。
在机器学习中文本分类经常会跟贝叶斯结合到一起。在这里我们将会以文本的情感分类为例。在实现贝叶斯分类前,先思考几个问题。 Q1:单纯来看这是一个概率公式,那我们怎么样才能观测到以往的数据呢? Q2:遇到一个新的数据我们将如何表示文本,计算过程中是只允许数字出现的? Q3:计算分类的时候p(x) 是否是必要计算的,乘法是否需要转化成加法?
答:
- 我们先回答Q2,我们所使用的词汇时有限的,换句话说我们可以先进行建立词库。常见的建立词库的方法有word2vec(深度学习的方法),one-hot编码等。这里我们使用的方法是对每个可能出现的词都进行one-hot编码,那句子的话就直接暴力的将这个句子中出现的向量全部叠加在一起。由于每次词的编码是等长的,也就不会出现由于句子变长导致无法正常计算的问题。
- 对于Q1。首先我们会有一些标记好的文本,也就是一些句子对应一个标签🏷?。然后将句子进行拆解成单个分词【英文具有天生分词的特征,而中文没有也就需要一些分词工具(关于这个的介绍在我其他博客中有写)。】我们对词库中每个词汇进行计算类别的概率。(说人话:如果我知道这个句子是类别c,那么这个词汇出现的概率是多少)这也就是贝叶斯🐮的地方,没办法计算正向的概率,那就先计算逆向概率的事件。
- 对于Q3,计算每个类别的概率的时候都是需要除p(x)的,那么我们最后在比较哪个概率比较大,那么概率大的就是那个类别。我们需要考虑的一个比较小的点是是不是存在p(x|c)=0,所以我们需要将每个变量初始化为1。
-
p
(
w
∣
c
i
)
=
p
(
w
0
,
w
1
.
.
.
.
w
n
∣
c
i
)
=
p
(
w
0
∣
c
i
)
?
p
(
w
1
∣
c
i
)
.
.
.
p
(
w
n
∣
c
i
)
p(w|c_i) = p(w_0,w_1....w_n|c_i) = p(w_0|c_i)*p(w_1|c_i)...p(w_n|c_i)
p(w∣ci?)=p(w0?,w1?....wn?∣ci?)=p(w0?∣ci?)?p(w1?∣ci?)...p(wn?∣ci?)
忽律掉p(x)之后
l
o
g
p
(
w
∣
c
i
)
=
∑
i
=
1
n
l
o
g
p
(
x
i
∣
c
)
+
l
o
g
p
(
c
)
logp(w|c_i) = \sum_{i=1}^nlogp(x_i|c) + logp(c)
logp(w∣ci?)=i=1∑n?logp(xi?∣c)+logp(c) log函数并不会改变单调性,所以我们可以通过比较logp的结果来代替比较p。
算法实现
第一步,和往常一样创建数据集。
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
postingList, classVec = loadDataSet()
第二步,创建一个语料库
def createVocabList(dataSet):
vocabularyList = set([])
for i in dataSet:
temp = set(i)
vocabularyList = vocabularyList | temp
return list(vocabularyList)
def setWord2vec(vocabularyList,sentence):
vec = [0]*len(vocabularyList)
for word in sentence:
if word in vocabularyList:
vec[vocabularyList.index(word)] += 1
return vec
vocabularyLis = createVocabList(postingList)
print(vocabularyLis)
第三步,计算每个词汇的概率
def trainNB(trainMatrix,trainCategory):
numTrainDoc = len(trainMatrix)
numWords = len(trainMatrix[0])
pB = sum(trainCategory) / float(numTrainDoc)
#p0num = np.zeros(numWords); p1num = np.zeros(numWords)
# p0 = 0.0 ; p1 = 0.0 # 为防止出现 p(wi|c) = 0 成积之后全是0
p0num = np.ones(numWords); p1num = np.ones(numWords)
p0 = 2.0 ; p1 = 2.0
for i in range(numTrainDoc):
if trainCategory[i] == 1:
p1num += trainMatrix[i]
p1 += sum(trainMatrix[i])
if trainCategory[i] == 0:
p0num += trainMatrix[i]
p0 += sum(trainMatrix[i])
p1vec = np.log(p1num/p1)
p0vec = np.log(p0num/p0)
return p0vec,p1vec,pB
trainMatrix = []
for data in postingList:
trainMatrix.append(setWord2vec(vocabularyLis,data))
p0v,p1v,pB = trainNB(trainMatrix,classVec)
def classfy(vec, p0v, p1v, pclass):
p1 = sum(vec*p1v) + np.log(pclass)
p0 = sum(vec*p0v) + np.log(1 - pclass)
if p1 > p0: return 1
else: return 0
下面我们将创建一个例子
setence = ['love','garbage', 'stupied']
vec = setWord2vec(vocabularyLis,setence)
classfy(vec,p0v,p1v,pB) #不出意外的话输出是1 我们可以看到文本带有攻击性
|