package gf;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.opengion.fukurou.business.BizLogic_TABLE;
import org.opengion.penguin.math.statistics.HybsCorrelation;
import org.opengion.penguin.math.statistics.HybsLogisticRegression;
import org.opengion.penguin.math.statistics.HybsMultiRegression;

/**
 * penguinパッケージの統計計算を利用するためのサンプルです。
 * 
 * GF47を利用して統計計算を行います。
 *
 * @version 5.0
 * @author T.OTA
 * @since JDK1.7
 */
public class GFX027A extends BizLogic_TABLE {
	double[][]		data;

	List<double[]>	dataList	= new ArrayList<double[]>();
	StringBuilder	rtn			= new StringBuilder();

	/**
	 * メインカーソルの各行で呼ばれるロジックを定義します。
	 * 
	 * @param row 行番号
	 * @return 処理が正常終了したか
	 */
	@Override
	protected boolean befall( int row ) {
		
		double[] lineData = new double[] { lined( "FGSEIBETU" ), lined( "SEISEKI" ), lined( "TIMESTUDY" ), lined( "SISYUTU" ), lined( "FGSMOKE" ), lined( "DAYDRINK" ), lined( "SIJISEITOU" ) };
		dataList.add( lineData );

		return true;
	}

	/**
	 * 最後の行の終わりで呼び出し
	 * 
	 * @return 処理が正常終了したか
	 */
	@Override
	protected boolean last() {
		StringBuilder sb = new StringBuilder();
		
		// 相関係数のﾏｯﾌﾟ出力
		String[] name = { "性別", "成績", "勉強時間", "支出", "喫煙", "飲酒日数", "支持政党"};

		// 相関係数ﾋｰﾄﾏｯﾌﾟの作成
		doHybsCorrelation(sb,name);
		// 重回帰の計算
		doHybsMultiRegression(sb,name);
		// ﾛｼﾞｽﾃｨｯｸ回帰分析の計算
		doHybsLogisticRegression(sb,name);
		
		rtn( sb.toString() );

		
		return true;
	}
	
	/**
	 * 相関係数のヒートマップを作成。
	 * 
	 * @param sb
	 * @param name
	 */
	private void doHybsCorrelation(StringBuilder sb, String[] name){
		// 相関係数を計算の実行
		HybsCorrelation rtn = new HybsCorrelation( name, (double[][]) dataList.toArray( new double[0][0] ) );
		// ｾﾙの背景色を設定用のCSS
		sb.append( "<style>.cell_heat_yes{background-color:rgb(197,217,241)}.cell_heat_no{background-color:rgb(242,220,219)}</style>");
		
		sb.append( "<table border = '1'>" );
		// x軸ﾀｲﾄﾙ行出力
		sb.append( "<tr><td class='row_h'></td>" );
		for( int i = 0; i < name.length; i++ ) {
			sb.append( "<td class='row_h'>" ).append( name[i] ).append( "</td>" );
		}
		for( int i = 0; i < rtn.getCorrMatrix().length; i++ ) {
			double[] rowData = rtn.getCorrMatrix()[i];
			// y軸ﾀｲﾄﾙ行出力
			sb.append( "<tr>" ).append( "<td class='row_h'>" ).append( name[i] ).append( "</td>" );
			// 相関ﾃﾞｰﾀ出力
			for( int k = 0; k < rowData.length; k++ ) {
				// 相関係数の値により、ｾﾙの背景色を設定
				int rgb = (int)(255 *  (1.0 -Math.abs( rowData[k] )));
				if(rowData[k] >= 0){
					sb.append( "<td style='background-color:rgb("+rgb+","+rgb+",255)'>" );
				}else{
					//sb.append("<td class='cell_heat_no'>");
					sb.append( "<td style='background-color:rgb(255,"+rgb+","+rgb+")'>" );
				}
				
				// 相関係数4桁で四捨五入
				sb.append( String.format("%.4f", rowData[k])).append( "</td>" );
			}
			sb.append( "</td></tr>" );
		}
		sb.append( "</table><br />" );
	}
	
	/**
	 * 重回帰の計算を実行。
	 * ※支出を目的変数に指定
	 * 
	 * @param sb
	 * @param name
	 */
	private void doHybsMultiRegression(StringBuilder sb, String[] name){
		// 重回帰のﾃﾞｰﾀ出力
		// 支出に対する重回帰
		double[] y = new double[dataList.size()];
		double[][] x = new double[dataList.size()][name.length - 1];
		
		for( int i = 0; i < dataList.size(); i++){
			double[] data = dataList.get( i );
			int idx = 0;
			for(int k = 0; k < data.length; k++){
				if(k == 3){
					// 目的変数の格納(支出を指定)
					y[i] = data[k];
				}else{
					// 説明変数の格納
					x[i][idx] = data[k];
					idx++;
				}
			}
		}
		
		// 重回帰計算の実行
		HybsMultiRegression mr = new HybsMultiRegression(x,y,true);
		sb.append( "以下、回帰分析は本来「説明変数同士の相関は低い方が良い」といった注意が必要なため、相関より何を使うか考えますが、サンプルとしてそのまま計算します。<br /><br/>" );
		sb.append( "支出を目的変数とした、重回帰分析の計算結果：<br />" );
		// 決定係数
		sb.append( "決定係数：").append( mr.getRSquare() ).append( "<br />" );
		// 係数
//		sb.append( "係数：").append( Arrays.toString(mr.getParam()) ).append( "<br /><br />" );
		sb.append( "係数：").append( Arrays.toString(mr.getCoefficient()) ).append( "<br /><br />" );
		
		// predictのﾃｽﾄ
		sb.append( "性別：1,成績:70,勉強時間:5,喫煙:1,飲酒日数:5を計算した場合の、支出予想値:" );
		sb.append(mr.predict( new double[]{1,70,5,1,5,1} ));
		sb.append( "<br /><br />" );
	}
	
	/**
	 * ﾛｼﾞｽﾃｨｯｸ回帰の計算を実行。
	 * ※支持政党を目的変数に指定
	 * 
	 * @param sb
	 * @param name
	 */
	private void doHybsLogisticRegression(StringBuilder sb,String[] name){
		
		double[][]train_X = new double[dataList.size()][name.length - 1];
		int[][] train_Y = new int[dataList.size()][4];
		for(int i = 0; i < dataList.size(); i++){
			double[] data = dataList.get( i );
			for(int k = 0; k < data.length; k++){
				if(k != 6){
					// 説明変数を格納
					train_X[i][k] = data[k];
				}{
					// 目的変数を格納(支持政党1-4を配列に変換)
					switch((int)data[k]){
						case 1:
							train_Y[i] = new int[]{1,0,0,0};
							break;
						case 2:
							train_Y[i] = new int[]{0,1,0,0};
							break;
						case 3:
							train_Y[i] = new int[]{0,0,1,0};
							break;
						case 4:
							train_Y[i] = new int[]{0,0,0,1};
							break;
					}
				}
				
			}
		}
		
		// ﾛｼﾞｽﾃｨｯｸ回帰計算の実行
		HybsLogisticRegression hlr = new HybsLogisticRegression(train_X,train_Y,0.1,500,1);
		
		//"性別", "成績", "勉強時間", "支出", "喫煙", "飲酒日数";
		double[][] test_X = {
				{0,80,4,5,1,4}
				,{0,70,7,3,1,1}
				,{1,70,3,10,0,0}
				,{1,85,12,6,0,1}
		};
		double[][] test_Y = new double[test_X.length][4];
		
		sb.append( "ロジスティック回帰分析結果：" ).append( "<br />" );
		sb.append( "ｻﾝﾌﾟﾙﾃﾞｰﾀを下記のように更新している。<br />" );
		sb.append( "支持政党 [1:特徴無し,2:支出少なめ,3:支出多め,4:勉強時間多め]<br />" );
		sb.append( "入力値:[性別, 成績, 勉強時間, 支出, 喫煙, 飲酒日数] 予測値:[支持政党(1-4)の確率分布]<br />");
		// 実行結果
		for(int i=0; i<test_X.length;i++){
			sb.append( "入力値:").append( Arrays.toString( test_X[i] ) );
			test_Y[i] = hlr.predict(test_X[i]);
			sb.append( "予測値:").append( Arrays.toString( test_Y[i]) )
				.append( "<br />" );
		}
	}
}
