content: package com.actelion.research.calc.statistics;
  
  import java.text.DecimalFormat;
  import java.text.DecimalFormatSymbols;
  import java.text.NumberFormat;
  import java.util.Arrays;
  import java.util.Locale;
  
  import com.actelion.research.calc.ArrayUtilsCalc;
  import com.actelion.research.calc.Matrix;
  import com.actelion.research.calc.histogram.ConstantsHistogram;
  import com.actelion.research.calc.histogram.IntegerHistogram;
  import com.actelion.research.calc.histogram.MatrixBasedHistogram;
  import com.actelion.research.util.Formatter;
  import com.actelion.research.util.datamodel.DoubleArray;
  import com.actelion.research.util.datamodel.IntArray;
  
  /**
   * 
   * StatisticsOverview
   * Some basic statistics about the given data
   * 28 Jun 2010 MvK: Start implementation
   */
  public class StatisticsOverview {
  
  	public static final String TAG_MEAN = "Avr";
  	public static final String TAG_SDV = "SDV";
  	public static final String TAG_MEDIAN = "Median";
  	public static final String TAG_PERCENTILE05 = "Percentile.05";
  	public static final String TAG_PERCENTILE95 = "Percentile.95";
  
  	public static final NumberFormat DF1 = new DecimalFormat("0.0", new DecimalFormatSymbols(Locale.US));
  	public static final NumberFormat DF3 = new DecimalFormat("0.000", new DecimalFormatSymbols(Locale.US));
  	public static final NumberFormat DF4 = new DecimalFormat("0.0000", new DecimalFormatSymbols(Locale.US));
  	private static final NumberFormat DF3Plus = new DecimalFormat("0.000##", new DecimalFormatSymbols(Locale.US));
  
  	private static final int BINS = 20;
  	
  	private static final int WIDTH = 8;
  	
  	private static final int DIGITS = 2;
  
  	private String name;
  	
  	private double min;
  	private double mean;
  	private double max;
  
  	private double sdv;
  	
  	private double percentile05;
  	private double leftQuartile;
  
  	private double median;
  
  	private double rightQuartile;
  	private double percentile95;
  
  	
  	private Matrix histogram;
  
  	private int valsBelowHistMin;
  	
  	private int valsAboveHistMax;
  	
  	private int bins;
  	
  	private DoubleArray data;
  	
  	private boolean evaluated;
  	
  	public StatisticsOverview() {
  		data = new DoubleArray();
  		bins = BINS;
  		evaluated = false;
  	}
  	
  	public StatisticsOverview(DoubleArray da) {
  		data = da;
  		bins = BINS;
  		evaluated = false;
  	}
  	
  	public void add(double value){
  		data.add(value);
  		evaluated = false;
  		
  	}
  	
  	public void add(double [] arr){
  		
  		for (int i = 0; i < arr.length; i++) {
  			data.add(arr[i]);	
  		}
  		
  		evaluated = false;
  		
  	}
  	
  	public void add(int [] arr){
  		
  		for (int i = 0; i < arr.length; i++) {
  			data.add(arr[i]);	
  		}
  		
  		evaluated = false;
  		
  	}
  
  	public DoubleArray getData() {
  		return data;
  	}
  
  	public double getMean() {
  		return mean;
  	}
  
  	public double getSdv() {
  		return sdv;
  	}
  
  	public double getMedian() {
  		return median;
  	}
  
  	public ModelStatisticsOverview evaluate(){
  
  		double histMin = data.min() - data.min() * ConstantsHistogram.TINY_FACTOR;
  		double histMax = data.max() + data.max() * ConstantsHistogram.TINY_FACTOR;
  
  		ModelStatisticsOverview modelStatisticsOverview = new ModelStatisticsOverview();
  
  		if(Math.abs(histMin-histMax) > Matrix.TINY08) {
  
  			evaluate(histMin, histMax);
  			modelStatisticsOverview.min = data.min();
  			modelStatisticsOverview.avr = mean;
  			modelStatisticsOverview.max = data.max();
  			modelStatisticsOverview.sdv = sdv;
  
  		} else {
  			modelStatisticsOverview.min = 0;
  			modelStatisticsOverview.avr = 0;
  			modelStatisticsOverview.max = 0;
  			modelStatisticsOverview.sdv = 0;
  		}
  
  		return modelStatisticsOverview;
  	}
  	
  	public void evaluate(double histMin, double histMax){
  
  		if(Math.abs(histMin-histMax) < Matrix.TINY08) {
  			throw new RuntimeException("Equal histogram boundaries! histMin " + histMin + " histMax" + histMax + ".");
  		}
  
  		calculateMedianStatistics();
  
  		double [] arr = data.get();
  
  		min = ArrayUtilsCalc.min(arr);
  
  		mean = ArrayUtilsCalc.getMean(arr);
  
  		max = ArrayUtilsCalc.max(arr);
  
  		sdv = ArrayUtilsCalc.getStandardDeviation(arr);
  		
  		Matrix maBins = MatrixBasedHistogram.getHistogramBins(histMin, histMax, bins);
  
  		Matrix ma = new Matrix(true, arr);
  
  		histogram = MatrixBasedHistogram.getHistogram(ma, maBins);
  
  		for (int i = 0; i < ma.cols(); i++) {
  			if(ma.get(0, i)<histMin)
  				valsBelowHistMin++;
  			else if(ma.get(0, i)>histMax)
  				valsAboveHistMax++;
  		}
  		
  		evaluated = true;
  	}
  	
  	public void evaluateIntegerBins(double histMin, double histMax){
  		
  		calculateMedianStatistics();
  		
  		Matrix ma = new Matrix(true, data.get());
  		
  		mean = ma.getMean();
  		
  		sdv = ma.getStandardDeviation();
  		
  		int [][] arrBins = IntegerHistogram.getBinsEquallyDistributed(bins, (int)histMin, (int)histMax);
  			
  		Matrix maBins = new Matrix(arrBins);
  		
  		maBins = maBins.getTranspose();
  
  		histogram = MatrixBasedHistogram.getHistogram(ma, maBins);
  		
  		for (int i = 0; i < ma.cols(); i++) {
  			if(ma.get(0, i)<histMin)
  				valsBelowHistMin++;
  			else if(ma.get(0, i)>histMax)
  				valsAboveHistMax++;
  		}
  		
  		evaluated = true;
  	}
  	
      private double calculateMedianStatistics() {
      	
      	double [] arr = data.get();
      	
      	Arrays.sort(arr);
      	
  		percentile05 = getQuartile(arr, 0.05);
  		leftQuartile = getQuartile(arr, 0.25);
  
  		median = getQuartile(arr, 0.5);
  		
  		rightQuartile = getQuartile(arr, 0.75);
  		percentile95 = getQuartile(arr, 0.95);
  
  		return median;
      }
  
  	public double getPercentile05() {
  		return percentile05;
  	}
  
  	public double getPercentile95() {
  		return percentile95;
  	}
  
  	private static double getQuartile(double [] arr, double q) {
      	double v = 0;
  
  		if(q<0){
  			throw new RuntimeException("Negative values are not allowed!");
  		}
  
  		if(arr.length % 2==0) {
  			if(((int)(q * arr.length))==0){
  				v = arr[0];
  			} else {
  				int p1 = (int) ((q * arr.length) - 1);
  				int p2 = (int) (q * arr.length);
  				v = (arr[p1] + arr[p2]) / 2.0;
  			}
  		} else {
  			int p = (int)(arr.length * q);
  			v = arr[p];
  		}
      	
      	return v;
      }
  
      public double getQuartile(double q) {
      	double [] arr = data.get();
      	Arrays.sort(arr);
      	return getQuartile(arr, q);
      }
  
      public int getNumData(){
      	return data.size();
      }
  	
  	@Override
  	public String toString() {
  
  		if(data.size()==0){
  			return "";
  		}
  
  		if(!evaluated)
  			evaluate();
  		
  		StringBuilder sb = new StringBuilder();
  		
  		sb.append("Name\t" + name);
  		sb.append("\n");
  		sb.append("Values\t" + data.size());
  		sb.append("\n");
  		sb.append("min\t" + min);
  		sb.append("\n");
  		sb.append("Mean\t" + DF3Plus.format(mean));
  		sb.append("\n");
  		sb.append("max\t" + max);
  		sb.append("\n");
  		sb.append("SDV\t" + DF3Plus.format(sdv));
  		sb.append("\n");
  		sb.append("Quartile 0.25\t" + DF3Plus.format(leftQuartile));
  		sb.append("\n");
  		sb.append("Median\t" + DF3Plus.format(median));
  		sb.append("\n");
  		sb.append("Quartile 0.75\t" + DF3Plus.format(rightQuartile));
  		sb.append("\n");
  		sb.append("Histogram values below hist min " + valsBelowHistMin + ", values above hist max " + valsAboveHistMax);
  		sb.append("\n");
  		sb.append(MatrixBasedHistogram.histogram2String(histogram, DIGITS, WIDTH));
  		
  		Matrix histTrans = histogram.getTranspose();
  		
  		DecimalFormat dfBins = Matrix.format(DIGITS);
  		
  		sb.append("\n");
  		for (int i = 0; i < histTrans.rows(); i++) {
  			sb.append(Matrix.format(histTrans.get(i,0), dfBins, WIDTH));
  			sb.append("\t");
  			sb.append(Matrix.format(histTrans.get(i,1), dfBins, WIDTH));
  			sb.append("\t");
  			sb.append(Matrix.format(histTrans.get(i,2), dfBins, WIDTH));
  			sb.append("\n");
  		}
  
  		return sb.toString();
  	}
  
  	public String getName() {
  		return name;
  	}
  
  	public void setName(String name) {
  		this.name = name;
  	}
  
  	public void setBins(int bins) {
  		this.bins = bins;
  	}
  
  	public int getValsBelowHistMin() {
  		return valsBelowHistMin;
  	}
  
  	public int getValsAboveHistMax() {
  		return valsAboveHistMax;
  	}
  
  	public Matrix getHistogram() {
  		return histogram;
  	}
  
  
  	public static ModelStatisticsOverview get(DoubleArray da){
  
  		StatisticsOverview statisticsOverview = new StatisticsOverview(da);
  
  		return statisticsOverview.evaluate();
  
  	}
  
  	public static ModelStatisticsOverviewMedian getMedianOverview(DoubleArray da){
  		StatisticsOverview statisticsOverview = new StatisticsOverview(da);
  		statisticsOverview.evaluate();
  		ModelStatisticsOverviewMedian model =
  				new ModelStatisticsOverviewMedian(
  						statisticsOverview.percentile05,
  						statisticsOverview.leftQuartile,
  						statisticsOverview.median,
  						statisticsOverview.rightQuartile,
  						statisticsOverview.percentile95);
  
  		return model;
  
  	}
  
  	public static String toString(DoubleArray da, String text1){
  
  		StringBuilder sb = new StringBuilder();
  
  		StatisticsOverview so = new StatisticsOverview(da);
  		so.evaluate();
  		sb.append(text1);
  		sb.append("\t");
  		sb.append(DF3.format(so.getMean()));
  		sb.append("\t");
  		sb.append(DF3.format(so.getSdv()));
  		sb.append("\t");
  		sb.append(DF3.format(so.getMedian()));
  		sb.append("\t");
  		sb.append(DF3.format(so.getPercentile05()));
  		sb.append("\t");
  		sb.append(DF3.format(so.getPercentile95()));
  
  		return sb.toString();
  	}
  
  	public static String toString(IntArray ia, String text){
  
  		StringBuilder sb = new StringBuilder();
  
  		DoubleArray da = new DoubleArray(ia);
  
  		StatisticsOverview so = new StatisticsOverview(da);
  		so.evaluate();
  		sb.append(text);
  		sb.append("\t");
  		sb.append(DF1.format(so.getMean()));
  		sb.append("\t");
  		sb.append(DF1.format(so.getSdv()));
  		sb.append("\t");
  		sb.append(DF1.format(so.getMedian()));
  		sb.append("\t");
  		sb.append(DF1.format(so.getPercentile05()));
  		sb.append("\t");
  		sb.append(DF1.format(so.getPercentile95()));
  
  		return sb.toString();
  	}
  
  	public static String toStringHeader(){
  
  		StringBuilder sb = new StringBuilder();
  		sb.append("text");
  		sb.append("\t");
  		sb.append("mean");
  		sb.append("\t");
  		sb.append("sdv");
  		sb.append("\t");
  		sb.append("median");
  		sb.append("\t");
  		sb.append("perc05");
  		sb.append("\t");
  		sb.append("perc95");
  
  		return sb.toString();
  	}
  
  
  	public static String toString(DoubleArray da, String text1, String text2){
  
  		StringBuilder sb = new StringBuilder();
  
  		StatisticsOverview so = new StatisticsOverview(da);
  		so.evaluate();
  		sb.append(text1);
  		sb.append("\t");
  		sb.append(text2);
  		sb.append("\t");
  		sb.append(DF3.format(so.getMean()));
  		sb.append("\t");
  		sb.append(DF3.format(so.getSdv()));
  		sb.append("\t");
  		sb.append(DF3.format(so.getMedian()));
  		sb.append("\t");
  		sb.append(DF3.format(so.getPercentile05()));
  		sb.append("\t");
  		sb.append(DF3.format(so.getPercentile95()));
  
  		return sb.toString();
  	}
  }
  