[Jeremy Hylton[
> The total collections are 1100 messages.  I trained with 1100/5
> messages.
I'm reading this now as that you trained on about 220 spam and about 220
ham.  That's less than 10% of the sizes of the training sets I've been
using.  Please try an experiment:  train on 550 of each, and test once
against the other 550 of each.  Do that a few times making a random split
each time (it won't be long until you discover why directories of individual
files are a lot easier to work -- e.g., random.shuffle() makes this kind of
thing trivial for me).

While that's not a lot of training data, I picked random subsets of my
corpora and got much better behavior (this is rates.py output; f-p rate per
Training on Data/Ham/Set1 & Data/Spam/Set1 ... 220 hams & 220 spams
Training on Data/Ham/Set2 & Data/Spam/Set2 ... 220 hams & 220 spams
Training on Data/Ham/Set3 & Data/Spam/Set3 ... 220 hams & 220 spams
Training on Data/Ham/Set4 & Data/Spam/Set4 ... 220 hams & 220 spams
Training on Data/Ham/Set5 & Data/Spam/Set5 ... 220 hams & 220 spams
Another full run with another randomly chosen (but disjoint) 220 of each in
each set was much the same.  The score distribution is also quite sharp:
It's hard to say whether you need better ham or better spam, but I suspect
better spam <wink>.  18 of the 30 most powerful discriminators here were
HTML-related spam indicators; the top 10 overall were:
The HTML tags come from non-multipart/alternative HTML messages, from which
HTML tags aren't stripped, and there are lots of these in my spam sets.
That doesn't account for it, though.  If I strip HTML tags out of those too,
raining on Data/Ham/Set1 & Data/Spam/Set1 ... 220 hams & 220 spams
raining on Data/Ham/Set2 & Data/Spam/Set2 ... 220 hams & 220 spams
raining on Data/Ham/Set3 & Data/Spam/Set3 ... 220 hams & 220 spams
raining on Data/Ham/Set4 & Data/Spam/Set4 ... 220 hams & 220 spams
raining on Data/Ham/Set5 & Data/Spam/Set5 ... 220 hams & 220 spams
The 4th-strongest discriminator *still* finds another HTML clue, though!