#!/usr/bin/perl -w # Copyright (C) 2003 level # License: GPL # spamdump.pl v1.1 May/29/2003 # http://www5e.biglobe.ne.jp/~level0/mozilla/ # Mozillaのtraining.datをダンプする。 # # Usage: spamdump [-s(1-4)] [-limit [+|-]p] [-v] [trainig.dat] # # -s(1-4) # ソートのキーを指定する。 # 1: spam確率(デフォルト) # 2: spamカウント # 3: non-spamカウント # 4: 単語 # -limit [+|-]p # pは0以上1以下の実数 # 正の実数の場合スパム確率がp以上の単語のみをダンプする # 負の実数の場合スパム確率がp以下の単語のみをダンプする # デフォルトではすべての単語をダンプする。 # -v : verbose mode # use strict; my $nGood; # non-spamメッセージの数 my $nBad; # spamメッセージの数 my @goodarray; # non-spamでの単語数 my @badarray; # spamでの単語数 my @spamprob; # spam確率 my @wordarray; # 単語。%hashの逆方向 my $index=0; # goodarray/badarray/spamprobのindex my %hash; # 単語のハッシュ、keyは単語、値は$index my $pmin = 0.0; # これより大きなspam確率の単語をダンプする my $pmax = 1.0; # これより小さなspam確率の単語をダンプする my $bmin = 0; # これより大きなspamカウントの単語をダンプする my $verbose= 0; my $sort_key = 1; # 1:spam確率、2:spamカウント、3:non-spamカウント、4:単語 &read_option(); printf("pmin=%f pmax=%f bmin=%d\n",$pmin,$pmax,$bmin); &read_header(); &read_ham(); &read_spam(); &dump_info(); ##################################################### #ヘッダ部分 sub read_header{ my $cookie; read(STDIN,$cookie,4); if ($cookie ne "\xfe\xed\xfa\xce") { die "Illegal file type"; } $nGood = &ReadInt(); $nBad = &ReadInt(); printf("nGood %d\n",$nGood); printf("nBad %d\n",$nBad); if ($verbose) { printf(STDERR "nGood %d\n",$nGood); printf(STDERR "nBad %d\n",$nBad); } } #ham(non-spam)の情報 sub read_ham{ my $total = &ReadInt(); my $i; printf("total non-spam tokens %d\n",$total); printf(STDERR "total non-spam tokens %d\n",$total) if ($verbose); for ($i=0;$i<$total;$i++) { my $count = &ReadInt(); my $word = &ReadStr(); #printf("%4d %s\n",$count,$word); $goodarray[$index] = $count; $hash{$word} = $index; $index++; } } #spamの情報 sub read_spam{ my $total = &ReadInt(); my $i; printf("total spam tokens %d\n",$total); printf(STDERR "total spam tokens %d\n",$total) if ($verbose); for ($i=0;$i<$total;$i++) { my $count = &ReadInt(); my $word = &ReadStr(); # printf("%4d %s\n",$count,$word); my $ii = $hash{$word}; if (defined ($ii)) { $badarray[$ii] = $count; } else { $hash{$word} = $index; $badarray[$index] = $count; $index++; } } } #spam確率の計算、情報をダンプする sub dump_info{ my ($word,$p,$i,$g,$b); foreach $word (keys(%hash)) { $i = $hash{$word}; # index $g= $goodarray[$i]; # good count if (!defined($g)) { $g = 0; $goodarray[$i] = 0} $g *= 2.0; $b = $badarray[$i]; # badcount; if (!defined($b)) { $b = 0; $badarray[$i] = 0;} if ($g+$b>5 && $nBad && $nGood) { $p = max(0.01, min(0.99, (min(1.0, ($b / $nBad)) / (min(1.0, ($g / $nGood)) + min(1.0, ($b / $nBad)))))); } else { $p = 0.4; } $spamprob[$i] = $p; $wordarray[$i] = $word; } my @indexes; @indexes = sort by_prob values(%hash) if ($sort_key==1); @indexes = sort by_nbad values(%hash) if ($sort_key==2); @indexes = sort by_ngood values(%hash) if ($sort_key==3); @indexes = sort by_word values(%hash) if ($sort_key==4); foreach $i (@indexes) { $g = $goodarray[$i]; if (!defined($g)) { $g = 0; } $b = $badarray [$i]; if (!defined($b)) { $b = 0; } $p = $spamprob [$i]; $word = $wordarray[$i]; if ($p>=$pmin && $p<=$pmax && $b>=$bmin) { printf("%5d %5d %5.3f %s\n",$g,$b,$p,$word); } } } # $sort_key=1:spam確率 sub by_prob{ $spamprob [$b] <=> $spamprob [$a] || $badarray [$b] <=> $badarray [$a] || $goodarray[$b] <=> $goodarray[$a] || $wordarray[$b] cmp $wordarray[$a]; } # $sort_key=2:spamカウント sub by_nbad{ $badarray [$b] <=> $badarray [$a] || $goodarray[$b] <=> $goodarray[$a] || $spamprob [$b] <=> $spamprob [$a] || $wordarray[$b] cmp $wordarray[$a]; } # $sort_key=3:non-spamカウント sub by_ngood{ $goodarray[$b] <=> $goodarray[$a] || $badarray [$b] <=> $badarray [$a] || $spamprob [$b] <=> $spamprob [$a] || $wordarray[$b] cmp $wordarray[$a]; } # $sort_key=4:単語 sub by_word{ $wordarray[$b] cmp $wordarray[$a]; } sub usage{ print STDERR<= 0 && $ARGV[0]=~/^\-/) { my $v; if ($#ARGV >= 1 && $ARGV[0] eq "-limit") { $v = $ARGV[1]; if ($v>0) { $pmin = $v; } else { $pmax = -$v; } shift(@ARGV); shift(@ARGV); } elsif ($ARGV[0] =~ /^\-s([1-4])$/ ) { $sort_key = $1; shift(@ARGV); } elsif ($ARGV[0] eq "-v") { $verbose = 1; shift(@ARGV); } else { print(STDERR "ilegal option: $ARGV[0]\n"); &usage(); } } if ($#ARGV>=0) { open(STDIN,$ARGV[0]) || die "Can't open file: $ARGV[0]"; shift(@ARGV); } } # からIntのデータを1個読み返す sub ReadInt { my $val; read(STDIN,$val,4); return unpack("N",$val); } sub ReadStr { my $len = &ReadInt(); my $s; read(STDIN,$s,$len); return $s; } sub max { return ($_[0]>$_[1])?$_[0]:$_[1]; } sub min { return ($_[0]<$_[1])?$_[0]:$_[1]; }