英単語の頻度を簡易集計する
なんとなく思いついたので、やってみました。入力に使ったページはhttp://en.wikipedia.org/wiki/Multiprocessing,http://en.wikipedia.org/wiki/Blogです。マルチバイト文字には対応してません。
shコマンドだけでやってみる
出現回数が多い順に、上位10件を表示します。
$ cat *.htm? | sed "s/<[^>]*>//g" | sed "s/\W/\n/g" | tr [A-Z] [a-z] | \ > grep [a-z] | sort | uniq -c | sort -rn | head 282 the 201 of 166 a 153 to 142 in 139 and 91 on 90 blog 71 blogs 67 is
コマンドの意味:(cat)HTMLファイルを出力→(sed)タグを削除→(sed)英字以外を全て改行に置換→(tr)大文字を小文字に→(grep)英字のみ抽出→(sort)一意にするため辞書順に並べ替え→(uniq)一意にして出現数を付加→(sort)数値が大きい順に並べ替え→(head)上位10件を表示
Perlで除外リスト付
標準入力からはテキストデータを受け取り、引数からは除外リストを受け取って処理します。ソートと上位10件表示は面倒なのでコマンドにさせます。
use strict; use warnings; # 除外リスト生成 my %excludes = (); for my $file (@ARGV) { -f $file or die "file '$file' does not exist"; open FILE, $file; while (<FILE>) { s/[\r\n]//g; $excludes{$_} = 1; } close FILE; } # 標準入力を処理 my %words = (); while (<STDIN>) { s/<[^>]+>//g; # タグを削除 tr [A-Z] [a-z]; # 大文字を小文字に my @a = grep { /^[a-z]+$/ } split /\W/; # 英字以外で分割して英字だけ抽出 for my $word (@a) { next if defined $excludes{$word}; # 除外リストにある場合はスキップ $words{$word} = 0 unless $words{$word}; ++$words{$word}; } } # 結果を出力 while (my ($key, $value) = each %words) { printf "%5d %s\n", $value, $key; }
$ cat *.htm? | perl word_count.pl list.txt | sort -rn | head 90 blog 71 blogs 41 multiprocessing 40 blogging 38 retrieved 32 bloggers 31 blogger 28 media 24 multiple 23 personal $
list.txt には簡単な単語1000語程度が含まれています。
Rubyで(以下略)
配列から配列をマイナスってのが面白そうなので、パフォーマンス度外視して使ってみる。
# 除外リスト生成 excludes = [] ARGV.each do |file| open(file) do |f| f.each do |line| excludes << line.chomp.downcase end end end # 単語リスト生成 words = [] STDIN.each do |line| line.gsub!(/<[^>]+>/, "") # タグ削除 words += line.downcase.split(/\W/).grep(/[a-z]/) # 英字以外で分割して英字だけ抽出 end words -= excludes # 単語リストから除外を取り除く words.uniq.each do |word| printf "%5d ", words.grep(word).size puts word end
$ cat *.htm? | ruby word_count.rb list.txt | sort -rn | head 90 blog 71 blogs 41 multiprocessing 40 blogging 38 retrieved 32 bloggers 31 blogger 28 media 24 multiple 23 personal $
結果は同じだけど、段違いに遅い。Perl版に近い実装にすればマシになるかな。