古い記事
ランダムジャンプ
新しい記事
入力にテキスト(文章)を与えると、それに対する平均情報量(エントロピー)を計算するだけの Perl スクリプトです。

各文字(または指定により任意のトークン)の確率(p)を求めて下記の式で計算するだけ[1]。



コマンドラインオプション:
- "-k NUM" : TSVのときに使うカラムを指定。指定なしだと全て。
- "-l" : 1行ごとに平均情報量を計算。指定なしだと全行まとめて。
- "-s STRING" : テキスト分割用のセパレータを指定。指定なしだと文字単位になる。

■コード (aventro.pl)
#!/usr/bin/env perl
use strict;
use warnings;
use List::Util qw(sum);
use Getopt::Long;
use utf8;
use open ":utf8";
binmode STDIN, ":utf8";
binmode STDOUT, ":utf8";

my $key_at_str = 0; # key=POS : process only POS-th column (origin 1)
my $sep = ""; # token separator
my $line_mode = 0; # process each-line
GetOptions(
    "key=s" => \$key_at_str,
    "sep=s" => \$sep,
    "line" => \$line_mode,
);

my %freq;
while (<>) {
    chomp;
    $_ = (split(/\t/, $_))[$key_at_str-1] if $key_at_str;
    next if /^\s*$/;
    my @c = split(/$sep/, $_);
    $freq{$_}++ for @c;
    if ($line_mode) {
	printf "%.8f\n", calc_entro(\%freq);
        %freq = ();
    }
}
printf "%.8f\n", calc_entro(\%freq) if not $line_mode;

sub calc_entro {
    my ($r) = @_;
    my $sum = sum(values %$r);
    my $H = -1 * sum(map {my $p = $r->{$_}/$sum; $p * log($p)/log(2)} keys %$r);
    return $H;
}

■実行例
% cat test-1.txt
六本木から渋谷へ行くには恵比寿経由かな
今日は高校で国語のテストです
バナナとリンゴ
あはははは
ああああ
% ./aventro.pl test-1.txt   
4.93880341
% ./aventro.pl -l test-1.txt
4.14266436
3.66449778
2.52164064
0.72192809
0.00000000
% cat test-2.tsv
1	六本木,から,渋谷,へ,行く,に,は,恵比寿,経由,で,山手線,で,行く
2	今日,は,国語,の,テスト,は,ない
3	バナナ,と,リンゴ
4	あはははは
% ./aventro.pl -k 2 -s "," test-2.tsv
4.22017552
% ./aventro.pl -k 2 -s "," -l test-2.tsv
3.39274741
2.52164064
1.58496250
0.00000000

参考

[1] 平均情報量/エントロピー
http://www.infonet.co.jp/ueyama/ip/binary/entropy.html
[2] 日本語ツイートの情報量は、世界で2番目に少ないらしい (TEXT/YUBASCRIPT)
http://blog.yubais.net/3.html
この記事に言及しているこのブログ内の記事