文章から単語と単語の相関度を学習するミニプログラム
ふと思いついたので、短時間で作ったプログラム。
以前ならperlでやるところですが、Cで。
あらかじめ覚えている単語辞書を使って、文章中に単語があるか調べ、
単語があれば、登場する単語と単語に相関度を設定して、相関辞書として学習する。
その結果、?「単語」と問いあわせると、逆に相関度のある単語を表示する
C:\shogidev>bcc32 st.cpp
Borland C++ 5.5.1 for Win32 Copyright (c) 1993, 2000 Borland
st.cpp:
Turbo Incremental Link 5.00 Copyright (c) 1997, 2000 BorlandC:\shogidev>st
>word
? 朝 会社 仕事 夕食 昼食 給料 少女 時間 ロボット カメラ 映画 本 犬 時計 時間 パ
ソコン メイド mp3 cpu 秋葉 アニメ 東京 大阪 ハンバーグ
>朝メイドがハンバーグを焼いた
>犬が朝吼えた
>ロボットがカメラを秋葉で使った
>メイドロボット萌え
>会社で少女が本を読んでいた
>dic
朝-メイド(1) 朝-ハンバーグ(2) メイド-ハンバーグ(1) 朝-犬(1) ロボット-カメラ(1)
ロボット-秋葉(2) カメラ-秋葉(1) ロボット-メイド(1) 会社-少女(1) 会社-本(2) 少女-
本(1)
>?朝
朝 メイド(1) ハンバーグ(2) 犬(1)
>exit
C:\shogidev>
wordとやると単語辞書の中身が出ます。
まず例文、「朝メイドがハンバーグを焼いた」を入力します。
中身的には、単語辞書を見て、「朝」「メイド」「ハンバーグ」が抽出され、
それぞれの単語に相関度が設定されます。数値は小さいほど良く、
朝-メイドは1。朝とハンバーグは2になります。(距離に応じて変わる)
?朝
と問い合わせると、朝に関連する「メイド」「ハンバーグ」「犬」が表示されます。
数字は、元の例文での距離です。
単語を大量に用意(もしくは自動抽出して学習)して、例文を大量に学習すると、
さまざまな単語間で相関度が学習される。
あとは、相関度の値を利用して、真に相関のあるものを判定してやったりできるはず。
簡単なプログラムですが、けっこう面白いことができそうです。
ニュースサイトの相関ニュース一覧なんてのは似たような方法をやってるはず。
プログラムは以下です。グローバル変数を利用するCらしくないプログラムですが、
短時間で書くなら、このほうが簡単です。
#include <stdio.h> #include <stdlib.h> #include <string.h> //既知の単語リスト char word[1000][100] = { "?", "朝","会社","仕事","夕食","昼食","給料","少女","時間", "ロボット","カメラ","映画","本","犬","時計","時間", "パソコン","メイド","mp3","cpu","秋葉","アニメ","東京","大阪","ハンバーグ", "" }; //単語と単語の相関リスト class Soukan { public: int a; int b; int v; }; Soukan sdic[1000]; int sp=0; //文章から抽出した単語のリスト int list[10]; int lp=0; //文章から既知の単語の番号リストを抽出する void scan( char*s ) { char* p; for(int i=0; i<10; i++) list[i]=0; lp=0; for(int i=0; ; i++) { if( *word[i] == 0 ) break; if(lp>=10) break; if( (p=strstr(s,word[ i ] )) != 0 ) { for(unsigned int j=0; j<strlen(word[i]);j++) p[j]=' '; list[lp++]=i; } } } //単語aと単語bを相関度vに設定する void kankei(int a,int b,int v) { sdic[sp].a=a; sdic[sp].b=b; sdic[sp].v=v; sp++; } //相関辞書を表示 void dispdic() { for(int i=0;i<sp;i++) printf("%s-%s(%d) ",word[sdic[i].a],word[sdic[i].b],sdic[i].v); printf("\n"); } //単語辞書を表示 void dispword() { for(int i=0;*word[i]!=0;i++) printf("%s ",word[i]); printf("\n"); } //リストの先頭が「?」ならば質問 void query() { for(int i=1;i<lp;i++) { printf("%s ",word[ list[i] ]); for(int j=0;j<sp;j++) { if(sdic[j].a == list[i] ) printf("%s(%d) ", word[ sdic[j].b], sdic[j].v ); else if(sdic[j].b == list[i] ) printf("%s(%d) ", word[ sdic[j].a], sdic[j].v ); } } printf("\n"); } //リスト同士に相関度を設定する void study() { for(int i=0;i<lp;i++) for(int j=i+1;j<lp;j++) { int a=list[i]; int b=list[j]; int v=abs(i-j); //単語aと単語bを相関度vに設定する kankei( a,b,v); } } void main() { char s[200]; for(;;) { //文章を取得する printf(">");gets(s); //システムコマンド if(strcmp(s,"dic")==0) { dispdic();continue; } else if(strcmp(s,"word")==0) { dispword();continue; } else if(strcmp(s,"exit")==0) { break; } //文章から既知の単語の番号リストを抽出する scan( s ); //リストの先頭が「?」ならば質問 if( list[0]==0) { query(); } //リスト同士に相関度を設定する else study(); } }