今日のIIR輪講[2008-09-07-2]の内容のフォローも兼ねて、ちょっとしたハックを紹介。
bigram language model に基づく、ランダム文生成を行います。
って、まあ、単純にある単語の次に現れる単語の分布を用いて、文章を生成していくだけですが。
以下、サンプルプログラムと実行例です。
rss-lm.pl
日本語形態素解析に Yahoo!API を使っています。
- テキスト解析:日本語形態素解析API - Yahoo!デベロッパーネットワーク
http://developer.yahoo.co.jp/webapi/jlp/ma/v1/parse.html
$appid は自分で取得したものを使ってくださいね。
(http://e.developer.yahoo.co.jp/webservices/register_application)
追記140605: APIのURLが古いままだったので変更。
- 旧:api.jlp.yahoo.co.jp
- 新:jlp.yahooapis.jp
またプログラムも時代に合わせて(?)一部変更。
RSS の URL を引数に与えて実行します。
実行結果はカオスです!
http://chalow.net/
あと、確かにオフィシャルなスイカ(たぶん国産西瓜のことかと)はおいしいです。
http://d.hatena.ne.jp/naoya/
あまり使ってないんだけどな、最近は。
あと、「何か適当に関する手法」を募集しているようです。
しかも第2回。一発ネタでは終わらないのですね。
RSS(日本語)を読み込んで、テキストを形態素解析し、単語2連続(bigram)をカウントしています(ハッシュ %next_words に格納)。
単語 x の後に y が現れる確率は P(y|x) です。
生成時は、確率 P(y|x) に準じてランダムに y を選びます。
その方法は、
(1) x の次に現れる単語( ...)を重複をゆるすリストに格納する。
という単純なものです。
説明するまでもないと思いますが、こうすることで「は」「も」「の」「から」は、それぞれ P(は|今日)、P(も|今日)、P(の|今日)、P(から|今日)、に準じた確率でランダムに選ばれます。
単語が多い対象では実行性能が悪くなりますが、RSS のテキストくらいの量なら問題ないでしょう。
ランダムで選ばれた単語を出力し、その単語の次に現れる単語をまたランダムで選ぶ、ということをループさせることにより文章を生成していきます。
なお、空文字の単語は「文頭または文末」を意味しています。
ループの最初は空文字からスタートさせます。
JavaScript 版と PHP 版。生成のロジックは同じです。
- マルコフ連鎖で文章生成(JavaScript) - エブログ
http://ablog.seesaa.net/article/20987336.html
- Yahoo!のAPIを利用してマルコフ連鎖で文章生成(php)
http://shohoji.net/blog/archives/001723.html
trigram (3gram) によるモデル。
- mizzy.org : perlで人工無脳 #1
http://blog.mizzy.org/articles/2005/06/19/bot01
確率文章生成を含む、いろんな人工無脳について。
- 人工無脳レビュー
http://www.ycf.nanet.co.jp/~skato/muno/material/review.html
いくつかの RSS でやってみたサンプル集。
- いろんなブログのRSSで文章生成してみた (ヲハニュース)
http://d.hatena.ne.jp/yto/20080906/p5
bigram language model に基づく、ランダム文生成を行います。
って、まあ、単純にある単語の次に現れる単語の分布を用いて、文章を生成していくだけですが。
以下、サンプルプログラムと実行例です。
サンプルコード
rss-lm.pl
#!/usr/bin/perl use strict; use warnings; use XML::RSS; use LWP::Simple; use XML::Simple; use URI::Escape; use utf8; binmode STDOUT, ":utf8"; my $appid = "YahooDemo"; my $rss_url = shift; my $rss_cont = get($rss_url) || ""; my $rss = XML::RSS->new; $rss->parse($rss_cont); my %next_words; my $pre = ""; foreach my $i (@{$rss->{items}}) { my $ma_ref = webma($i->{title}."\n".$i->{description}); foreach my $mo (@{$ma_ref->{ma_result}->{word_list}->{word}}) { my $w = $mo->{surface}; $w = "" if ref($w) eq "HASH"; next if ($pre eq "" and $w eq ""); push @{$next_words{$pre}}, $w; $pre = $w; } } my @words; my $cur = ""; for (my $i = 0; $i < 200; $i++) { my $tmp = $next_words{$cur}; $cur = $tmp->[rand(@$tmp)]; last if $cur eq "" and $i > 100; push @words, $cur; } print join("", @words), "\n"; sub webma { my ($key) = @_; my $url = "http://jlp.yahooapis.jp/MAService/V1/parse" ."?appid=$appid&results=ma&response=surface" ."&sentence=".URI::Escape::uri_escape_utf8($key); return {} if length($url) > 10000; my $response = get($url); my $xmlsimple = XML::Simple->new(ForceArray => [ 'word' ]); return $xmlsimple->XMLin($response); }
日本語形態素解析に Yahoo!API を使っています。
- テキスト解析:日本語形態素解析API - Yahoo!デベロッパーネットワーク
http://developer.yahoo.co.jp/webapi/jlp/ma/v1/parse.html
$appid は自分で取得したものを使ってくださいね。
(http://e.developer.yahoo.co.jp/webservices/register_application)
追記140605: APIのURLが古いままだったので変更。
- 旧:api.jlp.yahoo.co.jp
- 新:jlp.yahooapis.jp
またプログラムも時代に合わせて(?)一部変更。
実行例
RSS の URL を引数に与えて実行します。
実行結果はカオスです!
http://chalow.net/
./rss-lm.pl http://chalow.net/cl.rdf
【初めての持ちが、ハーゲンダッツの会)ブログで焼いて、その他のひみつ][2008北海道へ行かなくて。場所は、彼のエコアート。ローマ人のスーパーでは一個29,400円は、-04-03-08-基本的な味で売っていた!描画がFX35-KChromeLUMIXでも、デニムの大和路[2008特にhttp://wassr...blog.com/2008受賞作品展」というかとか西麻布でオフィシャルにスイカを置いておいしいです。「北海道へ行かなくて。場所は、彼のエコアート。」ってのは、ポエムな感じで素敵です。
あと、確かにオフィシャルなスイカ(たぶん国産西瓜のことかと)はおいしいです。
http://d.hatena.ne.jp/naoya/
./rss-lm.pl http://d.hatena.ne.jp/naoya/rss
SKK分だけ、はてなハイクの発表を受けはてなハイクのインターンもbyteArray::Gapでした。金曜日はアルゴリズムの頃、はてなハイクのたつをさんから、あの変換スタイルにやろうと言えばThriftcodesKansai.net/~naoya1977/about-thrift/naoya/naoya1977/インフラを終えて発表資料を試みました。という課題が終わり、計算機科学にアップロードしましたことから何か適当に関する手法第2回募集ついに「はてなハイクのたつをさん」になってしまいました!
あまり使ってないんだけどな、最近は。
あと、「何か適当に関する手法」を募集しているようです。
しかも第2回。一発ネタでは終わらないのですね。
簡単な解説
RSS(日本語)を読み込んで、テキストを形態素解析し、単語2連続(bigram)をカウントしています(ハッシュ %next_words に格納)。
単語 x の後に y が現れる確率は P(y|x) です。
生成時は、確率 P(y|x) に準じてランダムに y を選びます。
その方法は、
(1) x の次に現れる単語( ...)を重複をゆるすリストに格納する。
例:「今日」→「は」「も」「の」「の」「は」「から」「は」「の」(2) そのリストから一つランダムで選ぶ。
(x = 「今日」)
という単純なものです。
説明するまでもないと思いますが、こうすることで「は」「も」「の」「から」は、それぞれ P(は|今日)、P(も|今日)、P(の|今日)、P(から|今日)、に準じた確率でランダムに選ばれます。
単語が多い対象では実行性能が悪くなりますが、RSS のテキストくらいの量なら問題ないでしょう。
ランダムで選ばれた単語を出力し、その単語の次に現れる単語をまたランダムで選ぶ、ということをループさせることにより文章を生成していきます。
なお、空文字の単語は「文頭または文末」を意味しています。
ループの最初は空文字からスタートさせます。
関連リンク
JavaScript 版と PHP 版。生成のロジックは同じです。
- マルコフ連鎖で文章生成(JavaScript) - エブログ
http://ablog.seesaa.net/article/20987336.html
- Yahoo!のAPIを利用してマルコフ連鎖で文章生成(php)
http://shohoji.net/blog/archives/001723.html
trigram (3gram) によるモデル。
- mizzy.org : perlで人工無脳 #1
http://blog.mizzy.org/articles/2005/06/19/bot01
確率文章生成を含む、いろんな人工無脳について。
- 人工無脳レビュー
http://www.ycf.nanet.co.jp/~skato/muno/material/review.html
いくつかの RSS でやってみたサンプル集。
- いろんなブログのRSSで文章生成してみた (ヲハニュース)
http://d.hatena.ne.jp/yto/20080906/p5
この記事に言及しているこのブログ内の記事
- マルコフ連鎖と形態素解析でランダムな文章を生成する (2023-06-08)
- 【ヲハニュース 2022年1月18日号】国会図書館サイトで絶版本ネット閲覧可能に、バレンタインデーが世界一流ショコラティエが集まるチョコのコミケに、など (2022-01-18)
- 青空文庫のテキストデータの一括ダウンロード方法 (2018-07-25)
- 指定した確率分布に従った乱数発生を効率的に行う「別名法 (alias method)」を Perl で実装してみた (2014-04-16)
- Google 翻訳の英日翻訳の品質について (2008-09-17)
- 「Introduction to Information Retrieval」輪講第13回 (2008-09-07)