/* -------------------------------------------------------------------------- plant.cpp : プログラム名 このソフトウェアは、判別ツリーの学習ソフトウェアである。 下記サイトに掲載している情報処理学会研究報告 2005-DPS-121 「植物生体電位信号を用いたユビキタス多機能センサシステム」 で使用している判別ツリーを実行するプログラムです。 http://www.patentisland.com/PLANT.pdf 本ソフトウェアは、下記の条件で使用可能です。   1. 下記メールアドレスにあらかじめ連絡をいただければ、本ソフトウェアの、大学などの教育研究機関における研究目的での使用および 改変は無償で行なうことができます。 2. 前記1以外での本ソフトウェアの使用については、下記メールアドレスでお問い合わせください。 3. 本ソフトウェアを使用するソフトウェア、本ソフトウェアから派生するソフトウェアには、次のURLを出典として掲載すること が必要です。 http://www.patentisland.com/plant.txt http://www.patentisland.com/plantconst.h 2006年1月28日 ソフトウェア使用条件の追加 2004年10月12日 久野敦司( patentisland@hotmail.com ) http://www.patentisland.com/ (C) Copyright 2004 久野敦司( E-mail: patentisland@hotmail.com )All rights reserved -------------------------------------------------------------------------- */ #include #include #include "plantconst.h" #include #include /* ------------------------------------------------------------------- グローバル変数領域 ------------------------------------------------------------------- */ double sample[PLNT_SAMP_MAX]; // 電圧サンプルの配列 short ph[PLNT_NLEVEL][PLNT_NRUN],mh[PLNT_NLEVEL][PLNT_NRUN]; // hisano展開のためのランレングス符号化データ設定エリア double vector[PLNT_NCASE][PLNT_NF]; // 学習用のケースデータにおける特徴ベクトル int categcode[PLNT_NCASE][PLNT_CATEG]; // 学習用ケースデータにおけるカテゴリーデータ // 判別木のデータ int dtree_fno[PLNT_DTREENODE]; //判別木用のノードの特徴量番号 double dtree_th[PLNT_DTREENODE]; //判別木用のノードの、判別用しきい値 int dtree_categn[PLNT_DTREENODE];//判別木用のノードのカテゴリー番号(この値がマイナスの時は非終端ノード) int dtree_plusnode[PLNT_DTREENODE];//判別木用のノードの、プラス側分岐先ノード番号 int dtree_minusnode[PLNT_DTREENODE];//判別木用のノードの、マイナス側分岐先ノード番号 int dtree_parentnode[PLNT_DTREENODE];// 親ノード番号 int dtree_houkou[PLNT_DTREENODE]; // そのノードの親ノードからみた分岐方向(プラス方向なら1、マイナス方向なら−1) int dtree_used = -1; // 使用済みノードの個数(0番から使用開始。) /* -------------------------------------- vector[i][j]: 第iケースにおける特徴量jの値 -------------------------------------- */ int dtreegen_count = 0; // dtreegen関数の呼び出しカウンタ /* ----------------------------------------------------------------- 関数名: filewr 機能:  サンプルデータファイル"plantsignal.txt"に、      配列 double sample[PLNT_SAMP_MAX]などを書き込む関数          入力:  char *s1; 第1説明文字列へのポインタ char *s2; 第2説明文字列へのポインタ int categA; カテゴリー数値A      long count; サンプル数      double sample[]; 計測電圧サンプル値    起動: filewr(s1,s2,categA,count,sample); 更新履歴: 2004年10月20日 久野敦司( patentisland@hotmail.com ) (C) Copyright 2004 久野敦司(E-mail: patentisland@hotmail.com )All rights reserved ----------------------------------------------------------------- */ int filewr(char *s1,char *s2,int categA,long count,double *sample) { long k1; FILE *stream; char buffer[PLNT_BUFF]; if((stream = fopen("plantsignal.txt", "w" )) == NULL ) {printf("The file was not opened\n");} else {printf("The file was opened\n");} fprintf(stream,"%s\n",s1); fprintf(stream,"%s\n",s2); fprintf(stream,"%d\n",categA); fprintf(stream,"%ld\n\n\n",count); for (k1 = 0; k1 < count; k1++) { fprintf(stream,"%lf\n",sample[k1]); } fclose(stream); return (0); } /* ----------------------------------------------------------------- 関数名: filerd 機能:  サンプルデータファイル"plantsignal.txt"を読み取り、      配列 double sample[PLNT_SAMP_MAX]などに設定する関数          出力:  char *s1; 第1説明文字列へのポインタ char *s2; 第2説明文字列へのポインタ int categA; カテゴリー数値A      long count; サンプル数      double sample[]; 計測電圧サンプル値    起動: filerd(s1,s2,categA,count,sample); 更新履歴: 2004年10月20日 久野敦司( patentisland@hotmail.com ) (C) Copyright 2004 久野敦司(E-mail: patentisland@hotmail.com )All rights reserved ----------------------------------------------------------------- */ int filerd(char *s1,char *s2,int &categA,long &count,double *sample) { long k1; FILE *stream; char buffer[PLNT_BUFF]; double work; int d1;long d2; if((stream = fopen("plantsignal.txt","r" )) == NULL ) {printf("??filerd:The file was not opened\n");} else {printf("??filerd:The file was opened\n");} fscanf(stream,"%s",s1); fscanf(stream,"%s",s2); fscanf(stream,"%d",&d1); categA = d1; fscanf(stream,"%ld",&d2); count = d2; for (k1 = 0; k1 < count; k1++) { fscanf(stream,"%lf",&work); sample[k1]=work; } fclose(stream); return (0); } /* -------------------------------------------------------------------- 関数名: hisano 機能: サンプルデータ double sample[PLNT_SAMP_MAX]をHisano展開する 入力: long count; サンプル数     double sample[PLNT_SAMP_MAX]; 入力波形のデータ 出力: グローバル変数 レベルkのランレングス符号: ph[k][j] = 正の値 : 第j番の連続区間が、pbinary(k,i)が値1を有する区間である場合の、区間長さ      負の値 : 第j番の連続区間が、pbinary(k,i)が値0を有する区間である場合の、区間長さ 0 : データ区間終了の符号 mh[k][j] = 正の値 : 第j番の連続区間が、mbinary(k,i)が値1を有する区間である場合の、区間長さ      負の値 : 第j番の連続区間が、mbinary(k,i)が値0を有する区間である場合の、区間長さ 0 : データ区間終了の符号 起動: hisano(count,sample); 波形のHisano展開の説明 展開対象として入力される波形データを、s(i)とする。 ここで、しきい値TH*kによりs(i)を2値化して得た2値データを次式で示す。 pbinary(k,i) = 0 : s(i) < TH*k 1 : s(i) >= TH*k mbinary(k,i) = 0 : s(i) > -TH*k 1 : s(i) <= -TH*k そうすると、波形データs(i)のHisano展開は、次式で表現できる。 N s(i) = (pbinary(k,i) - mbinary(k,i)) k=1 このように、pbinary, mbinaryには元の波形データsを復元できる能力があるので、pbinary,mbinary をランレングスコーディングして得た特徴量は、元の波形データを表現するものとなる。 pbinary(k,i)のランレングスコーディングデータは、ph[k][j]との配列に入れる。 mbinary(k,i)のランレングスコーディングデータは、mh[k][j]との配列に入れる。 レベルkのランレングス符号: ph[k][j] = 正の値 : 第j番の連続区間が、pbinary(k,i)が値1を有する区間である場合の、区間長さ      負の値 : 第j番の連続区間が、pbinary(k,i)が値0を有する区間である場合の、区間長さ 0 : データ区間終了の符号 mh[k][j] = 正の値 : 第j番の連続区間が、mbinary(k,i)が値1を有する区間である場合の、区間長さ      負の値 : 第j番の連続区間が、mbinary(k,i)が値0を有する区間である場合の、区間長さ 0 : データ区間終了の符号 更新履歴: 2004年10月20日 久野敦司( patentisland@hotmail.com ) (C) Copyright 2004 久野敦司(E-mail: patentisland@hotmail.com )All rights reserved --------------------------------------------------------------------- */ int hisano(long count,double *sample) {// (1) #define hisano_Debug1 0 int k1,k2; int length; int flag,nrun; short binary[PLNT_SAMP_MAX]; // Hisano展開のための作業用配列 double threshold; for (k2 = 1; k2 < PLNT_NLEVEL;k2++) { //(2) threshold = k2 * PLNT_KIZAMI; // ランレングス符号化エリアの着目レベルの先頭セルに終端符号を入れて、初期化する。 ph[k2][0] = 0; mh[k2][0] = 0; // 着目レベルでの2値化と、ランレングス符号化 for (k1 = 0; k1 < count;k1++) { // (3) if (sample[k1] >= threshold) { binary[k1] = 1;} else { binary[k1] = 0;} }// (3) #if hisano_Debug1 == 1 printf("??hisano level = %d",k2); for (k1 = 0; k1 < count; k1++) { if (binary[k1] == 1) {printf("\n??hisano: □□□□□□□□□□□□");} else {printf("\n??hisano: ●●●");} } #endif // ランレングス符号化によって、配列 phを生成 length = 0; flag = binary[0]; nrun = 0; for (k1 = 0;k1 < count;k1++) {//(4) if (flag == binary[k1]) {length++;} else { if (flag == 1) { ph[k2][nrun] = length;} else {ph[k2][nrun] = (-1)*length;} nrun++; flag = binary[k1]; length = 1; // 着目符号の変更と長さの初期値の設定 } }//(4) ph[k2][nrun+1] = 0; // ランレングス符号化の終端記号の設定 threshold = -1.0 * threshold; for (k1 = 0; k1 < count;k1++) {//(5) if (sample[k1] <= threshold) { binary[k1] = 1;} else { binary[k1] = 0;} }//(5) // ランレングス符号化によって、配列 mを生成 length = 0; flag = binary[0]; nrun = 0; for (k1 = 0;k1 < count;k1++) {//(6) if (flag == binary[k1]) {length++;} else { if (flag == 1) { mh[k2][nrun] = length;} else {mh[k2][nrun] = (-1)*length;} nrun++; flag = binary[k1]; length = 1; // 着目符号の変更と長さの初期値の設定 } }//(6) mh[k2][nrun+1] = 0; // ランレングス符号化の終端記号の設定 }//(2) return (0); } /* -------------------------------------------------------------------- 関数名: hisanodisp 機能: 下記のグローバル変数の内容を表示する レベルkのランレングス符号: ph[k][j] = 正の値 : 第j番の連続区間が、pbinary(k,i)が値1を有する区間である場合の、区間長さ      負の値 : 第j番の連続区間が、pbinary(k,i)が値0を有する区間である場合の、区間長さ 0 : データ区間終了の符号 mh[k][j] = 正の値 : 第j番の連続区間が、mbinary(k,i)が値1を有する区間である場合の、区間長さ      負の値 : 第j番の連続区間が、mbinary(k,i)が値0を有する区間である場合の、区間長さ 0 : データ区間終了の符号 起動: hisanodisp(); 更新履歴: 2004年10月20日 久野敦司( patentisland@hotmail.com ) (C) Copyright 2004 久野敦司(E-mail: patentisland@hotmail.com )All rights reserved --------------------------------------------------------------------- */ int hisanodisp() { int k1,k2; for (k1 = 1;k1 < PLNT_NLEVEL;k1++) { printf("\n--------------------------------------------"); printf("\n プラス側レベル(%d)のランレングスの表示\n",k1); k2 = 0; while (ph[k1][k2] != 0) { printf("【%d】 ",ph[k1][k2]); k2++; } } return(0); } /* ----------------------------------------------------------------- 関数名: vectfilerd 機能:  ベクトルデータファイル"vector.txt"を読み取り、      配列 double vector[PLNT_NCASE][PLNT_NF]にベクトルデータを設定し、      カテゴリー配列 int categcode[PLNT_NCASE][PLNT_CATEG]にベクトルデータ      が示すカテゴリー値を設定する。さらに、有効なケース数、有効な特徴量数、      有効なカテゴリー切り口数を出力する。      ファイルのデータフォーマットは、次のとおりとする。      有効なケース数 int ncase;      有効な特徴量数 int nfeature; 有効なカテゴリー切り口数 int ncateg; i vector[i][0] vector[i][1] ---- vector[i][nfearture-1] categcode[i][0] -- categcode[i][ncateg-1] j vector[j][0] vector[j][1] ---- vector[j][nfearture-1] categcode[j][0] -- categcode[j][ncateg-1] 出力: int ncase, nfeature,ncateg; double vector[][]; int categcode[][]; 起動: int vectfilerd(ncase,nfeature,ncateg,ptr_ptr_vector,categcode); 注意: 2次元配列については、各行の先頭ポインタを格納した配列を用意し、そのポインタ配列へのポインタと、     行数と列数を引数として渡すようにして、関数内で関数を呼び出した側で定義した配列を操作できるようにした。 更新履歴: 2004年10月14日 久野敦司( patentisland@hotmail.com ) (C) Copyright 2004 久野敦司(E-mail: patentisland@hotmail.com )All rights reserved ----------------------------------------------------------------- */ /* ---------------------------- 関数定義 ---------------------------- */ int vectfilerd(int &ncase,int &nfeature,int &ncateg,double **vector,int **categcode) { #define Debug_vectfilerd1 0 // デバッグスイッチ #define Debug_vectfilerd2 0 // デバッグスイッチ long k1,k2; FILE *stream; char buffer[PLNT_BUFF],s1[PLNT_BUFF],s2[PLNT_BUFF]; int work; double r = 12345.0; // 作業用レジスタ int ir; // 作業用レジスタ if((stream = fopen("vector.txt", "r" )) == NULL ) {printf("??vectfilered: The file was not opened\n");} else {printf("??vectfilerd: The file was opened\n");} fscanf(stream,"%d",&ncase); fscanf(stream,"%d",&nfeature); fscanf(stream,"%d",&ncateg); #if Debug_vectfilerd1 == 1 printf("\n ??vectfilerd ncase = %d, nfeature = %d, ncateg = %d",ncase,nfeature,ncateg); #endif for (k1 = 0; k1 < ncase;k1++) { for (k2 = 0;k2 < nfeature;k2++) { fscanf(stream,"%lf",&r); vector[k1][k2] = r;} for (k2 = 0;k2 < ncateg;k2++) { fscanf(stream,"%d",&ir); categcode[k1][k2] = ir; } } fclose(stream); return 0; } /* ------------------------------------------------------------------- 関数名: segprofile 機能:  ある1つの種類の特徴量に関するサンプル値と、各サンプルごとの      カテゴリー符号の対応分布を分析して、その分布を最適に2分する      ためのしきい値と、そのしきい値で2分した場合の分離評価値を      算出する。カテゴリーの種類数は、2以上とする。 入力: int nsamp; サンプル数である。サンプル配列の0からnsamp-1までが有効なデータである           ことを意味する。 double step; 特徴量に関して最適しきい値を探索するためのステップ幅である。 double a[]; サンプルデータの1次元配列である。     int c[]; カテゴリー符号の1次元配列である。サンプルデータに対応するカテゴリー符号がはいっている。 出力: double th; 特徴量分布をカテゴリーによって最適に2分する最適しきい値である。 double v; 最適しきい値vで2分することで得られる総合評価値である。 int categorycode; 入力の有するカテゴリー種類数が1の場合の、そのカテゴリー符号 本関数の戻り値; int型の カテゴリー分離が完了したかどうかを示すフラグである。 0 : カテゴリー分離が完了した。すなわち、しきい値をはさんで両側はそれぞれ異なる唯一の           カテゴリーのサンプルだけになった。 1 : しきい値と同じか大きい値のサンプル分布側に複数個のカテゴリーのものを含む。小さい側のカテゴリは1個 2 : しきい値よりも小さい値のサンプル分布側に複数個のカテゴリーのものを含む。大きい側のカテゴリは1個 3 : しきい値よりも大きい値の側も小さい値の側も複数個のカテゴリーのものを含む。         4 : 入力された分布は、1つのカテゴリーのみから構成される。 -1 : 異常終了(分離不能) 起動: stat = segprofile(nsamp,step,a,c,th,v,categorycode);            更新履歴: 2004年10月18日 久野敦司( patentisland@hotmail.com ) (C) Copyright 2004 久野敦司(E-mail: patentisland@hotmail.com )All rights reserved ------------------------------------------------------------------- */ int segprofile(int nsamp,double step,double *a,int *c,double &th,double &v,int &categorycode) { #define Debug_segprofile1 0 #define Debug_segprofile2 0 int k1,k2,k3,flag,nncateg; double r1,r2; double mina,maxa; // その特徴量に関する分布の範囲の最小値と最大値 int result; int categcodep[PLNT_CATEGNMAX]; // カテゴリー符号設定エリア。第iカテゴリーのカテゴリー符号を設定する。 double categbunpu[3][PLNT_CATEGNMAX]; // 各カテゴリーごとの分布を示すデータ th = v = 0.0; // 初期化 /* --------------------------------------------------------- categbunpu[0][i]: 第iカテゴリーの特徴量の平均値 categbunpu[1][i]: 第iカテゴリーの特徴量の最小値 categbunpu[2][i]: 第iカテゴリーの特徴量の最大値 --------------------------------------------------------- */ // カテゴリー符号設定エリアへのカテゴリー符号の設定 for (k1 = 0;k1 < PLNT_CATEGNMAX; k1++) // 符号未設定状態に初期化 {categcodep[k1] = -1;} for (k1 = 0; k1 < nsamp; k1++) { for (k2 = 0; k2 < PLNT_CATEGNMAX; k2++) { if (categcodep[k2] == -1) // categcodep[k2]が未登録エリアとして、空いているか? { flag = 0; for (k3 = k2; k3 >= 0;k3--) { if (categcodep[k3] == c[k1]) { flag = 1; break;} // c[k1]のカテゴリー符号はcategcodep[]に登録済み } if (flag == 0) { categcodep[k2] = c[k1];} // c[k1]のカテゴリー符号が未登録なら登録する } } } // カテゴリー種類数のチェック nncateg = 0; for (k1 = 0; k1 < PLNT_CATEGNMAX;k1++) { if (categcodep[k1] != -1) { nncateg++;} } if (nncateg == 1) // カテゴリーが1個しかない場合 { result = 4; #if Debug_segprofile1 == 1 printf("\n ??segprofile : nsamp = %d, step = %lf",nsamp,step); for (k1 = 0;k1 < nsamp;k1++) { printf("\n ??segprofile : a[%d] = %lf , c[%d] = %d",k1,a[k1],k1,c[k1]); } printf("\n ??segprofile : th = %lf",th); printf("\n ??segprofile : v = %lf",v); printf("\n ??segprofile : result = %d",result); #endif categorycode = categcodep[0];return(result); } #if Debug_segprofile1 == 1 printf("\n ??segprofile: カテゴリー種類数=%d",nncateg); #endif // 分布の最大値と最小値の取得 mina = PLNT_MAXVAL; maxa = PLNT_MINVAL; for (k1 = 0;k1 < nsamp;k1++) { if (a[k1] > maxa) {maxa = a[k1];} if (a[k1] < mina) {mina = a[k1];} } if ((maxa - mina) <= step) {// 探索ステップが不適切な場合 result = -1; #if Debug_segprofile1 == 1 printf("\n ??segprofile : nsamp = %d, step = %lf",nsamp,step); for (k1 = 0;k1 < nsamp;k1++) { printf("\n ??segprofile : a[%d] = %lf , c[%d] = %d",k1,a[k1],k1,c[k1]); } printf("\n ??segprofile : th = %lf",th); printf("\n ??segprofile : v = %lf",v); printf("\n ??segprofile : result = %d",result); #endif return(result);} // カテゴリーごとの分布の平均値、最小値、最大値を求める。 for (k1 = 0;k1 < nncateg;k1++) { categbunpu[0][k1] = 0.0; // 平均値を求めるための初期化 categbunpu[1][k1] = maxa; // 最小値を求めるための初期化 categbunpu[2][k1] = mina; // 最大値を求めるための初期化 k3 = 0; // categcodep[k1]と同じカテゴリー符号を持つサンプル数の初期化 for (k2 = 0;k2 < nsamp;k2++) { if (c[k2] == categcodep[k1]) { k3++; categbunpu[0][k1] = categbunpu[0][k1] + a[k2]; if (categbunpu[1][k1] > a[k2]) {categbunpu[1][k1] = a[k2];} if (categbunpu[2][k1] < a[k2]) {categbunpu[2][k1] = a[k2];} } } if (k3 == 0) {printf("\n ??segprofile: カテゴリーごとのサンプル数カウントエラー");} else { categbunpu[0][k1] = categbunpu[0][k1]/k3;} } #if Debug_segprofile2 == 1 printf("\n 分布の最小値 = %lf",mina); printf("\n 分布の最大値 = %lf",maxa); for (k1 = 0; k1 < nncateg;k1++) { printf("\n カテゴリー%d の平均値 = %lf",k1,categbunpu[0][k1]); // 平均値 printf("\n カテゴリー%d の最小値 = %lf",k1,categbunpu[1][k1]); // 最小値 printf("\n カテゴリー%d の最大値 = %lf",k1,categbunpu[2][k1]); // 最大値 } #endif // 分離の位置と総合評価値の初期値を設定する。 double th1; // 暫定の最適分離位置 double th2; // 分離位置探索用変数 double v1; // 総合評価値変数 double v2; // 総合評価値の探索用変数 double v3; // ワーク用変数 int pcount; // 分離位置よりもプラス側にあるカテゴリーの数のカウンタ int mcount; // 分離位置よりもマイナス側にあるカテゴリーの数のカウンタ th1 = mina; v1 = (maxa - mina)*nncateg*(-1.0); // 総合評価値として、最悪値を初期値として設定した #if Debug_segprofile2 ==1 printf("\n ??segprofile(1) : v1 = %lf",v1); #endif for (th2 = mina+step; th2 < maxa; th2=th2+step) { v2 = 0; // 各カテゴリーの中心点(平均値),最大値点,最小値点の分離位置からの遠さを評価値に加算 for (k1 = 0;k1 < nncateg;k1++) { v2 = v2 + abs(th2 - categbunpu[0][k1])+abs(th2-categbunpu[1][k1])+abs(th2-categbunpu[2][k1]); } // 各カテゴリーの中心点を中心に平均値点、最大値点、最小値点が正側/負側にできるだけ対称に分布しているいることの評価 v3 = 0.0; for (k1 = 0;k1 < nncateg;k1++) { v3 = v3 + (th2 - categbunpu[0][k1])+(th2-categbunpu[1][k1])+(th2-categbunpu[2][k1]); } v3 = abs(v3); v2 = v2 - v3; // できるだけ対称に分布していると、v3の値がゼロに近くなるはずなので、v3をv2から引き算する。 // 各カテゴリーの幅が小さいほうが良いので、各カテゴリーの幅の合計値を評価値から引く v3 = 0.0; for (k1 = 0;k1 < nncateg;k1++) { v3 = v3 + categbunpu[2][k1]-categbunpu[1][k1]; } v2 = v2 -v3; // 分離位置th2を境界にして中心点と端点(最小値または最大値)が逆の領域にある度合いを評価値から引き算する。 for (k1 = 0; k1 < nncateg;k1++) { if (categbunpu[0][k1] > th2) // 中心点が分離位置よりもプラス側にあるとき { v2 = v2 + (categbunpu[1][k1] - th2); // 最小値の位置が分離位置よりもプラス側なら評価値を増やす } else // 中心点が分離位置よりもマイナス側にあるとき { v2 = v2 + (th2 - categbunpu[2][k1]); // 最大値の位置が分離位置よりもマイナス側なら評価値を増やす } } if (v2 > v1) { v1 = v2; th1 = th2;} // 最適分離位置と総合評価値の更新 #if Debug_segprofile2 ==1 printf("\n ??segprofile(2) :th2 = %lf, v1 = %lf, v2 = %lf",th2,v1,v2); #endif } // 分離位置th1よりもマイナス側とプラス側のカテゴリー数の計測 pcount = 0; mcount = 0; for (k1 = 0; k1 < nncateg;k1++) { if (categbunpu[2][k1] > th1) // 最大位置が分離位置よりもプラス側にあるとき { pcount++; } if (categbunpu[1][k1] < th1) // 最小位置が分離位置よりもマイナス側にあるとき { mcount++; } } // 関数の戻り値の形成 result = -1; // 初期化 if (pcount == 1 && mcount == 1 && nncateg == 2) // カテゴリーがプラス側1つとマイナス側1つに完全分離されたか? { if ((categbunpu[2][0]-th1)*(categbunpu[1][1]-th1)< 0.0){result = 0;} // 完全分離 } if (pcount > 1 && result == -1) { if (mcount > 1) { result = 3; // プラス側もマイナス側も複数個のカテゴリーあり } else { result = 1; } } else { if (mcount > 1) { result = 2; } } // 出力の形成 th = th1; // 最適分離位置の出力 v = v1; // 総合評価値の出力 #if Debug_segprofile1 == 1 printf("\n ??segprofile : nsamp = %d, step = %lf",nsamp,step); for (k1 = 0;k1 < nsamp;k1++) { printf("\n ??segprofile : a[%d] = %lf , c[%d] = %d",k1,a[k1],k1,c[k1]); } printf("\n ??segprofile : th = %lf",th); printf("\n ??segprofile : v = %lf",v); printf("\n ??segprofile : result = %d",result); #endif return (result); } /* -------------------------------------------------------- 関数名: divbunpu 機能: 入力された分布データを与えられたしきい値をもとに、プラス側の分布データと     マイナス側の分布データに分割する。 入力:  int casenum[]; ケース番号の1次元配列である。vector[i][j]は、第iケースの第j特徴量である。casenum[k]とは、           第kサンプルが対応するケース番号である。 int nsamp; サンプル数である。サンプル配列の0からnsamp-1までが有効なデータである           ことを意味する。 int jiku; 注目している特徴量の軸番号 double th; 特徴量分布をカテゴリーによって最適に2分する最適しきい値 出力: プラス側のサンプルデータ: int casenum_plus[]; ケース番号の1次元配列である。vector[i][j]は、第iケースの第j特徴量である。casenum_plus[k]とは、           第kサンプルが対応するケース番号である。 int nsamp_plus; サンプル数である。サンプル配列の0からnsamp_plus-1までが有効なデータである           ことを意味する。 マイナス側のサンプルデータ: int casenum_minus[]; ケース番号の1次元配列である。vector[i][j]は、第iケースの第j特徴量である。casenum_minus[k]とは、           第kサンプルが対応するケース番号である。 int nsamp_minus; サンプル数である。サンプル配列の0からnsamp_minus-1までが有効なデータである           ことを意味する。 起動: divbunpu(casenum,nsamp,jiku,th,casenum_plus,nsamp_plus,casenum_minus,nsamp_minus); 更新履歴: 2004年10月16日 久野敦司( patentisland@hotmail.com ) (C) Copyright 2004 久野敦司(E-mail: patentisland@hotmail.com )All rights reserved -------------------------------------------------------- */ int divbunpu(int *casenum,int nsamp,int jiku,double th,int *casenum_plus,int &nsamp_plus,int *casenum_minus,int &nsamp_minus) { int k1,k2,k3; k2 = 0; k3 = 0; for (k1=0; k1 < nsamp; k1++) { if (vector[casenum[k1]][jiku] > th) {// plus side casenum_plus[k2] = casenum[k1]; k2++; } else {// minus side casenum_minus[k3] = casenum[k1]; k3++; } } nsamp_plus = k2; nsamp_minus = k3; return(0); } /* -------------------------------------------------------------------- 関数名: bestone 機能: 入力されたケース番号リストをもとに、各ケース番号のケースのベクトルデータとカテゴリー符号を     読み出して、そのデータに関して最適な特徴軸と、その特徴軸に関するしきい値を検出する。 入力: int ncase; 処理対称として有効なケースの個数     int casenum[PLNT_NCASE]; 処理対称とするケースのケース番号リストcasenum[0] -- casenum[ncase-1]                 までが、有効なデータである。 int nfeatute; 有効な特徴軸の本数 出力: int bestaxis; 最適な特徴軸の番号     double thsearch; しきい値 int categorycode; 入力された分布が1つのカテゴリーのみからなる場合(本関数の戻り値=4)              、これはそのカテゴリーの符号を示す 起動: st = bestone(ncase,casenum,nfeature,bestaxis,thsearch,categorycode); 本関数の戻り値; int型の カテゴリー分離が完了したかどうかを示すフラグである。 0 : カテゴリー分離が完了した。すなわち、しきい値をはさんで両側はそれぞれ異なる唯一の           カテゴリーのサンプルだけになった。 1 : しきい値と同じか大きい値のサンプル分布側に複数個のカテゴリーのものを含む。 小さい側のカテゴリは1個 2 : しきい値よりも小さい値のサンプル分布側に複数個のカテゴリーのものを含む。 3 : しきい値よりも大きい値の側も小さい値の側も複数個のカテゴリーのものを含む。         4 : 入力された分布は、1つのカテゴリーのみから構成される。 -1 : 異常終了(分離不能) 更新履歴: 2004年10月18日 久野敦司( patentisland@hotmail.com ) (C) Copyright 2004 久野敦司(E-mail: patentisland@hotmail.com )All rights reserved -------------------------------------------------------------------- */ int bestone(int ncase,int *casenum,int nfeature,int &bestaxis,double &thsearch,int &categorycode1) { #define Debug_bestone1 0 #define Debug_bestone2 0 #define Debug_bestone3 0 int k1,k2; double a[PLNT_NCASE]; int c[PLNT_NCASE]; double min1,max1; double step; // 最適しきい値探索のためのステップ幅 int stat; // 最適しきい値選択処理のステータス segprofile関数の戻り値の受け取り用の変数 double th; // 最適しきい値 double v; // 上記の最適しきい値のときの総合評価値 int pncateg; // 最適しきい値よりもプラス側に分布するサンプルデータの含むカテゴリーの種類数 int mncateg; // 最適しきい値よりもマイナス側に分布するサンプルデータの含むカテゴリーの種類数 double vsearch; // 最適しきい値のときの評価値レジスタ int pncategsearch; // 最適しきい値よりもプラス側に分布するサンプルデータの含むカテゴリーの種類数探索変数 int mncategsearch; // 最適しきい値よりもマイナス側に分布するサンプルデータの含むカテゴリーの種類数探索変数 int statsearch; int st; int categorycode; bestaxis = 0; // 最良の特徴軸番号の初期化 thsearch = 0.0; // 値を何か代入しておく。 statsearch = -1; // 初期化 vsearch = PLNT_VALMIN; // 軸選択のための評価値の最小値を設定 for (k2 = 0; k2 < nfeature;k2++) // 特徴軸を変えながらの探索 {//(1) st = 0; // stの値の初期化 #if Debug_bestone3 == 1 printf("\n ?? bestone: 第%d番の特徴軸に関する処理",k2); #endif // segprofile に設定するデータの準備 min1 = vector[casenum[0]][k2]; max1 = vector[casenum[0]][k2]; for (k1 = 0; k1 < ncase;k1++) { a[k1] = vector[casenum[k1]][k2]; c[k1] = categcode[casenum[k1]][0]; // カテゴリー切り口数を1個と固定して、カテゴリー符号を設定した。 if (a[k1] < min1) {min1 = a[k1];} if (a[k1] > max1) {max1 = a[k1];} } step = (max1 - min1)/PLNT_NSTEP; // 特徴軸を最大値と最小値の間で、PLNT_NSTEPステップに分割して各ステップで軸評価する。 if (step == 0.0) {printf("\n ??bestone 異常発生: 特徴軸番号 = %d, ncase = %d",k2,ncase); st = -1;} // ステップがゼロであると、その特徴軸に関する処理を中断して次の特徴軸の処理に移る /* -------------------------------------------------------------------------------------- 指定した軸上での特徴量分布に関する最適なしきい値と、その時の評価値を算出する。 --------------------------------------------------------------------------------------- */ if (st != -1) // step = 0.0なら、segprofileの実行を避ける {// (2) st = segprofile(ncase,step,a,c,th,v,categorycode); if (st == -1) { printf("\n ??bestone 異常発生2");} // 異常終了 if (st == 4) // その軸ではカテゴリーは1つしかない { categorycode1 = categorycode; // カテゴリー符号を設定する statsearch = st; break; // 軸の探索ループから抜ける } if (v > vsearch && st >= 0 && st <= 3) // 最適軸候補が見つかったときの処理 { vsearch = v; bestaxis = k2; thsearch = th; statsearch = st; } #if Debug_bestone1 == 1 printf("\n ??bestone(1): st = %d,bestaxis = %d, thsearch = %lf,th = %lf,vsearch = %lf",st,bestaxis,thsearch,th,vsearch); #endif }// end of (2) }// end of (1) #if Debug_bestone2 == 1 printf("\n ??bestone(2) 入力データ\n: ncase = %d, nfeature = %d",ncase,nfeature); /* for (k1 = 0; k1 < ncase;k1++) { printf("\n ??bestone(2): casenum[%d] = %d",k1,casenum[k1]); } */ printf("\n ??bestone(2) 出力データ\n: bestaxis = %d, thsearch = %lf",bestaxis,thsearch); printf("\n ??bestone(2) st = %d, categorycode = %d",st,categorycode); #endif return(statsearch); } /* -------------------------------------------------------------------- 関数名: dtreedisplay 更新履歴: 2004年10月19日 久野敦司( patentisland@hotmail.com ) (C) Copyright 2004 久野敦司(E-mail: patentisland@hotmail.com )All rights reserved -------------------------------------------------------------------- */ int dtreedisplay() { int k1; printf("\n 判別ツリーのノードを表示する。ノードの個数 = %d\n",dtree_used); //判別木用のノードの個数 for (k1 = 0;k1 %lf then Node #%d else Node #%d",dtree_fno[k1],dtree_th[k1],dtree_plusnode[k1],dtree_minusnode[k1]); } else { printf("\n | Category code = %d",dtree_categn[k1]); } } return(0); } /* ------------------------------------------------------------------------------------ 関数名: dtreegen 機能: 判別ツリーのノードの生成をする。すなわち、最適な特徴軸の番号、しきい値を得て     ノードを生成する。 入力: int bestaxis; 最適な特徴軸の番号     double thsearch; しきい値 int nfeatute; 有効な特徴軸の本数 int depth; 再帰呼び出しの深さ int parent; 親ノードの番号 int houkou; 判別ツリーの生成方向(1:プラス側、−1:マイナス側) 起動: dtreegen(houkou,ncase,casenum,nfeature,depth,parent); 使用するグローバル変数: int dtree_fno[PLNT_DTREENODE]; //判別木用のノードの特徴量番号 double dtree_th[PLNT_DTREENODE]; //判別木用のノードの、判別用しきい値 int dtree_categn[PLNT_DTREENODE];//判別木用のノードのカテゴリー番号(この値がマイナスの時は非終端ノード) int dtree_plusnode[PLNT_DTREENODE];//判別木用のノードの、プラス側分岐先ノード番号 int dtree_minusnode[PLNT_DTREENODE];//判別木用のノードの、マイナス側分岐先ノード番号 int dtree_parentnode[PLNT_DTREENODE]; // 親ノードの番号 int dtree_used = -1; // 使用済みノード番号(0番から仕様開始。未使用ならマイナスの値をとる) int categcode[PLNT_NCASE][PLNT_CATEG]; // 学習用ケースデータにおけるカテゴリーデータ 更新履歴: 2004年10月18日 久野敦司( patentisland@hotmail.com ) (C) Copyright 2004 久野敦司(E-mail: patentisland@hotmail.com )All rights reserved ------------------------------------------------------------------------------------ */ int dtreegen(int houkou,int ncase,int *casenum,int nfeature,int depth,int parent) { #define dtreegen_Debug 0 #define dtreegen_Debug1 0 #define dtreegen_Debug2 0 #define dtreegen_Debug3 0 int pncase; //thよりもプラス側に存在するケース数 int mncase; //thよりもマイナス側に存在するサンプル数 int casenump[PLNT_NCASE]; /*入力のサンプルデータa[]を最適しきい値vで区分したときの、プラス側ケース番号の 1次元配列である。*/ int casenumm[PLNT_NCASE];/* 入力のサンプルデータa[]を最適しきい値vで区分したときの、マイナス側ケース番号の1次元配列である。          vector[i][j]は、第iケースの第j特徴量である。casenumm[k]とは、第kサンプルが対応するケース番号である。 */ int bestaxis; // 最適しきい値を与えるときの特徴軸番号 int statsearch; double thsearch=0.0; // 最適しきい値 int categorycode; // 入力された分布が単一のカテゴリーから構成される場合のカテゴリー符号 int k1,k2; int depth1,parent1; depth1 = depth; // この関数が呼ばれたときのローカルな記憶領域 parent1 = parent; dtreegen_count++; // デバッグ用のdtreegen関数のコール回数カウンタのインクリメント #if dtreegen_Debug1 == 1 printf("\n ??dtreegen(1): 判別ツリーノード探索方向 = %d",houkou); // For debug printf("\n ??dtreegen(1): 親ノードの番号 = %d",parent1); // For debug printf("\n ??dtreegen(1): dtreegen count = %d",dtreegen_count); // For debug printf("\n ??dtreegen(1): dtree_used = %d",dtree_used); //判別木用のノードの個数 #endif /* ---------------------------------------------------------------- 特別な状態の場合の判別ツリーノードの形成処理 ---------------------------------------------------------------- */ if (depth1 >= PLNT_DEPTHMAX) {printf("\n ?? dtreegen: 探索深さ超過エラー");return(-1);} if (ncase == 1) // サンプル数が1つのみになった場合 { dtree_houkou[dtree_used] = houkou; // 親ノードからみた、そのノードの設定方向をセット dtree_categn[dtree_used] = categcode[casenum[0]][0]; // そのサンプルのカテゴリーを判別ツリーノードのカテゴリとする dtree_parentnode[dtree_used] = parent1; dtree_used++; #if dtreegen_Debug3 == 1 printf("\n ?? dtreegen (サンプル数が1になったときの処理)"); #endif return(0); } /* ----------------------------------------------------- casenum[]とケース数ncaseで決まる分布データに関する最適な 特徴軸bestaxisを選択し、その特徴軸でのしきい値を返す。 ----------------------------------------------------- */ statsearch = bestone(ncase,casenum,nfeature,bestaxis,thsearch,categorycode); #if dtreegen_Debug3 == 1 printf("\n dtreegen??(1.1) dtree_used = %d,statsearch = %d,bestaxis = %d",dtree_used,statsearch,bestaxis); #endif if (statsearch <= 3 && statsearch >= 0) // 非終端ノードの場合 { dtree_houkou[dtree_used] = houkou; // 親ノードからみた、そのノードの設定方向をセット dtree_fno[dtree_used] = bestaxis; //判別木用のノードの特徴量番号 dtree_th[dtree_used] = thsearch; //判別木用のノードの、判別用しきい値 dtree_categn[dtree_used] = -1;//判別木用のノードのカテゴリー番号(この値がマイナスの時は非終端ノード) dtree_parentnode[dtree_used] = parent1; dtree_used++; parent1 = dtree_used - 1; # if dtreegen_Debug2 == 1 printf("\n ?? dtreegen(2) :: dtree_used = %d",dtree_used); //判別木用のノードの個数 for (k1 = 0;k1 < dtree_used;k1++) { printf("\n ?? dtreegen(2) :: dtree_fno[%d] = %d",k1,dtree_fno[k1]); //判別木用のノードの特徴量番号 printf("\n ?? dtreegen(2) :: dtree_th[%d] = %lf",k1,dtree_th[k1]); //判別木用のノードのしきい値 printf("\n ?? dtreegen(2) :: dtree_categn[%d] = %d",k1,dtree_categn[k1]); //判別木用のノードのカテゴリー番号 printf("\n ?? dtreegen(2) :: dtree_plusnode[%d] = %d",k1,dtree_plusnode[k1]); //判別木用のプラス側ノード番号 printf("\n ?? dtreegen(2) :: dtree_minusnode[%d] = %d",k1,dtree_minusnode[k1]); //判別木用のマイナス側ノード番号 printf("\n ?? dtreegen(2) :: dtree_parentnode[%d] = %d",k1,dtree_parentnode[k1]); //判別木用のマイナス側ノード番号 } #endif divbunpu(casenum,ncase,bestaxis,thsearch,casenump,pncase,casenumm,mncase); // 分布の分割 #if dtreegen_Debug3 == 1 printf("\n dtreegen??(1.4) プラス側分布の処理直前 dtree_used = %d,parent1=%d",dtree_used,parent1); #endif dtreegen(1,pncase,casenump,nfeature,depth1+1,parent1); // プラス側の分布の処理 #if dtreegen_Debug3 == 1 printf("\n dtreegen??(1.5) プラス側分布の処理直後 dtree_used = %d,parent1=%d",dtree_used,parent1); #endif dtreegen(-1,mncase,casenumm,nfeature,depth1+1,parent1); // マイナス側の分布の処理 #if dtreegen_Debug3 == 1 printf("\n dtreegen??(1.6) マイナス側分布の処理直後 dtree_used = %d,parent1=%d",dtree_used,parent1); #endif } else if (statsearch == 4) // 終端ノードの場合 { #if dtreegen_Debug3 == 1 printf("\n dtreegen??(1.2) dtree_used = %d,statsearch = %d,bestaxis = %d",dtree_used,statsearch,bestaxis); #endif #if dtreegen_Debug == 1 if (categorycode == -1) {printf("\n ??dtreegen(3) categorycode 設定エラー");} #endif dtree_houkou[dtree_used] = houkou; // 親ノードからみた、そのノードの設定方向をセット dtree_categn[dtree_used] = categorycode;//判別木用のノードのカテゴリー番号を設定 dtree_parentnode[dtree_used] = parent1; dtree_used++; #if dtreegen_Debug3 == 1 printf("\n dtreegen??(1.3) dtree_used = %d,statsearch = %d,bestaxis = %d",dtree_used,statsearch,bestaxis); #endif } else { if (ncase > 0) { printf("\n dtreegen?? すべてのケースデータが同一点となって、カテゴリー分離不能の異常発生。0番のケースデータのカテゴリー符号を設定した。"); dtree_houkou[dtree_used] = houkou; // 親ノードからみた、そのノードの設定方向をセット dtree_categn[dtree_used] = categcode[casenum[0]][0]; // そのサンプルのカテゴリーを判別ツリーノードのカテゴリとする dtree_parentnode[dtree_used] = parent1; dtree_used++; } } return(0); } /* ------------------------------------------------------------------------------------ 関数名: recognize 機能: 判別ツリーを用いて、入力された特徴ベクトルの属するカテゴリー符号を返す。 入力: double pattern[PLNT_NF]; 特徴ベクトル(第0番特徴量からが有効 起動: int recognize(pattern); 戻り値: カテゴリー符号 使用するグローバル変数: int dtree_fno[PLNT_DTREENODE]; //判別木用のノードの特徴量番号 double dtree_th[PLNT_DTREENODE]; //判別木用のノードの、判別用しきい値 int dtree_categn[PLNT_DTREENODE];//判別木用のノードのカテゴリー番号(この値がマイナスの時は非終端ノード) int dtree_plusnode[PLNT_DTREENODE];//判別木用のノードの、プラス側分岐先ノード番号 int dtree_minusnode[PLNT_DTREENODE];//判別木用のノードの、マイナス側分岐先ノード番号 int dtree_parentnode[PLNT_DTREENODE]; // 親ノードの番号 int dtree_used = -1; // 使用済みノード番号(0番から仕様開始。未使用ならマイナスの値をとる) int categcode[PLNT_NCASE][PLNT_CATEG]; // 学習用ケースデータにおけるカテゴリーデータ 更新履歴: 2004年10月19日 久野敦司( patentisland@hotmail.com ) (C) Copyright 2004 久野敦司(E-mail: patentisland@hotmail.com )All rights reserved ------------------------------------------------------------------------------------ */ int recognize(double *pattern) { int point; int jiku; double thresh; int result; point = 0; while (dtree_categn[point] == -1) { jiku = dtree_fno[point]; thresh = dtree_th[point]; if (pattern[jiku] > thresh) {point = dtree_plusnode[point];} else {point = dtree_minusnode[point];} } result = dtree_categn[point]; return(result); } /* ----------------------------------------------------------------- 非終端ノードにおけるプラス側とマイナス側の子供ノード番号を設定する 関数名: dtreeset 入力:  起動: dtreeset(); 更新履歴: 2004年10月20日 久野敦司( patentisland@hotmail.com ) (C) Copyright 2004 久野敦司(E-mail: patentisland@hotmail.com )All rights reserved ----------------------------------------------------------------- */ int dtreeset() { int k1,oya; for (k1 = 1;k1 < dtree_used;k1++) // ルートノード(ノード番号0のもの以外のノードについて、分析する) { oya = dtree_parentnode[k1]; if (dtree_houkou[k1] == 1) // Plus { dtree_plusnode[oya] = k1; } if (dtree_houkou[k1] == -1) // Minus { dtree_minusnode[oya] = k1; } } return(0); } /* -------------------------------------------------------------------- 関数:dtreefilewr 機能:判別ツリーをファイルに書き出す。 入力: char *filename; ファイルネームの文字列へのポインタ 起動: dtreefilewr(filename); 更新履歴: 2004年10月20日 久野敦司( patentisland@hotmail.com ) (C) Copyright 2004 久野敦司(E-mail: patentisland@hotmail.com )All rights reserved -------------------------------------------------------------------- */ dtreefilewr(char *filename) { FILE *stream; int k1; stream = fopen(filename,"w"); fprintf(stream,"%d",dtree_used); //判別木用のノードの個数 for (k1 = 0;k1 < dtree_used;k1++) { fprintf(stream,"\n %d",dtree_fno[k1]); //判別木用のノードの特徴量番号 fprintf(stream,"\n %lf",dtree_th[k1]); //判別木用のノードのしきい値 fprintf(stream,"\n %d",dtree_categn[k1]); //判別木用のノードのカテゴリー番号 fprintf(stream,"\n %d",dtree_plusnode[k1]); //判別木用のプラス側ノード番号 fprintf(stream,"\n %d",dtree_minusnode[k1]); //判別木用のマイナス側ノード番号 fprintf(stream,"\n %d\n\n",dtree_parentnode[k1]); //判別木用のマイナス側ノード番号 } fclose(stream); return(0); } /* -------------------------------------------------------------------- 関数:dtreefilerd 機能:判別ツリーをファイルから読み出す。 入力: char *filename; ファイルネームの文字列へのポインタ 起動: dtreefilerd(filename); 更新履歴: 2004年10月20日 久野敦司( patentisland@hotmail.com ) (C) Copyright 2004 久野敦司(E-mail: patentisland@hotmail.com )All rights reserved -------------------------------------------------------------------- */ dtreefilerd(char *filename) { FILE *stream; int k1; stream = fopen(filename,"r"); fscanf(stream,"%d",&dtree_used); //判別木用のノードの個数 for (k1 = 0;k1 < dtree_used;k1++) { fscanf(stream,"%d",&(dtree_fno[k1])); //判別木用のノードの特徴量番号 fscanf(stream,"%lf",&(dtree_th[k1])); //判別木用のノードのしきい値 fscanf(stream,"%d",&(dtree_categn[k1])); //判別木用のノードのカテゴリー番号 fscanf(stream,"%d",&(dtree_plusnode[k1])); //判別木用のプラス側ノード番号 fscanf(stream,"%d",&(dtree_minusnode[k1])); //判別木用のマイナス側ノード番号 fscanf(stream,"%d",&(dtree_parentnode[k1])); //判別木用のマイナス側ノード番号 } fclose(stream); return(0); } /* -------------------------------------------------------------------- メインプログラム (C) Copyright 2004 久野敦司(E-mail: patentisland@hotmail.com )All rights reserved -------------------------------------------------------------------- */ void main(void) { #define Debug_main1 0 // デバッグスイッチ1 #define Debug_main2 0 // デバッグスイッチ2 #define Debug_main3 1 // デバッグスイッチ3 #define Debug_main4 1 // デバッグスイッチ4 #define Debug_main5 0 // デバッグスイッチ5 #define Debug_main6 0 // デバッグスイッチ6 #define Debug_main7 1 // デバッグスイッチ7 #define Debug_main8 1 // デバッグスイッチ8 FILE *stream; long count; int k1,k2; double avr,max,min,bunsan,sigma; // 一次特徴量 int categA,categB; double rwork; double *ptr_vector[PLNT_NCASE]; // vector[][]配列用のポインタ配列 // ケースごとの特徴量のカテゴリー符号配列 int *ptr_categcode[PLNT_NCASE]; // 上記配列用のポインタ配列 // 2次元配列用のポインタ配列の値設定 for (k1 = 0;k1 < PLNT_NCASE;k1++) { ptr_vector[k1] = &(vector[k1][0]); } for (k1 = 0;k1 < PLNT_NCASE;k1++) { ptr_categcode[k1] = &(categcode[k1][0]); } // ポインタ配列の先頭を指すポインタの設定 double **ptr_ptr_vector = &ptr_vector[0]; int **ptr_ptr_categcode = &ptr_categcode[0]; double min1,max1; double step; // 最適しきい値探索のためのステップ幅 double a[PLNT_NCASE]; int c[PLNT_NCASE]; int casenum[PLNT_NCASE]; int psamp; //thよりもプラス側に存在するサンプル数 int msanp; //thよりもマイナス側に存在するサンプル数 double ap[PLNT_NCASE]; //入力のサンプルデータa[]を最適しきい値vで区分したときの、プラス側サンプルデータの1次元配列である。 int cp[PLNT_NCASE]; //入力のサンプルデータa[]を最適しきい値vで区分したときの、プラス側カテゴリー符号の1次元配列である。サンプルデータに対応するカテゴリー符号がはいっている。 int casenump[PLNT_NCASE]; /*入力のサンプルデータa[]を最適しきい値vで区分したときの、プラス側ケース番号の1次元配列である。 vector[i][j]は、第iケースの第j特徴量である。casenump[k]とは、第kサンプルが対応するケース番号である。*/ double am[PLNT_NCASE];//入力のサンプルデータa[]を最適しきい値vで区分したときの、マイナス側サンプルデータの1次元配列である。 int cm[PLNT_NCASE];//入力のサンプルデータa[]を最適しきい値vで区分したときの、マイナス側カテゴリー符号の1次元配列である。サンプルデータに対応するカテゴリー符号がはいっている。 int casenumm[PLNT_NCASE];/* 入力のサンプルデータa[]を最適しきい値vで区分したときの、マイナス側ケース番号の1次元配列である。          vector[i][j]は、第iケースの第j特徴量である。casenumm[k]とは、第kサンプルが対応するケース番号である。 */ int stat; // 最適しきい値選択処理のステータス segprofile関数の戻り値の受け取り用の変数 double th; // 最適しきい値 double v; // 上記の最適しきい値のときの総合評価値 double thsearch; // 最適しきい値の探索用のレジスタ double vsearch; // 最適しきい値のときの評価値レジスタ int bestaxis; // 最適しきい値を与えるときの特徴軸番号 int pncateg; // 最適しきい値よりもプラス側に分布するサンプルデータの含むカテゴリーの種類数 int mncateg; // 最適しきい値よりもマイナス側に分布するサンプルデータの含むカテゴリーの種類数 int pncategsearch; // 最適しきい値よりもプラス側に分布するサンプルデータの含むカテゴリーの種類数探索変数 int mncategsearch; // 最適しきい値よりもマイナス側に分布するサンプルデータの含むカテゴリーの種類数探索変数 int statsearch; // segprofileの処理結果ステータス変数 int ncategsyu; // カテゴリー種類数 int oya; // 親ノード番号の設定エリア // ベクトルデータファイル"vector.txt"の読み取り結果データ // ケースごとの特徴量データ配列 int ncase; // 有効なケース数 int nfeature; // 有効な特徴量数 int ncateg; // 有効なカテゴリー切り口数 char s1[PLNT_BUFF],s2[PLNT_BUFF]; // 判別ツリー用のデータエリアの初期化 for (k1=0; k1 < PLNT_DTREENODE ;k1++) { dtree_fno[k1] = -1; //判別木用のノードの特徴量番号 dtree_th[k1] = 0.0; //判別木用のノードの、判別用しきい値 dtree_categn[k1] = -100;//判別木用のノードのカテゴリー番号(この値がマイナスの時は非終端ノード) dtree_plusnode[k1] = -222;//判別木用のノードの、プラス側分岐先ノード番号 dtree_minusnode[k1] = -333;//判別木用のノードの、マイナス側分岐先ノード番号 dtree_parentnode[k1] = -5555; // 親ノードを−1に初期化する dtree_houkou[k1] = 0; // 初期化 } #if Debug_main8 == 1 count = 0; for (k1 = 0; k1 < PLNT_SAMP_MAX;k1++) { sample[k1] = 5000*sin(k1*5.0);count++; } filewr("サンプルデータです","2004年10月20日作成",0,count,sample); #endif filerd(s1,s2,categA,count,sample); // サンプルデータの読み取り hisano(count,sample);// サンプルデータのhisano展開の実施 //hisanodisp(); #if Debug_main1 == 1 // 1次元配列の関数わたしのテスト(ベクトルデータの自動生成) for (k1 = 0;k1 < PLNT_NCASE;k1++) { for (k2 = 0; k2 < PLNT_NF;k2++) { vector[k1][k2] = sin(k1*10.0 + k2*30.0)*100.0; printf("\n ??main: vector[%d][%d] = %f",k1,k2,vector[k1][k2]);} } for (k1 = 0; k1 < PLNT_NCASE;k1++) { for (k2 = 0; k2 < PLNT_CATEG;k2++) { categcode[k1][k2] = floor((sin(vector[k1][k2])*1.5+1.5)/2.0); } } #endif #if Debug_main2 == 1 // ベクトルファイルデータの作成 stream = fopen("vector.txt","w"); // ベクトルファイルデータの作成後書き込みモードでのオープン fprintf(stream,"%d\n%d\n%d\n",PLNT_NCASE,PLNT_NF,PLNT_CATEG); for (k1 = 0; k1 < PLNT_NCASE;k1++) { fprintf(stream,"\n"); for (k2 = 0;k2 < PLNT_NF;k2++) { fprintf(stream,"%lf\t",vector[k1][k2]);} fprintf(stream,"\t\t"); for (k2 = 0;k2 < PLNT_CATEG;k2++) { fprintf(stream,"%d\t",categcode[k1][k2]);} } fclose(stream); #endif /* ---------------------------------------------- ベクトルファイルデータの読み取り ---------------------------------------------- */ vectfilerd(ncase,nfeature,ncateg,ptr_ptr_vector,ptr_ptr_categcode); #if Debug_main3 == 1 printf("\n ??main ファイルから読み取ったベクトルデータおよびカテゴリー符号データを表示する。\n"); for (k1 = 0; k1 < ncase;k1++) { printf("\n"); for (k2 = 0;k2 < nfeature;k2++) { printf("%lf\t",vector[k1][k2]);} printf("\t\t"); for (k2 = 0;k2 < ncateg;k2++) { printf("%d\t",categcode[k1][k2]);} } #endif #if Debug_main5 == 1 // ファイルから読み取ったデータを表示する for (k1 = 0; k1 < ncase;k1++) { printf("\n"); for (k2 = 0;k2 < nfeature;k2++) { printf("%lf\t",vector[k1][k2]);} printf("\t\t"); for (k2 = 0;k2 < ncateg;k2++) { printf("%d\t",categcode[k1][k2]);} } #endif /* -------------------------------------------------------------------------------------------------------- 判別ツリーのノードの生成 -------------------------------------------------------------------------------------------------------- */ for (k1 = 0; k1 < ncase;k1++) { casenum[k1] = k1; } dtree_used = 0; // 判別ツリーはゼロ番要素から格納されるため dtreegen_count = 0; // for debug #if Debug_main6 == 1 printf("\n ??main(****************************************************): dtreegen_count = %d",dtreegen_count); printf("\n ??main(****************************************************): dtree_used = %d",dtree_used); #endif dtreegen(0,ncase,casenum,nfeature,0,-1); /* ----------------------------------------------------------------- 非終端ノードにおけるプラス側とマイナス側の子供ノード番号を設定する ----------------------------------------------------------------- */ dtreeset(); dtreedisplay(); dtreefilewr("dtree.txt"); dtreefilerd("dtree.tst"); dtreedisplay(); #if Debug_main7 == 1 printf("\n ??main: 判別ツリーによる認識実験を開始します nfeature = %d",nfeature); int jikkoflag=0; while (jikkoflag == 0) { printf("\n 特徴ベクトルの各パラメータの値を入力してください。"); for (k1 = 0; k1 < nfeature;k1++) { printf("\n 第%d 特徴量 = ",k1); scanf("%lf",&rwork); a[k1] = rwork; } printf("\n 入力されたベクトルのカテゴリー= %d",recognize(a)); printf("\n 実験を続けますか? 続けるなら 0 を入力してください = "); scanf("%d",&jikkoflag); } #endif return; }