它假设「给定类别之后,每个词之间互相独立」——这个假设明显是错的 ("免费"和"中奖"明明总是成对出现)。但就是靠着这个错误假设, 5574 条真实短信里的垃圾短信,它判对了 97%。 这一页让你亲手改一条短信,看每个词各自把票投给了谁。
想知道「这条短信是垃圾邮件的概率」,直接算很难。但训练数据能告诉我们相反方向的事: 「垃圾邮件里出现"免费"的概率」。贝叶斯定理把两者接起来:
分母 对所有类别都一样, 所以比较时可以直接丢掉。这就是为什么页面上的"判决分数"只有两部分: 类先验 和 似然。
是一整条短信(150 个词的出现与否)。 要算 ,得知道这 150 个位置的联合分布—— 参数量是天文数字。于是朴素贝叶斯直接假设它们条件独立:
连乘取对数变求和,每个词就只需要一个概率:
这个假设当然是错的。但它错得很"便宜": 条件独立假设带来的偏差,是把每个词的证据重复计算了; 可好处是参数量从指数级降到线性级——150 个词只要估计 150 个数。 在文本分类这种"特征多、数据相对少"的场景里,这笔买卖非常划算。
两种建模方式,差别只在 怎么算:
claim 这个词在训练集里 spam 出现了 108 次、ham 出现了 0 次。 如果不做平滑,, 那么任何一条含 claim 的正常短信都会被判成垃圾——而且概率算出来是 0, 连"有多确信"都说不出来。所以所有计数都加一个 α:
α = 1 就是常说的拉普拉斯平滑。α 太小容易过拟合,α 太大又会让所有词看起来差不多—— 把右侧滑杆从 0.01 拖到 100,看准确率怎么变化。
scripts/prepare_sms.py --top 400
重新生成数据,自己试一下词表变大后准确率怎么走。