package org.opengion.penguin.math.statistics;

import java.util.Arrays;
import org.apache.commons.math3.stat.regression.SimpleRegression;

/**
 * apache.commons.mathを利用した線形単回帰計算のクラスです。
 * f(x)=ax+bの形で線形回帰を行います。
 */
public class HybsSimpleRegression implements HybsRegression {
	private final double[] cnst = new double[3] ;		// 係数(０次、１次、２次は常に０)

	private double rsquare;		// 決定係数

	/**
	 * コンストラクタ。
	 * 与えた二次元データを元に回帰直線を計算します。
	 * {x,y}の配列でデータを与えます。
	 *
	 * @param data xとyの組み合わせの配列
	 */
	public HybsSimpleRegression( final double[][] data ) {
		// ここで単回帰計算
		train( data );
	}

	/**
	 * dataを与えて回帰直線を求める。
	 *
	 * @param data {x,y}の配列
	 */
	private void train( final double[][] data ) {
		final SimpleRegression regression = new SimpleRegression();
		regression.addData( data );

		cnst[2] = 0 ;							// ２次係数は、常に０
		cnst[1] = regression.getSlope();
		cnst[0] = regression.getIntercept();

		rsquare = regression.getRSquare();
	}

	/**
	 * 決定係数の取得。
	 *
	 * @return 決定係数
	 */
	@Override
	public double getRSquare() {
		return rsquare;
	}

	/**
	 * 係数(０次、１次、２次は常に０)の順にセットした配列を返します。
	 *
	 * @return 係数の配列
	 */
	@Override
	public double[] getCoefficient() {
		return Arrays.copyOf( cnst,cnst.length );
	}

	/**
	 * a + bxを計算。
	 *
	 * @param in_x 必要な大きさの変数配列
	 * @return 計算結果
	 */
	@Override
	public double predict( final double... in_x ) {
		return cnst[1] * in_x[0] + cnst[0];
	}

	//************** ここまでが本体 **************
	/**
	 * ここからテスト用mainメソッド 。
	 *
	 * @param args 引数
	 */
	public static void main( final String[] args ) {
		final double[][] data = {{1, 2.3}, {2, 3.4}, {3, 6.1}, {4, 8.2}}; 

		final HybsSimpleRegression sr = new HybsSimpleRegression(data);

		final double[] cnst = sr.getCoefficient();

		System.out.println(cnst[2]);
		System.out.println(cnst[1]);
		System.out.println(cnst[0]);

		System.out.println(sr.predict( 5 ));
	}
}

