代码之家  ›  专栏  ›  技术社区  ›  afeldspar

计算垃圾邮件概率

  •  3
  • afeldspar  · 技术社区  · 5 年前

    我正在用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份提交。
    • “spam”被用户b标识为“spam”,被用户c 2346标识为“ham”。
    • “ham”被用户b标识为“spam”,被用户c 33634标识为“ham”。
    • 如果用户B说是垃圾邮件,而用户C说是火腿,那么6.52%的时间是垃圾邮件,93.48%的时间是火腿。

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

    3 回复  |  直到 14 年前
        1
  •  5
  •   Community kfsone    8 年前

    bayes'定理 告诉我们:

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

    p(x y)=p(y x)p(x)/p(y)
    < /代码> 
    
    

    edit:以下内容稍有错误,因为xshould bethis post u b y a_u is spam->code>,not just“this post is spam”(and so y should just be“b accepts a's post,c rejects it”)。我不会在这里重做数学,因为数字无论如何都会改变--请参阅下面的其他编辑以获得正确的数字正确的算术。

    您想让x表示“这篇文章是垃圾邮件”,y代表情况的组合a已经发布了它,b批准了它,c拒绝了它(并且让我们假设有条件的独立性)。

    我们需要p(x),a priori probability that any post(无论谁制作或批准它)is spam;p(y),a priori probability that a post would be made b y a,approved b y b,rejected b y c(when it's spam or not);andp(y x),same a s the later but with the post being spam.

    正如你可能注意到的,你并没有给我们计算所需的全部零碎。你的三点告诉我们: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's overall acceptance time s c's rejection prob);p(y x)=0.4*0.25*0.75=0.075(a's prob of spamming time b's prob of accepting spam time c's prob of rejecting spam)。.

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

    但是,当然(即使在简化条件独立假设的情况下,=)这个计算对我关于b和c的假阳性与假阴性的比率,以及总体垃圾邮件比率的猜测/假设非常敏感。这类问题涉及到五个数字(总体垃圾邮件问题,针对垃圾邮件和非垃圾邮件的b和c中的每一个b和c的条件问题),而您只给我们两个相关(线性)约束(针对b和c的无条件接受问题)和两个模糊的“握手”语句(关于低和高精度),因此有足够的自由度。

    如果您能更好地估计五个键的数字,计算就可以更加精确。

    而且,顺便说一句,python(和fortiori-django)与这个案例完全无关——我建议您删除那些不相关的标签,以获得更广泛的响应范围!

    edit:用户澄清(在注释中--shd really edit his q!)

    < Buff行情>

    当我说“B的适度”接受 利率只有30%“我是说 每十次B缓和一些东西 垃圾邮件/没有垃圾邮件他做错了 决定7次。所以有70% 有可能他会标记一些垃圾邮件/不 如果不是垃圾邮件。对于用户C,“他的 适度的“接受率为80%”是指 如果C说什么是垃圾邮件或者没有 垃圾邮件,他百分之八十是对的。 注册用户的总体机会 垃圾邮件是20%。

    < /块引用>

    …并要求我重做数学(我假设b和c中的每一个都有可能出现误报和否定)。请注意,B是一个优秀的“逆向指标”,因为他有70%的时间是错的!-)< /P>

    总之: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--Theoverallprob of spam i s not relevant,because we know the post i s a's!);p(y)=0.46*0.56=0.2576(b's overall acceptance rate for a time s c's rejection prob for a);p(y x)=0.7*0.8=0.56(b's prob of accepting spam time c's prob of rejecting spam).

    所以p(x_y)=0.56*0.4/0.2576=0.87(rounding)。IOW:虽然A的帖子是垃圾邮件的概率是0.4,但是B的接受度和C的拒绝度都会提高它,所以这个特定的A的帖子有大约87%成为垃圾邮件的可能性。

    让我们将事件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将由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的条件问题),您只给我们两个相关(线性)约束(针对b和c的无条件接受问题)和两个模糊的“握手”语句(关于低和高精度),因此这里有很大的自由度。

    如果你能更好地估计五个键的数字,计算就更精确了。

    而且,顺便说一句,python(和fortiori-django)与这个案例完全无关——我建议您删除那些不相关的标签,以获得更广泛的响应范围!

    编辑:用户澄清(在注释中——shd真的编辑了他的q!):

    当我说“B的适度”接受 利率只有30%“我是说 每十次B缓和一些东西 垃圾邮件/没有垃圾邮件他做错了 决定7次。所以有70% 有可能他会标记一些垃圾邮件/不 如果不是垃圾邮件。对于用户C,“他的 适度的“接受率为80%”是指 如果C说什么是垃圾邮件或者没有 垃圾邮件,他百分之八十是对的。 注册用户的总体机会 垃圾邮件是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的时候犯了错误,因为我忽略了垃圾邮件的概率是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%的机会成为垃圾邮件。

        2
  •  2
  •   ConcernedOfTunbridgeWells    14 年前

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

    结果很可能是垃圾邮件,可以推到一个仲裁工作流(如果你有专门的仲裁人)。同样,可以将以前的缓和结果的样本提交到元缓和工作流中,以查看分类的质量(即,我们是否获得了不可接受的高误报率和否定率)。

    最后,一个用户可能抱怨帖子被不公平分类的“呼吁”也可能将帖子推到元调节工作流中。如果用户有上诉被拒绝的历史,或者上诉提交率过高(可能是DoS攻击的尝试),他们的帖子可能会在上诉工作流中被逐渐降低优先级。

        3
  •  -1
  •   Peter Rowell    14 年前

    我们更注重经验。

    我们发现垃圾邮件最好的指标之一是一篇文章/评论中的外部链接数量,因为垃圾邮件的关键是让你去某个地方买点东西和/或让友好的GoogleBot认为链接到页面更有趣。

    我们的一般规则 未注册用户 是:1个链接可以,2个是80%+可能是垃圾邮件,3个或更多,他们是烤面包。我们保留一个主要域名列表,这些域名出现在被拒绝的帖子中,即使在1或2链接器中,这些域名也会成为触发器。你也可以使用红细胞,但要小心,因为它们可能是真正的龙。

    这个简单的东西可能对你不起作用,但是它大大减少了我们的主持人的负担,我们没有来自真正的人类的抱怨。