sang.pl - Suffix Array を用いて N-gram 統計をとるプログラム
2010-06-21-1
[Programming]
SUFARY に付属している sang というプログラムの Perl 版「sang.pl」を作りました。
オリジナルCコード(sang.c)に書いてある説明を改変して載せておきます。
使い方は同じです。
■コード(sang.pl):
■実行例:
インデックス作成。
対象ファイルは utf-8。
mkipu8.pl[2007-06-10-3]を使う。
4-gram で頻度は3よりも大きいものを出力。
ref.
- SUFARY 臨時復旧ページ http://ta2o.net/tools/sufary/
(SUFARYの入手はここから。)
- [を] SUFARY用インデクサのPerl版の雛形[2007-06-10-3]
(mkipu8.pl のソースはここに。)
- [を] 自分マイニング! - Blogでよく使うフレーズは?[2005-01-18-3]
(sang を使ったデータマイニング例。)
オリジナルCコード(sang.c)に書いてある説明を改変して載せておきます。
使い方は同じです。
sang.pl --- Suffix Array を用いて N-gram 統計をとるプログラム USAGE sang.pl -n NUM -t NUM FILENAME OPTION -n NUM : NUM で n-gram の n を指定する。 -t NUM : threshold: NUM以下の頻度のものは表示しない n-gram には改行は含まれない。 [実行例] % cat test ABCBACABBAACABCABCACABACABBACBACACAAABACCAB % makeary -q test ● arrayファイルの作成 % sang -n 6 -t 1 test ● 6-gram で頻度が 1 より大きいものを表示 2 ACABBA 2 BACABB % ./sang.pl -n 3 -t 4 test ● trigram で頻度が 4 より大きいものを表示 6 ACA 5 BAC 6 CAB
■コード(sang.pl):
#!/usr/bin/perl
use strict;
use warnings;
use SUFARY;
use Encode;
use Getopt::Std;
use utf8;
use open ':utf8';
binmode STDOUT, ":utf8";
my %opts = ();
getopts("n:t:", \%opts);
my $ng = $opts{n} || 4;
my $threshold = $opts{t} || 3;
my $fn = shift @ARGV;
my $sa = SUFARY->new($fn);
my $n_ctr = 0;
my @ktoks = ();
for (my $i = 0; $i < $sa->{arraysize}; $i++) {
my $pos = $sa->get_position($i);
my ($from, $len) = $sa->get_line_info($pos);
my $s = $sa->get_string($pos, $from + $len - $pos);
$s =~ s/^([^\n]+)\n.*$/$1/;
my @ttoks = map {Encode::decode_utf8($_)}
($s =~ m{([\x00-\x7f]|[\xC0-\xDF][\x80-\xBF]|
[\xE0-\xEF][\x80-\xBF]{2}|[\xF0-\xF7][\x80-\xBF]{3})}gsx);
if (cmp_tok(\@ktoks, \@ttoks) >= $ng) {
$n_ctr++;
} else {
output();
$n_ctr = 1;
}
@ktoks = @ttoks;
}
output() if $n_ctr >= 1;
sub output {
return if $n_ctr <= $threshold;
print "$n_ctr ".join("", @ktoks[0..($ng-1)])."\n";
}
sub cmp_tok {
my ($k_ref, $t_ref) = @_;
my $i;
for ($i = 0; $i < @$k_ref and $i < @$t_ref; $i++) {
last if $k_ref->[$i] ne $t_ref->[$i];
}
return $i;
}
■実行例:
インデックス作成。
対象ファイルは utf-8。
mkipu8.pl[2007-06-10-3]を使う。
N-gram カウント。% ./mkipu8.pl a.txt > a.txt.ary % mkary -so a.txt
4-gram で頻度は3よりも大きいものを出力。
% ./sang.pl -n 4 -t 3 a.txt 4 100円 5 「ぬんな 10 ぬんなり 4 ました。 4 まったり 5 んなり」
ref.
- SUFARY 臨時復旧ページ http://ta2o.net/tools/sufary/
(SUFARYの入手はここから。)
- [を] SUFARY用インデクサのPerl版の雛形[2007-06-10-3]
(mkipu8.pl のソースはここに。)
- [を] 自分マイニング! - Blogでよく使うフレーズは?[2005-01-18-3]
(sang を使ったデータマイニング例。)
