文章から単語と単語の相関度を学習するミニプログラム

ふと思いついたので、短時間で作ったプログラム。
以前なら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 Borland

C:\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();

	}
}