You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@spamassassin.apache.org by jm...@apache.org on 2007/10/18 22:09:14 UTC
svn commit: r586111 -
/spamassassin/branches/bug-5293-pluginized-bayes/lib/Mail/SpamAssassin/Plugin/OSBF.pm
Author: jm
Date: Thu Oct 18 13:09:13 2007
New Revision: 586111
URL: http://svn.apache.org/viewvc?rev=586111&view=rev
Log:
implement the Bayes chain rule algorithm
Modified:
spamassassin/branches/bug-5293-pluginized-bayes/lib/Mail/SpamAssassin/Plugin/OSBF.pm
Modified: spamassassin/branches/bug-5293-pluginized-bayes/lib/Mail/SpamAssassin/Plugin/OSBF.pm
URL: http://svn.apache.org/viewvc/spamassassin/branches/bug-5293-pluginized-bayes/lib/Mail/SpamAssassin/Plugin/OSBF.pm?rev=586111&r1=586110&r2=586111&view=diff
==============================================================================
--- spamassassin/branches/bug-5293-pluginized-bayes/lib/Mail/SpamAssassin/Plugin/OSBF.pm (original)
+++ spamassassin/branches/bug-5293-pluginized-bayes/lib/Mail/SpamAssassin/Plugin/OSBF.pm Thu Oct 18 13:09:13 2007
@@ -710,7 +710,8 @@
goto skip;
}
- $score = Mail::SpamAssassin::Bayes::Combine::combine($ns, $nn, \@sorted);
+ $score = bcr_combine($ns, $nn, \@sorted);
+ # $score = Mail::SpamAssassin::Bayes::Combine::combine($ns, $nn, \@sorted);
# Couldn't come up with a probability?
goto skip unless defined $score;
@@ -769,6 +770,47 @@
return $score;
}
+# combine using the Bayes chain rule algorithm described in the
+# EDDC paper
+
+sub bcr_combine {
+ my ($ns, $nn, $probary) = @_;
+
+ my $PCs = $ns / ($ns + $nn); # P(Ci) where i = "spam"
+ my $PCh = $nn / ($ns + $nn); # P(Ci) where i = "ham"
+ if ($ns + $nn == 0) {
+ return; # cannot combine without both ham *and* spam
+ }
+
+ my $Ps = 0.5; # accumulators
+ my $Ph = 0.5;
+ foreach my $p (@$probary) {
+ # note: the denominator is
+ #
+ # Sum (i=1 .. m) ( P (Fj | Ci) . P (Ci) )
+ #
+ # we only have two classes, s and h, with P(f | s) = $p, P(f | h) = 1-$p
+ #
+ # => ($p) * $PCs + (1-$p) * $PCh
+
+ my $invp = 1-$p;
+ my $denom = $p * $PCs + $invp * $PCh;
+ $Ps *= $p / $denom;
+ $Ph *= $invp / $denom;
+
+ # avoid underflow; if they've become ~0, reset to a non-0 value
+ # so that further multiplications still work
+ if ($Ps == 0) { $Ps = 1e-300; }
+ if ($Ph == 0) { $Ph = 1e-300; }
+ }
+
+ # pick the lowest value (a tip from
+ # http://www.bgl.nu/bogofilter/BcrFisher.html )
+ if ($Ph < $Ps) { $Ps = 1-$Ph; } else { $Ph = 1-$Ps; }
+
+ return $Ps;
+}
+
###########################################################################
# Plugin hook.
@@ -1250,7 +1292,7 @@
# 0.99 instead of 0.125, which makes more sense for us
my $K1 = 0.25;
my $K2 = 10;
- my $K3 = 4;
+ my $K3 = 1;
my $Sumf = $s + $n; die "assert: Sumf == 0" unless $Sumf;
my $WdotSumf = $weight * $Sumf;