入力にテキスト(文章)を与えると、それに対する平均情報量(エントロピー)を計算するだけの Perl スクリプトです。
各文字(または指定により任意のトークン)の確率(p)を求めて下記の式で計算するだけ[1]。

コマンドラインオプション:
- "-k NUM" : TSVのときに使うカラムを指定。指定なしだと全て。
- "-l" : 1行ごとに平均情報量を計算。指定なしだと全行まとめて。
- "-s STRING" : テキスト分割用のセパレータを指定。指定なしだと文字単位になる。
■コード (aventro.pl)
■実行例
http://www.infonet.co.jp/ueyama/ip/binary/entropy.html
[2] 日本語ツイートの情報量は、世界で2番目に少ないらしい (TEXT/YUBASCRIPT)
http://blog.yubais.net/3.html
各文字(または指定により任意のトークン)の確率(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
この記事に言及しているこのブログ内の記事
