古い記事
ランダムジャンプ
新しい記事
一時期流行した「○○成分分析」を簡単に実現する方法。
サンプルとして perl のコード片で解説する。

コード(seibun.pl):
#!/usr/bin/perl
use strict;
use warnings;
use utf8;
use Encode;
use open ':utf8';
binmode STDIN, ":utf8";
binmode STDOUT, ":utf8";

my @data = (
    ["パン", 37],
    ["甘夏", 19],
    ["苺", 41],
    ["納豆", 23],
    ["LOVE", 31],
    );

while (<>) {
    chomp;
    my $r_ref = name2seibun($_, \@data);
    foreach my $i (@$r_ref) {
        last if $i->[1] == 0;
        print "$_ の $i->[1]% は $i->[0] でできています。\n";
    }
}

sub name2seibun {
    my ($str, $d_ref) = @_;
    my $num = 0;
    foreach my $d (split(//, encode('utf8', $str))) {
        $num *= 256;
        $num += unpack("C", $d);
    }
    my @rv;
    my $total;
    foreach my $i (@$d_ref) {
        my $rate = ($num % $i->[1]) / $i->[1];
        push @rv, [$i->[0], $rate];
        $total += $rate;
    }
    @rv = map {
        [$_->[0], int($_->[1] / $total * 100)]
    } sort {$b->[1] <=> $a->[1]} @rv;
    return \@rv;
}

実行例:
% cat a.txt
矢風太郎
スティーブ・ゲイツ
Bill Jobs
% ./seibun.pl a.txt
矢風太郎 の 67% は 甘夏 でできています。
矢風太郎 の 15% は LOVE でできています。
矢風太郎 の 8% は パン でできています。
矢風太郎 の 7% は 苺 でできています。
スティーブ・ゲイツ の 35% は 苺 でできています。
スティーブ・ゲイツ の 31% は 納豆 でできています。
スティーブ・ゲイツ の 20% は 甘夏 でできています。
スティーブ・ゲイツ の 10% は パン でできています。
スティーブ・ゲイツ の 3% は LOVE でできています。
Bill Jobs の 24% は パン でできています。
Bill Jobs の 23% は 納豆 でできています。
Bill Jobs の 19% は 苺 でできています。
Bill Jobs の 19% は LOVE でできています。
Bill Jobs の 12% は 甘夏 でできています。

ロジック解説:
(1) 各成分には適当な素数を割り振っておく。
(2) 文字列を256進数の数値とみなして10進数へ変換(桁は逆だが)。
(3) それぞれの成分に割り振った素数で割ったあまりをその素数で割って 0〜1 の成分値に正規化。
(4) 全成分値を正規化してパーセント表示。

ランダムを使わないのがポイント。ランダムを使うと名前と成分分析結果の対応データを保持する必要があり、処理速度やデータ容量の問題が発生する可能性がある。ランダムでなければそのような不必要な問題に煩わされず、放置したまま長く運営可能なサービスにできる。週末プログラマならば、保守の必要性を減らすことを優先するのがけっこう重要。

追記100209: 素数じゃない数字を設定していたので変更しました。 42→41