使用对数概率的复杂化 - 朴素贝叶斯文本分类器
Complication using log-probabilities - Naive Bayes text classifier
我正在 Python 中从头开始构建朴素贝叶斯文本 classifier 并且我知道,在遇到概率非常小的乘积时,对概率使用对数是不错的选择。
现在的问题是,我使用的数学函数对这些极小概率的乘积求和。
具体来说,我正在尝试计算给定混合成分 (class) 在所有 classes 中的总词概率。
简单地将这些总概率的对数相加是不正确的,因为总和的对数不等于对数之和。
举个例子,假设我有 3 classes,2000 个单词和 50 个文档。
然后我有一个名为 wordprob 的单词概率矩阵,它有 2000 行和 3 列。
此示例中的总词概率算法如下所示:
sum = 0
for j in range(0,3):
prob_product = 1
for i in words: #just the index of words from my vocabulary in this document
prob_product = prob_product*wordprob[i,j]
sum = sum + prob_product
最终发生的是 prob_product 由于许多小概率相互相乘而在多次迭代中变为 0。
由于我无法用日志轻松解决这个问题(因为前面的总结)我完全没有头绪
任何帮助将不胜感激。
你的问题似乎是关于事物的数学方面而不是它的编码。
我还没有完全弄清楚你的问题是什么,但日志的总和等于产品的日志。不知道这是否有帮助..
此外,您正在为每个 j 计算一个 prob_product 但您只是使用最后一个(并且您正在重新初始化它)。你打算做两件事之一:要么在 j 循环之前初始化它,要么在递增 j 之前使用它。最后,我认为您不需要初始化 sum 除非这是您未在此处显示的另一个循环的一部分。
这就是我现在的全部。
对不起,很长post,没有代码。
High school algebra 告诉你:
log(A*B*....*Z) = log(A) + log(B) + ... + log(Z) != log(A + B + .... + Z)
我认为您最好将所有内容都保存在日志中。第一部分计算乘积的对数只是将项的对数相加。第二位,计算对数指数总和的对数有点棘手。
一种方法是将每个产品的日志存储在一个数组中,然后您需要一个函数,给定一个包含 n 个元素的数组 L,它将计算
S = log( sum { i=1..n | exp( L[i])})
一种方法是找到 L 的最大值,比如说 M;一点代数显示
S = M + log( sum { i=1..n | exp( L[i]-M)})
L[i]-M 中的每一项都是非正的,因此不会发生溢出。下溢不是问题,因为它们 exp 将 return 0。至少其中一个(L[i] 为 M 的那个)将为零,因此 exp 将为 1,我们将得到一些结果我们可以传递给日志。换句话说,公式的计算将没有问题。
如果你有函数 log1p (log1p(x) = log(1+x)) 那么你可以通过省略(只有一个!)i 来获得一些准确性,其中 L[i] == M 来自总和,并将总和传递给 log1p 而不是 log.
我正在 Python 中从头开始构建朴素贝叶斯文本 classifier 并且我知道,在遇到概率非常小的乘积时,对概率使用对数是不错的选择。
现在的问题是,我使用的数学函数对这些极小概率的乘积求和。
具体来说,我正在尝试计算给定混合成分 (class) 在所有 classes 中的总词概率。
简单地将这些总概率的对数相加是不正确的,因为总和的对数不等于对数之和。
举个例子,假设我有 3 classes,2000 个单词和 50 个文档。 然后我有一个名为 wordprob 的单词概率矩阵,它有 2000 行和 3 列。
此示例中的总词概率算法如下所示:
sum = 0
for j in range(0,3):
prob_product = 1
for i in words: #just the index of words from my vocabulary in this document
prob_product = prob_product*wordprob[i,j]
sum = sum + prob_product
最终发生的是 prob_product 由于许多小概率相互相乘而在多次迭代中变为 0。
由于我无法用日志轻松解决这个问题(因为前面的总结)我完全没有头绪
任何帮助将不胜感激。
你的问题似乎是关于事物的数学方面而不是它的编码。 我还没有完全弄清楚你的问题是什么,但日志的总和等于产品的日志。不知道这是否有帮助.. 此外,您正在为每个 j 计算一个 prob_product 但您只是使用最后一个(并且您正在重新初始化它)。你打算做两件事之一:要么在 j 循环之前初始化它,要么在递增 j 之前使用它。最后,我认为您不需要初始化 sum 除非这是您未在此处显示的另一个循环的一部分。
这就是我现在的全部。 对不起,很长post,没有代码。
High school algebra 告诉你:
log(A*B*....*Z) = log(A) + log(B) + ... + log(Z) != log(A + B + .... + Z)
我认为您最好将所有内容都保存在日志中。第一部分计算乘积的对数只是将项的对数相加。第二位,计算对数指数总和的对数有点棘手。
一种方法是将每个产品的日志存储在一个数组中,然后您需要一个函数,给定一个包含 n 个元素的数组 L,它将计算
S = log( sum { i=1..n | exp( L[i])})
一种方法是找到 L 的最大值,比如说 M;一点代数显示
S = M + log( sum { i=1..n | exp( L[i]-M)})
L[i]-M 中的每一项都是非正的,因此不会发生溢出。下溢不是问题,因为它们 exp 将 return 0。至少其中一个(L[i] 为 M 的那个)将为零,因此 exp 将为 1,我们将得到一些结果我们可以传递给日志。换句话说,公式的计算将没有问题。
如果你有函数 log1p (log1p(x) = log(1+x)) 那么你可以通过省略(只有一个!)i 来获得一些准确性,其中 L[i] == M 来自总和,并将总和传递给 log1p 而不是 log.