古い記事
ランダムジャンプ
新しい記事
Wikipedia のキーワードリンクを使って関連語データ(関連キーワード集)
を作ってみた。

Wikipedia のデータはダウンロードページからbz2形式のを取ってきた。
日本のウィキペディアのXMLデータね。
(see Wikipedia:データベースダウンロード)

で、Perlスクリプトで以下の関連語データ作成処理を行った。
(スクリプトはこの記事の末尾に載せておく)

(1) 各キーワードページに含まれているキーワード(リンク)を取り出す。
例えばキーワードAのページにB,C,Dが含まれていたら、A => B,C,D というデータを蓄積。
またキーワードAが他のキーワードのページ(例えばX)に含まれていたら、それも蓄積。その場合、 A => B,C,D,X となる。

(2) 各キーワードのDFを計算する。
この場合のDocumentはキーワードページの数。

(3) ランキングの方法
(3-1) 相互リンクされているキーワード群と片方向リンクのキーワード群とに分けて、前者を優先して並べる。
(3-2) 各群の中ではDFの小さい順に並べる。
(3-3) 20位までで足切り。

処理が重くなるので単語の共起情報は使っていない。
そもそも共起情報を使わないとまともな関連情報は取れないのだが、週末にちょこちょこっとやるネタなので手軽な方法に終始している。

なお、":" や "|" を含むキーワードは無視している。
また、曖昧さ回避の括弧を消す、年月日を無視する、一覧系キーワードを無視する、などのヒューリスティックもいくつか使っている。

完成したデータは下記のような TSV である。キーワードの後ろの数字はDF。
ヨーグルト  ダヒ:4  スメタナ:12  イリヤ・メチニコフ:17  腸内細菌:39 ...
鶴巻温泉  陣屋事件:7  鶴巻温泉駅:13  秦野市:197  ...
麦芽  糖化:27  発芽:41  水飴:70  酵素:451  ビール:545  ...
データサイズは130Mバイト。53万エントリ。
関連語のないキーワードは含めていない。

gzip したものを下記URLに置いておく。勝手に使って。
もちろん無償・無保証。
- http://wikipehacks.ta2o.net/relwords/pseudo/wp-rel.txt.gz (51M)

利用例として単純な検索CGIも置いておく。
- http://wikipehacks.ta2o.net/relwords/pseudo/wprel.cgi
-- 例:Linux
   http://wikipehacks.ta2o.net/relwords/pseudo/wprel.cgi?key=Linux
-- 例:雁
   http://wikipehacks.ta2o.net/relwords/pseudo/wprel.cgi?key=%E9%9B%81

大量アクセスはご勘弁を。
CGIのコードも公開しておくので自分のところでどうぞ。
- http://wikipehacks.ta2o.net/relwords/pseudo/wprel_cgi.txt
(ライセンス=「無償・無保証・著作権放棄」
  http://lifehacks.ta2o.net/byebye-copyright.html

■関連語データ作成スクリプト(Perl):
処理は黒MacBookで15分ほどかかる。
途中でテンポラリファイルに出力しているのはメモリ対策。
#!/usr/bin/perl
# usage: bunzip2 -c jawiki-latest-pages-articles.xml.bz2|prog.pl>wp-rel.txt
use strict;
use warnings;
use utf8;
use Encode;
use open ':utf8';
binmode STDIN, ":utf8";
binmode STDOUT, ":utf8";

my %title_word;
my %df;

my $flag_page_inside = 0;
my $page;
open(F, ">:utf8", "./tmp-removeme.txt") or die "can't open a tmpfile";
while (<>) {
    my $line = $_;
    if ($flag_page_inside == 0 and $line =~ m{<page>}) {
        $flag_page_inside = 1;
    }
    if ($flag_page_inside == 1) {
        $page .= $line;
    }
    if ($flag_page_inside == 1 and $line =~ m{</page>}) {
        my ($title) = $page =~ m{<title>([^<]+)<};
        $title = word_ok($title);
        if ($title ne "" and not defined $title_word{$title}) {
            $title_word{$title} = 1;
            $df{$title}++;
            my %relwords;
            while ($page =~ m{\[\[(.+?)\]\]}g) {
                my $w = word_ok($1);
                next if $w eq "";
                next if $w eq $title;
                next if defined $relwords{$w};
                $relwords{$w}++;
                $df{$w}++;
                print F "$title\t$w\n";
                print F "$w\t$title\n";
            }
        }
        $flag_page_inside = 0;
        $page = "";
    }
}
close F;

sub word_ok {
    my ($w) = @_;
    return "" unless $w;
    return "" if $w =~ m{[:\|\n\t\[\]]};;
    return "" if $w =~ m{^[\#\s]};;
    $w =~ s/\s*\(.+?\)$//;
    return "" if $w =~ /一覧$/;
    return "" if $w =~ /\d+月\d+日$/;
    return "" if $w =~ /^\d{4}年$/;
    return $w;
}

my @list;
my $preword = "";
open(F, "-|:utf8", "sort ./tmp-removeme.txt") or die "can't open a tmpfile";
while (<F>) {
    chomp;
    my @c = split("\t", $_);
    next if (@c != 2);
    if ($preword ne $c[0]) {
        calc_rel($preword, \@list);
        $preword = $c[0];
        @list = ();
    }
    next unless defined $title_word{$c[0]};
    next unless defined $title_word{$c[1]};
    push @list, $c[1];
}
close F;
calc_rel($preword, \@list) if @list > 0;

sub calc_rel {
    my ($title, $lp) = @_;
    return if @$lp == 0;
    my %count;
    foreach my $w (@$lp) {
        $count{$w}++;
    }
    my @rws = map {"$_:$df{$_}"} sort {
        $df{$a}/(($count{$a}-1)*1000000+1)
            <=> $df{$b}/(($count{$b}-1)*1000000+1)
    } keys %count;
    @rws = @rws[0..20] if @rws > 20;
    print "$title\t", join("\t", @rws), "\n";
}
(ライセンス=「無償・無保証・著作権放棄」
  http://lifehacks.ta2o.net/byebye-copyright.html

ちょっといじるだけで共起情報を使う版ができるので、向学心のある人は、
相互情報量[2005-05-27-1]やシンプソン係数[2006-03-08-2]などを計算して、
より正確な関連情報を抽出してみるのも良いだろう。
なお、この手の処理はすぐにメモリが足りなくなるので、
いろいろと工夫が必要だ。健闘を祈る。