人工無脳を作ってみようとするよ3

先人の知恵は高尚で、理解に時間がかかってしまう。なのでMeCabにわかち書きさせる以外は適当な「こうやったら文章っぽくなるんじゃね?」アルゴリズムで開発中。

人工無脳目指すスクリプト」さん、喋りなさい。

以下妄想。
おそらくは元々アカウント名は1000倍だがする行為なよ、待ち合わせに説教とか思ったのでとりあえず今日もねえん言っていたか言及はなく、いくら奥歯を取ろう。
脳味噌のドブには模試の話がいた。
という話がある。
飽きたもんだ!ダダイズムかって言って倒れそうだがなんかlambda(1800+)で、立ってる人でいやがるん。
生きて欲しくてくない。
仏像が、愛してると思いたつように良いんg(露)とも貼り付けたかった。
書けんのやつ。
今日は戦士プリキュアとかどうでもいい。
今貼り付けていたあの顧問教師は要するにめんどくさいだけさ!したり顔でやっつけるしか存在するわけでは進めない。

元データは相変わらずここの日記過去ログ。一見文章に見えますね。言ってることは支離滅裂ですけど。
やってることは単純。
まず記録ステップ。一行一文ずつMeCabに渡し、わかち書きで形態素に分割させる。分割した文章を記録する。
次に辞書作成ステップ。記録されたデータから、形態素の繋がりを示す辞書を作る。文頭にはこの形態素が来た、この形態素の次にはコレが、文末にはアレが、というように。
最後に発言ステップ。形態素の繋がり辞書を元に文頭から文末までの道を探す。経路は繋がった形態素。次の形態素は、元データにおいて前の形態素の次にその形態素が出てきた確率によって選ばれる。

畜生わかりにくい文章だ。以下ヘボスクリプトたち。

まずは記録部分スクリプト

#!/usr/bin/perl
use MeCab;

my $cmd = new MeCab::Tagger("-Owakati ");

open(DIC, ">>bot.dic")||die("file open error ");
while(<STDIN>){
  next if(/^$/);
  my $str = $cmd->parse($_);
  print DIC $str;
}
close(DIC);

どうもこうもないですね。空行を飛ばして、標準入力をMeCab分かち書きさせて、結果をbot.dicに追記させてるだけです。

このスクリプト

こんにちは、おはよう、さようなら。
もう駄目だなあと毎日思いますよ。

というテキストを出力すると、

こんにちは 、 おはよう 、 さようなら 。 
もう 駄目 だ なあ と 毎日 思い ます よ 。 

というテキストをbot.dicに追記します。

辞書作り部分スクリプト

#!/usr/bin/perl

my %wordhash = ();
open(DIC, "bot.dic");
while(<DIC>){
  chomp($_);
  s/\\/\\\\/g;
  s/,/\\camma/g;
  s/=/\\eq/g;
  my @words = (split(" ", $_));
  my $word = "\\bos";
  my $length = @words;
  foreach(@words){
    if(defined($wordhash{$word})){
      $wordhash{$word} .= ",$_";
    }else{
      $wordhash{$word} = "$_";
    }
    $word = $_;
  }
  if(defined($wordhash{$word})){
    $wordhash{$words[$length-1]} .= ",\\eos";
  }else{
    $wordhash{$words[$length-1]} .= "\\eos";
  }
}
close(DIC);

@keys = sort(keys(%wordhash));
open(WORDDIC, ">word.dic");
foreach(@keys){
  printf WORDDIC ("%s=%s\n", $_, $wordhash{$_});
}
close(WORDDIC);

bot.dicの記録から、辞書ハッシュを作成します。ハッシュのキーは形態素で、中身は次に来る形態素csvとします。「,」と「=」は辞書に使うので「\camma」「\eq」でエスケープさせます。「\」自身は「\\」と書きます。文頭を「\bos」、文末を「\eos」と表現しています。
ハッシュを作り終わったら、word.dicに「キー=値」の形式で書き込みます。
絶対いつかエスケープまわりで失敗すると思います。

bot.dic

こんにちは 、 おはよう 、 さようなら 。 
もう 駄目 だ なあ と 毎日 思い ます よ 。 

という内容のテキストがある状態でこのスクリプトを走らせると、

\bos=こんにちは,もう
、=おはよう,さようなら
。=\eos,\eos
おはよう=、
こんにちは=、
さようなら=。
だ=なあ
と=毎日
なあ=と
ます=よ
もう=駄目
よ=。
思い=ます
駄目=だ
毎日=思い

という結果をword.dicに書き込みます。


発言部分スクリプト

#!/usr/bin/perl

open(WORDDIC, "word.dic");
while(<WORDDIC>){
  ($key, $val) = split("=", $_);
  $wordhash{$key} = $val;
}
close(WORDDIC);

$word = "\\bos";

@words = split(",", $wordhash{$word});
$word = $words[rand(@words)];
chomp($word);

while($word ne "\\eos"){
  $word =~ s/\\eq/=/g;
  $word =~ s/\\camma/,/g;
  $word =~ s/\\\\/\\/g;
  print $word;

  @words = split(",", $wordhash{$word});
  $word = $words[rand(@words)];
  chomp($word);
}
print "\n";

辞書ファイルword.dicをハッシュに読み込みます。「\bos」をキーにして、次の形態素をハッシュの中からランダムに選びます。
先のword.dicを元に発言させると、「\bos」から「もう」か「」のどちらかの形態素を選びます。「もう」の後は「\eos」まで一本道です。「こんにちは」を選ぶと「、」の後にも選択肢が。運が良ければ(悪ければ?)、「こんにちは、おはよう、おはよう、……、さようなら。」とか言ってくれます。

汚い図ですが、こういうこと。

3つ目の発言スクリプトだけをループさせて偽非人工無脳はできるかな。会話から学習しないどころか、相手の言う事を全く聞かないけど。組み合せれば相手の言ったことを学習するくらいはできても、相手の言ったことにより違う反応をすることができないなあ。
相手の発言から特徴的な要素を取り出して、文末じゃなくてその要素目指して文章を生成すれば、それらしく見えるだろうか。文末だったらどの道を選んでも必ず辿りつく道が存在するけど、それ以外の要素だったら、まず道を見つける必要があるかな。

追記

あー、これってちょっと前にちらっとだけ見たけど、よくわからなかったんでちゃんと読まなかった
Markov1.pmとほぼ同じ内容の処理だな。たぶん。信州大学の確率論の講義資料とかを見ても、どうもそれっぽいかな。一応この確率論の式やら眺めてて、頑張れば理解できるかもしれないあたり、大学来て良かったなあ。頑張らないとわからないあたりが駄目大学生で素敵ですが。
マルコフ連鎖ってのは、はてなキーワード:マルコフ連鎖で端的に述べられてるが「ある変数を順次、発生させるときに、現世代のパラメタの値(のセット)のみをもとに次世代のパラメタの値を発生させる方法」といったところか。正確には「任意の事象のみをもとにその次世代の事象の確率を求められる事象の集合」ということになるんだろうか。
いやあしかしアルゴリズム的にはMarkov1.pmと似てても、書いてるプログラムの内容はナマコとバクテリアだね。pmとかカッコイイ! 俺なんてPerlのサブルーチンの書き方すらよくわからない!

書いてる時は熱中してたが、この日記長え。「続きを読む」を設定しておく。

test