2010-06-07 200 views
3

我正在python/django中構建一個網站,並且想要預測用戶提交是否有效或它是垃圾郵件。計算垃圾郵件概率

用戶對他們提交的內容具有接受率,就像本網站一樣。

用戶可以調節其他用戶的提交;並且這些調整由管理員稍後進行元代碼管理。

有鑑於此:

  • 與提交註冊用戶A接受的60%的速度提交的東西。
  • 用戶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取得了10萬份意見書。其中60194個是「火腿」。
  • 用戶B已正確主持了29864次提交。
  • 用戶C已正確主持了79990個提交。
  • 「垃圾郵件」被用戶B識別爲「垃圾郵件」,用戶C識別爲「火腿」2346次。
  • 'ham'被用戶B和'ham'識別爲'垃圾',用戶C 33634次。
  • 如果用戶B說它是垃圾郵件,而用戶C說這是垃圾郵件,那麼它將佔垃圾郵件總數的6.52%,並佔用93.48%的時間。

這裏的概率是否合理?這是模擬場景的正確方法嗎?

+0

14.4%它不是垃圾郵件;-) – Boldewyn 2010-06-07 15:12:52

回答

5

Bayes' Theorem告訴我們:

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

讓我們改變字母的事件A和B,X和Y RESP。因爲你使用A,B和C代表的人,這會讓事情困惑:

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

編輯:以下是略微錯誤的,因爲Xthis post _by A_ is spam,不只是「這個職位垃圾郵件「(因此Y應該是」B接受A的郵件,C拒絕它「)。我不會在這裏重新計算數字,因爲無論如何都會改變數字 - 請參閱下面的其他編輯,以獲取正確的數字正確的算術。

你想X意思是「這個職位是垃圾郵件」,Y來代表情況A has posted it, B approved it, C rejected it(並假設有條件的獨立性的情況下)。

我們需要P(X),任何帖子(無論是誰製作或批准)都是垃圾郵件的先驗概率;​​,由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的猜測,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的無條件接受概率)和兩個模糊的「handwaving」陳述(關於低精度和高精度),所以這裏有很多自由度。

如果您可以更好地估計五個關鍵數字,可以使計算更加精確。

而且,BTW,Python(以及更高級的Django)與這種情況完全無關 - 我建議您刪除那些不相關的標籤以獲得更廣泛的響應!

編輯:用戶澄清(在評論 - SHD真的編輯自己的Q!):

當我說 「B的審覈的接受 率只有30%,」 我的意思是對於 每隔十次B溫和一些東西 垃圾郵件/沒有垃圾郵件他使錯誤的 決定7次。所以有70%的機會,他會在沒有垃圾郵件時標記垃圾郵件/沒有郵件 。對於用戶C,「他的 審覈」接受率爲80%「意味着 ,如果C說有東西是垃圾郵件或沒有 垃圾郵件,他是正確的80%的時間。 發送垃圾郵件的註冊用戶總數有2035%。

...並要求我重做數學(我假設假陽性和陰性對於B和C每個都是相同的可能性)。請注意,B是一個很好的「逆向指標」,因爲他錯了70%的時間!)。無論如何: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.4之前錯在0.2 - 垃圾郵件的整體概率是不相關的,因爲我們知道該帖子是A的!); P(Y)=0.46*0.56=0.2576(B對A的C次拒絕概率的總體接受率); 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的拒絕率都會提高它,所以的這個特定帖子有大約87%的被垃圾郵件可能性。

+0

我建議在實施貝葉斯法則時尋找關於精度的答案。 http://stackoverflow.com/questions/2691021/problem-with-precision-floating-point-operation-in-c – Jacob 2010-06-07 17:38:51

+0

@Jacob,與OP需要少量的操作我不認爲這是一個擔心在這案例(儘管使用日誌不是一個壞主意)。如果需要更高精度的算術,GMP,MPIR&c總是可用的(如果OP想要使用Python,可以使用'gmpy'包裝,正如他最初所表明的那樣 - 儘管我說服他去掉那個標籤,因爲他在這個階段的問題找到正確的公式,所以在實現上述公式中擔心數字和編程問題有點不成熟 - 「分離問題」是可取的; - )。 – 2010-06-07 18:31:30

+0

@alex - 如果您可以重做算法,我會非常感激 - 我的頭在游泳! :-)我發現用實數學習示例比學習算法更容易學習。 – Hobhouse 2010-06-07 18:59:13

2

可以使用bayesean分類來檢測垃圾郵件,並根據修改結果選擇垃圾郵件和火腿的訓練集。結果也可能由用戶接受的帖子的比率加權。

垃圾郵件可能性很高的結果可能會被推送到審覈工作流程中(如果您有專門的版主)。同樣,前調節結果的樣本可以提交到元調節工作流程中,以獲得關於分類質量的觀點(即,我們是否得到了不可接受的高誤報率和負值)。

最後,用戶可能會抱怨發佈內容不公平的「吸引力」,也可能會將發帖推入元調節工作流程。如果用戶有上訴拒絕歷史或提交上訴率過高(可能是DOS攻擊的嘗試),則他們的上傳可能會在上訴工作流程中被分配逐漸降低的優先級。

-1

我們更爲經驗地去了解它。

我們發現垃圾郵件的最佳指標之一是發佈/評論中的外部鏈接數量,因爲垃圾郵件的全部內容是讓您去某個地方併購買某物和/或進行友善googlebot認爲鏈接頁面更有趣。

我們對未註冊用戶的一般規則是:1個鏈接可能是好的,2個是80%+可能是垃圾郵件,3個或更多,他們是烤麪包。我們保留出現在被拒絕帖子中的主要域名列表,即使在1或2鏈接器中,這些域名也會成爲觸發器。你也可以使用RBL,但要小心,因爲它們可能非常嚴格。

這個簡單的東西可能不適合你,但它大大減少了我們的版主的負擔,我們沒有真正的人類抱怨。