3

我正在 python/django 中建立一个网站,并想预测用户提交是有效的还是垃圾邮件。

用户对他们的提交有一个接受率,就像这个网站一样。

用户可以审核其他用户的提交;这些审核稍后由管理员进行元审核。

鉴于这种:

  • 提交接受率为60%的注册用户A提交了一些东西。
  • 用户 B 将 A 的帖子审核为有效提交。但是,用户 B 有 70% 的情况是错误的。
  • 用户 C 将 A 的帖子审核为垃圾邮件。用户 C 通常是对的。如果用户 C 说某事是垃圾邮件/非垃圾邮件,那么 80% 的时间都是正确的。

如何预测 A 的帖子成为垃圾邮件的可能性?

编辑:我制作了一个模拟这种情况的python脚本:

#!/usr/bin/env python

import random

def submit(p):
    """Return 'ham' with (p*100)% probability"""
    return 'ham' if random.random() < p else 'spam'

def moderate(p, ham_or_spam):
    """Moderate ham as ham and spam as spam with (p*100)% probability"""
    if ham_or_spam == 'spam':
        return 'spam' if random.random() < p else 'ham'
    if ham_or_spam == 'ham':
        return 'ham' if random.random() < p else 'spam'

NUMBER_OF_SUBMISSIONS = 100000 
USER_A_HAM_RATIO = 0.6 # Will submit 60% ham
USER_B_PRECISION = 0.3 # Will moderate a submission correctly 30% of the time
USER_C_PRECISION = 0.8 # Will moderate a submission correctly 80% of the time

user_a_submissions = [submit(USER_A_HAM_RATIO) \
                        for i in xrange(NUMBER_OF_SUBMISSIONS)]

print "User A has made %d submissions. %d of them are 'ham'." \
        % ( len(user_a_submissions), user_a_submissions.count('ham'))

user_b_moderations = [ moderate( USER_B_PRECISION, ham_or_spam) \
                        for ham_or_spam in user_a_submissions]

user_b_moderations_which_are_correct = \
    [i for i, j in zip(user_a_submissions, user_b_moderations) if i == j]

print "User B has correctly moderated %d submissions." % \
    len(user_b_moderations_which_are_correct)

user_c_moderations = [ moderate( USER_C_PRECISION, ham_or_spam) \
                        for ham_or_spam in user_a_submissions]

user_c_moderations_which_are_correct = \
    [i for i, j in zip(user_a_submissions, user_c_moderations) if i == j]

print "User C has correctly moderated %d submissions." % \
    len(user_c_moderations_which_are_correct)

i = 0
j = 0    
k = 0 
for a, b, c in zip(user_a_submissions, user_b_moderations, user_c_moderations):
    if b == 'spam' and c == 'ham':
        i += 1
        if a == 'spam':
            j += 1
        elif a == "ham":
            k += 1

print "'spam' was identified as 'spam' by user B and 'ham' by user C %d times." % j
print "'ham' was identified as 'spam' by user B and 'ham' by user C %d times." % k
print "If user B says it's spam and user C says it's ham, it will be spam \
        %.2f percent of the time, and ham %.2f percent of the time." % \
         ( float(j)/i*100, float(k)/i*100)

运行脚本会给我这个输出:

  • 用户 A 提交了 100000 次。其中60194个是“火腿”。
  • 用户 B 已正确审核了 29864 个提交。
  • 用户 C 已正确审核了 79990 个提交。
  • “垃圾邮件”被用户 B 识别为“垃圾邮件”,被用户 C 识别为“火腿”2346 次。
  • 用户 B 将“ham”识别为“垃圾邮件”,用户 C 将“ham”识别为 33634 次。
  • 如果用户 B 说它是垃圾邮件,而用户 C 说它是 ham,那么 6.52% 的时间它是垃圾邮件,93.48% 的时间是 ham。

这里的概率合理吗?这是模拟场景的正确方法吗?

4

3 回答 3

5

贝叶斯定理告诉我们:

<code>P(A|B)=P(B|A)P(A)/P(B)</code>

让我们将事件 A 和 B 的字母分别更改为 X 和 Y。因为您使用 A、B 和 C 来代表人,这会使事情变得混乱:

P(X|Y) = P(Y|X) P(X) / P(Y)

编辑:以下内容略有错误,因为X应该是this post _by A_ is spam,而不仅仅是“这个帖子是垃圾邮件”(因此 Y 应该只是“B 接受 A 的帖子,C 拒绝它”)。我不会在这里重做数学,因为无论如何数字都会改变 - 请参阅下面的其他编辑以获取正确的数字正确的算术。

您想要X表示“此帖子是垃圾邮件”,Y以代表各种情况A has posted it, B approved it, C rejected it(并假设相关情况有条件独立)。

我们需要P(X),任何帖子(无论是谁发布或批准)是垃圾邮件的先验概率;P(Y), 一个帖子由 A 发布、由 B 批准、被 C 拒绝的先验概率(无论是否为垃圾邮件);和P(Y | X),与后者相同,但帖子是垃圾邮件。

您可能已经注意到,您并没有真正为我们提供计算所需的所有点点滴滴。您的三点告诉我们:A 的给定帖子是垃圾邮件,概率为 0.4(这似乎是第一点的意思);B 的接受概率是 0.3,但我们不知道垃圾邮件和非垃圾邮件有什么不同,除了应该有“小”差异(低准确度);C 是 0.8,我们不知道垃圾邮件与非垃圾邮件如何影响它,除了应该存在“大”差异(高精度)。

所以我们需要更多的数字!C 在接受 80% 的帖子时具有很高的准确率这一事实告诉我们,总体垃圾邮件必须非常低——如果总体垃圾邮件与 A 的 40% 相同,那么 C 将不得不接受其中的一半(即使他在始终接受非垃圾邮件方面非常完美)以获得 80% 的总体接受率,这几乎不是“高精度”。所以说垃圾邮件总体只有 20%,而 C 只接受其中的 1/4(并拒绝 1/16 的非垃圾邮件),确实非常准确,并且总体上与您提供的数字相匹配。

假设 B 接受了 30% 的整体,现在“知道”垃圾邮件整体为 20%,我们可以猜测 B 接受 1/4 的垃圾邮件和仅 5/16 的非垃圾邮件。

所以:P(X)=0.2; P(Y)=0.3*0.2=0.06(B 的总体接受乘以 C 的拒绝概率);P(Y|X)=0.4*0.25*0.75=0.075(A 发送垃圾邮件的概率 B 接受垃圾邮件的概率 C 拒绝垃圾邮件的概率)。

所以P(X|Y)=0.075*0.2/0.06=0.25——除非我犯了一些算术错误(很有可能,重点是向你展示如何在这种情况下推理;-),这个特定帖子是垃圾邮件的概率是 0.25——比任何随机帖子成为垃圾邮件的概率,低于A的随机帖子成为垃圾邮件的概率。

但是,当然(即使是在整个地方条件独立的简化假设下;=)这个计算对我关于 B 和 C 的误报与误报的比率以及总体垃圾邮件比率的猜测/假设非常敏感。涉及到五个此类数字(总体垃圾邮件概率,垃圾邮件和非垃圾邮件的 B 和 C 的条件概率),您只给我们两个相关(线性)约束(B 和 C 的无条件接受概率)和两个模糊的“挥手”声明(关于低准确度和高准确度),所以那里有很多自由度。

如果你能更好地估计这五个关键数字,计算可以更精确。

而且,顺便说一句,Python(更何况 Django)与此案例完全无关——我建议您删除那些不相关的标签以获得更广泛的响应!

编辑:用户澄清(在评论中——shd真的编辑了他的Q!):

当我说“B 的审核接受率仅为 30%”时,我的意思是 B 每审核 10 次垃圾邮件/无垃圾邮件,他就会做出 7 次错误决定。所以有 70% 的机会他会标记垃圾邮件/没有垃圾邮件。对于用户 C,“他的审核接受率为 80%”意味着如果 C 说某事是垃圾邮件或非垃圾邮件,那么他在 80% 的情况下是对的。注册用户发送垃圾邮件的总体几率为 20%。

...并要求我重做数学运算(我假设 B 和 C 的误报和否定的可能性相同)。请注意,B 是一个出色的“反向指标”,因为他 70% 的时间都是错误的!-)。

无论如何:B 对 A 帖子的总体接受率必须是 0.6*0.3(当他接受 A 的非垃圾邮件时)+ 0.4*0.7(当他接受 A 的垃圾邮件时)= 0.18 + 0.28 = 0.46;C 必须是 0.8*0.4 + 0.2*0.6 = 0.32 + 0.12 = 0.44。所以我们有...:

P(X)=0.4(我之前在 0.2 时错了,因为我忽略了A的垃圾邮件概率为 0.4 的事实——垃圾邮件的整体概率不相关,因为我们知道帖子是 A 的!);P(Y)=0.46*0.56=0.2576(B 对 A 的总体接受率乘以 C 对 A 的拒绝概率);P(Y|X)=0.7*0.8=0.56(B 接受垃圾邮件的概率时间 C 拒绝垃圾邮件的概率)。

所以P(X|Y)=0.56*0.4/0.2576=0.87(四舍五入)。IOW:虽然 A 的帖子是垃圾邮件的先验概率是 0.4,但 B 的接受和 C 的拒绝都提高了概率,因此A 的这个特定帖子有大约 87% 的机会成为垃圾邮件。

于 2010-06-07T15:37:18.247 回答
2

可以使用贝叶斯分类来检测垃圾邮件并根据修改结果为垃圾邮件和火腿选择训练集。结果也可能由用户接受帖子的比率加权。

很可能是垃圾邮件的结果可能会被推送到审核工作流程中(如果您有专门的版主)。类似地,可以将以前审核的结果样本提交到元审核工作流中,以了解分类的质量(即,我们是否得到了令人无法接受的高误报率和误报率)。

最后,用户可以抱怨帖子被不公平分类的“上诉”也可以将帖子推入元审核工作流程。如果用户有上诉被拒绝的历史或提交上诉的比率过高(可能是 DOS 攻击的尝试),他们的帖子可能会在上诉工作流程中被分配逐渐降低的优先级。

于 2010-06-07T15:15:37.753 回答
-1

我们更凭经验来研究它。

我们发现垃圾邮件的最佳指标之一是帖子/评论中的外部链接数量,因为垃圾邮件的全部目的是让您去某个地方买东西和/或让友好的 googlebot 认为链接-to page 更有趣。

我们对未注册用户的一般规则是:1 个链接可能没问题,2 是 80%+ 可能是垃圾邮件,3 或更多,他们是敬酒。我们保留了出现在被拒绝帖子中的主要域名列表,即使在 1 或 2 链接器中,这些也会成为触发器。您也可以使用 RBL,但要小心,因为它们可能非常严厉。

这么简单的事情可能对您不起作用,但它大大减轻了我们版主的负担,而且我们没有收到真人的抱怨。

于 2010-06-07T16:17:45.930 回答