Xamarin Public Jenkins (auto-signing) 536cd135cc Imported Upstream version 5.4.0.167
Former-commit-id: 5624ac747d633e885131e8349322922b6a59baaa
2017-08-21 15:34:15 +00:00

2190 lines
67 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//-------------------------------------------------------------
// <copyright company=Microsoft Corporation>
// Copyright © Microsoft Corporation. All Rights Reserved.
// </copyright>
//-------------------------------------------------------------
// @owner=alexgor, deliant
//=================================================================
// File: StatisticalAnalysis.cs
//
// Namespace: System.Web.UI.WebControls[Windows.Forms].Charting.Formulas
//
// Classes: StatisticalAnalysis
//
// Purpose: This class is used for Statistical Analysis
//
// Reviewed: AG - Apr 1, 2003
//
//===================================================================
using System;
using System.Collections;
#if Microsoft_CONTROL
namespace System.Windows.Forms.DataVisualization.Charting.Formulas
#else
namespace System.Web.UI.DataVisualization.Charting.Formulas
#endif
{
/// <summary>
///
/// </summary>
internal class StatisticalAnalysis : IFormula
{
#region Error strings
// Error strings
//internal string inputArrayStart = "Formula requires";
//internal string inputArrayEnd = "arrays";
#endregion
#region Parameters
/// <summary>
/// Formula Module name
/// </summary>
virtual public string Name { get { return SR.FormulaNameStatisticalAnalysis; } }
#endregion // Parameters
#region Methods
/// <summary>
/// Default constructor
/// </summary>
public StatisticalAnalysis()
{
}
/// <summary>
/// The first method in the module, which converts a formula
/// name to the corresponding private method.
/// </summary>
/// <param name="formulaName">String which represent a formula name</param>
/// <param name="inputValues">Arrays of doubles - Input values</param>
/// <param name="outputValues">Arrays of doubles - Output values</param>
/// <param name="parameterList">Array of strings - Formula parameters</param>
/// <param name="extraParameterList">Array of strings - Extra Formula parameters from DataManipulator object</param>
/// <param name="outLabels">Array of strings - Used for Labels. Description for output results.</param>
virtual public void Formula( string formulaName, double [][] inputValues, out double [][] outputValues, string [] parameterList, string [] extraParameterList, out string [][] outLabels )
{
string name;
outLabels = null;
name = formulaName.ToUpper(System.Globalization.CultureInfo.InvariantCulture);
try
{
switch( name )
{
case "TTESTEQUALVARIANCES":
TTest( inputValues, out outputValues, parameterList, out outLabels, true );
break;
case "TTESTUNEQUALVARIANCES":
TTest( inputValues, out outputValues, parameterList, out outLabels, false );
break;
case "TTESTPAIRED":
TTestPaired( inputValues, out outputValues, parameterList, out outLabels );
break;
case "ZTEST":
ZTest( inputValues, out outputValues, parameterList, out outLabels );
break;
case "FTEST":
FTest( inputValues, out outputValues, parameterList, out outLabels );
break;
case "COVARIANCE":
Covariance( inputValues, out outputValues, out outLabels );
break;
case "CORRELATION":
Correlation( inputValues, out outputValues, out outLabels );
break;
case "ANOVA":
Anova( inputValues, out outputValues, parameterList, out outLabels );
break;
case "TDISTRIBUTION":
TDistribution( out outputValues, parameterList, out outLabels );
break;
case "FDISTRIBUTION":
FDistribution( out outputValues, parameterList, out outLabels );
break;
case "NORMALDISTRIBUTION":
NormalDistribution( out outputValues, parameterList, out outLabels );
break;
case "INVERSETDISTRIBUTION":
TDistributionInverse( out outputValues, parameterList, out outLabels );
break;
case "INVERSEFDISTRIBUTION":
FDistributionInverse( out outputValues, parameterList, out outLabels );
break;
case "INVERSENORMALDISTRIBUTION":
NormalDistributionInverse( out outputValues, parameterList, out outLabels );
break;
case "MEAN":
Average( inputValues, out outputValues, out outLabels );
break;
case "VARIANCE":
Variance( inputValues, out outputValues, parameterList, out outLabels );
break;
case "MEDIAN":
Median( inputValues, out outputValues, out outLabels );
break;
case "BETAFUNCTION":
BetaFunction( out outputValues, parameterList, out outLabels );
break;
case "GAMMAFUNCTION":
GammaFunction( out outputValues, parameterList, out outLabels );
break;
default:
outputValues = null;
break;
}
}
catch( IndexOutOfRangeException )
{
throw new InvalidOperationException( SR.ExceptionFormulaInvalidPeriod(name) );
}
catch( OverflowException )
{
throw new InvalidOperationException( SR.ExceptionFormulaNotEnoughDataPoints(name) );
}
}
#endregion // Methods
#region Statistical Tests
/// <summary>
/// Anova test
/// </summary>
/// <param name="inputValues">Arrays of doubles - Input values</param>
/// <param name="outputValues">Arrays of doubles - Output values</param>
/// <param name="parameterList">Array of strings - Parameters</param>
/// <param name="outLabels">Array of strings - Used for Labels. Description for output results.</param>
private void Anova(double [][] inputValues, out double [][] outputValues, string [] parameterList, out string [][] outLabels )
{
// There is no enough input series
if( inputValues.Length < 3 )
throw new ArgumentException(SR.ExceptionStatisticalAnalysesNotEnoughInputSeries);
outLabels = null;
for( int index = 0; index < inputValues.Length - 1; index++ )
{
if( inputValues[index].Length != inputValues[index+1].Length )
throw new ArgumentException(SR.ExceptionStatisticalAnalysesInvalidAnovaTest);
}
// Alpha value
double alpha;
try
{
alpha = double.Parse( parameterList[0], System.Globalization.CultureInfo.InvariantCulture );
}
catch(System.Exception)
{
throw new ArgumentException(SR.ExceptionStatisticalAnalysesInvalidAlphaValue);
}
if( alpha < 0 || alpha > 1 )
{
throw new ArgumentOutOfRangeException(SR.ExceptionStatisticalAnalysesInvalidAlphaValue);
}
// Output arrays
outputValues = new double [2][];
// Output Labels
outLabels = new string [1][];
// Parameters description
outLabels[0] = new string [10];
// X
outputValues[0] = new double [10];
// Y
outputValues[1] = new double [10];
int m = inputValues.Length - 1;
int n = inputValues[0].Length;
double [] average = new double[ m ];
double [] variance = new double[ m ];
// Find averages
for( int group = 0; group < m; group++ )
{
average[group] = Mean( inputValues[group+1] );
}
// Find variances
for( int group = 0; group < m; group++ )
{
variance[group] = Variance( inputValues[group+1], true );
}
// Total Average ( for all groups )
double averageTotal = Mean( average );
// Total Sample Variance
double totalS = 0;
foreach( double avr in average )
{
totalS += ( avr - averageTotal ) * ( avr - averageTotal );
}
totalS /= ( m - 1 );
// Group Sample Variance
double groupS = Mean( variance );
// F Statistica
double f = totalS * ( n ) / groupS;
// ****************************************
// Sum of Squares
// ****************************************
// Grend Total Average
double grandTotalAverage = 0;
for( int group = 0; group < m; group++ )
{
foreach( double point in inputValues[group+1] )
{
grandTotalAverage += point;
}
}
grandTotalAverage /= ( m * n );
// Treatment Sum of Squares
double trss = 0;
for( int group = 0; group < m; group++ )
{
trss += ( average[group] - grandTotalAverage ) * ( average[group] - grandTotalAverage );
}
trss *= n;
// Error Sum of Squares
double erss = 0;
for( int group = 0; group < m; group++ )
{
foreach( double point in inputValues[group+1] )
{
erss += ( point - average[group] ) * ( point - average[group] );
}
}
outLabels[0][0] = SR.LabelStatisticalSumOfSquaresBetweenGroups;
outputValues[0][0] = 1;
outputValues[1][0] = trss;
outLabels[0][1] = SR.LabelStatisticalSumOfSquaresWithinGroups;
outputValues[0][1] = 2;
outputValues[1][1] = erss;
outLabels[0][2] = SR.LabelStatisticalSumOfSquaresTotal;
outputValues[0][2] = 3;
outputValues[1][2] = trss + erss;
outLabels[0][3] = SR.LabelStatisticalDegreesOfFreedomBetweenGroups;
outputValues[0][3] = 4;
outputValues[1][3] = m - 1;
outLabels[0][4] = SR.LabelStatisticalDegreesOfFreedomWithinGroups;
outputValues[0][4] = 5;
outputValues[1][4] = m * ( n - 1 );
outLabels[0][5] = SR.LabelStatisticalDegreesOfFreedomTotal;
outputValues[0][5] = 6;
outputValues[1][5] = m * n - 1;
outLabels[0][6] = SR.LabelStatisticalMeanSquareVarianceBetweenGroups;
outputValues[0][6] = 7;
outputValues[1][6] = trss / ( m - 1 );
outLabels[0][7] = SR.LabelStatisticalMeanSquareVarianceWithinGroups;
outputValues[0][7] = 8;
outputValues[1][7] = erss / ( m * ( n - 1 ) );
outLabels[0][8] = SR.LabelStatisticalFRatio;
outputValues[0][8] = 9;
outputValues[1][8] = f;
outLabels[0][9] = SR.LabelStatisticalFCriteria;
outputValues[0][9] = 10;
outputValues[1][9] = FDistributionInverse( alpha, m - 1, m * ( n - 1 ) );
}
/// <summary>
/// Correlation measure the relationship between two data sets that
/// are scaled to be independent of the unit of measurement. The
/// population correlation calculation returns the covariance
/// of two data sets divided by the product of their standard
/// deviations: You can use the Correlation to determine whether two
/// ranges of data move together — that is, whether large values of
/// one set are associated with large values of the other
/// (positive correlation), whether small values of one set are
/// associated with large values of the other (negative correlation),
/// or whether values in both sets are unrelated (correlation
/// near zero).
/// </summary>
/// <param name="inputValues">Arrays of doubles - Input values</param>
/// <param name="outputValues">Arrays of doubles - Output values</param>
/// <param name="outLabels">Array of strings - Used for Labels. Description for output results.</param>
private void Correlation(double [][] inputValues, out double [][] outputValues, out string [][] outLabels )
{
// There is no enough input series
if( inputValues.Length != 3 )
throw new ArgumentException( SR.ExceptionPriceIndicatorsFormulaRequiresTwoArrays);
outLabels = null;
// Output arrays
outputValues = new double [2][];
// Output Labels
outLabels = new string [1][];
// Parameters description
outLabels[0] = new string [1];
// X
outputValues[0] = new double [1];
// Y
outputValues[1] = new double [1];
// Find Covariance.
double covar = Covar( inputValues[1], inputValues[2] );
double varianceX = Variance( inputValues[1], false );
double varianceY = Variance( inputValues[2], false );
// Correlation
double correl = covar / Math.Sqrt( varianceX * varianceY );
outLabels[0][0] = SR.LabelStatisticalCorrelation;
outputValues[0][0] = 1;
outputValues[1][0] = correl;
}
/// <summary>
/// Returns covariance, the average of the products of deviations
/// for each data point pair. Use covariance to determine the
/// relationship between two data sets. For example, you can
/// examine whether greater income accompanies greater
/// levels of education.
/// </summary>
/// <param name="inputValues">Arrays of doubles - Input values</param>
/// <param name="outputValues">Arrays of doubles - Output values</param>
/// <param name="outLabels">Array of strings - Used for Labels. Description for output results.</param>
private void Covariance(double [][] inputValues, out double [][] outputValues, out string [][] outLabels )
{
// There is no enough input series
if( inputValues.Length != 3 )
throw new ArgumentException( SR.ExceptionPriceIndicatorsFormulaRequiresTwoArrays);
outLabels = null;
// Output arrays
outputValues = new double [2][];
// Output Labels
outLabels = new string [1][];
// Parameters description
outLabels[0] = new string [1];
// X
outputValues[0] = new double [1];
// Y
outputValues[1] = new double [1];
// Find Covariance.
double covar = Covar( inputValues[1], inputValues[2] );
outLabels[0][0] = SR.LabelStatisticalCovariance;
outputValues[0][0] = 1;
outputValues[1][0] = covar;
}
/// <summary>
/// Returns the result of an F-test. An F-test returns the one-tailed
/// probability that the variances in array1 and array2 are not
/// significantly different. Use this function to determine
/// whether two samples have different variances. For example,
/// given test scores from public and private schools, you can
/// test whether these schools have different levels of diversity.
/// </summary>
/// <param name="inputValues">Arrays of doubles - Input values</param>
/// <param name="outputValues">Arrays of doubles - Output values</param>
/// <param name="parameterList">Array of strings - Parameters</param>
/// <param name="outLabels">Array of strings - Used for Labels. Description for output results.</param>
private void FTest(double [][] inputValues, out double [][] outputValues, string [] parameterList, out string [][] outLabels )
{
// There is no enough input series
if( inputValues.Length != 3 )
throw new ArgumentException( SR.ExceptionPriceIndicatorsFormulaRequiresTwoArrays);
outLabels = null;
double alpha;
// The number of data points has to be > 1.
CheckNumOfPoints( inputValues );
// Alpha value
try
{
alpha = double.Parse( parameterList[0], System.Globalization.CultureInfo.InvariantCulture );
}
catch(System.Exception)
{
throw new ArgumentException(SR.ExceptionStatisticalAnalysesInvalidAlphaValue);
}
if( alpha < 0 || alpha > 1 )
{
throw new ArgumentOutOfRangeException(SR.ExceptionStatisticalAnalysesInvalidAlphaValue);
}
// Output arrays
outputValues = new double [2][];
// Output Labels
outLabels = new string [1][];
// Parameters description
outLabels[0] = new string [7];
// X
outputValues[0] = new double [7];
// Y
outputValues[1] = new double [7];
// Find Variance of the first group
double variance1 = Variance( inputValues[1], true );
// Find Variance of the second group
double variance2 = Variance( inputValues[2], true );
// Find Mean of the first group
double mean1 = Mean( inputValues[1] );
// Find Mean of the second group
double mean2 = Mean( inputValues[2] );
// F Value
double valueF = variance1 / variance2;
if( variance2 == 0 )
{
throw new InvalidOperationException(SR.ExceptionStatisticalAnalysesZeroVariance);
}
// The way to find a left critical value is to reversed the degrees of freedom,
// look up the right critical value, and then take the reciprocal of this value.
// For example, the critical value with 0.05 on the left with 12 numerator and 15
// denominator degrees of freedom is found of taking the reciprocal of the critical
// value with 0.05 on the right with 15 numerator and 12 denominator degrees of freedom.
// Avoiding Left Critical Values. Since the left critical values are a pain to calculate,
// they are often avoided altogether. This is the procedure followed in the textbook.
// You can force the F test into a right tail test by placing the sample with the large
// variance in the numerator and the smaller variance in the denominator. It does not
// matter which sample has the larger sample size, only which sample has the larger
// variance. The numerator degrees of freedom will be the degrees of freedom for
// whichever sample has the larger variance (since it is in the numerator) and the
// denominator degrees of freedom will be the degrees of freedom for whichever sample
// has the smaller variance (since it is in the denominator).
bool lessOneF = valueF <= 1;
double fDistInv;
double fDist;
if( lessOneF )
{
fDistInv = FDistributionInverse( 1 - alpha, inputValues[1].Length - 1, inputValues[2].Length - 1 );
fDist = 1 - FDistribution( valueF, inputValues[1].Length - 1, inputValues[2].Length - 1 );
}
else
{
fDistInv = FDistributionInverse( alpha, inputValues[1].Length - 1, inputValues[2].Length - 1 );
fDist = FDistribution( valueF, inputValues[1].Length - 1, inputValues[2].Length - 1 );
}
outLabels[0][0] = SR.LabelStatisticalTheFirstGroupMean;
outputValues[0][0] = 1;
outputValues[1][0] = mean1;
outLabels[0][1] = SR.LabelStatisticalTheSecondGroupMean;
outputValues[0][1] = 2;
outputValues[1][1] = mean2;
outLabels[0][2] = SR.LabelStatisticalTheFirstGroupVariance;
outputValues[0][2] = 3;
outputValues[1][2] = variance1;
outLabels[0][3] = SR.LabelStatisticalTheSecondGroupVariance;
outputValues[0][3] = 4;
outputValues[1][3] = variance2;
outLabels[0][4] = SR.LabelStatisticalFValue;
outputValues[0][4] = 5;
outputValues[1][4] = valueF;
outLabels[0][5] = SR.LabelStatisticalPFLessEqualSmallFOneTail;
outputValues[0][5] = 6;
outputValues[1][5] = fDist;
outLabels[0][6] = SR.LabelStatisticalFCriticalValueOneTail;
outputValues[0][6] = 7;
outputValues[1][6] = fDistInv;
}
/// <summary>
/// Returns the two-tailed P-value of a z-test. The z-test
/// generates a standard score for x with respect to the data set,
/// array, and returns the two-tailed probability for the
/// normal distribution. You can use this function to assess
/// the likelihood that a particular observation is drawn
/// from a particular population.
/// </summary>
/// <param name="inputValues">Arrays of doubles - Input values</param>
/// <param name="outputValues">Arrays of doubles - Output values</param>
/// <param name="parameterList">Array of strings - Parameters</param>
/// <param name="outLabels">Array of strings - Used for Labels. Description for output results.</param>
private void ZTest(double [][] inputValues, out double [][] outputValues, string [] parameterList, out string [][] outLabels )
{
// There is no enough input series
if( inputValues.Length != 3 )
throw new ArgumentException( SR.ExceptionPriceIndicatorsFormulaRequiresTwoArrays);
// The number of data points has to be > 1.
CheckNumOfPoints( inputValues );
outLabels = null;
double variance1;
double variance2;
double alpha;
double HypothesizedMeanDifference;
// Find Hypothesized Mean Difference parameter
try
{
HypothesizedMeanDifference = double.Parse( parameterList[0], System.Globalization.CultureInfo.InvariantCulture );
}
catch(System.Exception)
{
throw new ArgumentException(SR.ExceptionStatisticalAnalysesInvalidMeanDifference);
}
if( HypothesizedMeanDifference < 0.0 )
{
throw new ArgumentOutOfRangeException(SR.ExceptionStatisticalAnalysesNegativeMeanDifference);
}
// Find variance of the first group
try
{
variance1 = double.Parse( parameterList[1], System.Globalization.CultureInfo.InvariantCulture );
}
catch(System.Exception)
{
throw new ArgumentException(SR.ExceptionStatisticalAnalysesInvalidVariance);
}
// Find variance of the second group
try
{
variance2 = double.Parse( parameterList[2], System.Globalization.CultureInfo.InvariantCulture );
}
catch(System.Exception)
{
throw new ArgumentException(SR.ExceptionStatisticalAnalysesInvalidVariance);
}
// Alpha value
try
{
alpha = double.Parse( parameterList[3], System.Globalization.CultureInfo.InvariantCulture );
}
catch(System.Exception)
{
throw new ArgumentException(SR.ExceptionStatisticalAnalysesInvalidAlphaValue);
}
if( alpha < 0 || alpha > 1 )
{
throw new ArgumentOutOfRangeException(SR.ExceptionStatisticalAnalysesInvalidAlphaValue);
}
// Output arrays
outputValues = new double [2][];
// Output Labels
outLabels = new string [1][];
// Parameters description
outLabels[0] = new string [9];
// X
outputValues[0] = new double [9];
// Y
outputValues[1] = new double [9];
// Find Mean of the first group
double mean1 = Mean( inputValues[1] );
// Find Mean of the second group
double mean2 = Mean( inputValues[2] );
double dev = Math.Sqrt( variance1 / inputValues[1].Length + variance2 / inputValues[2].Length );
// Z Value
double valueZ = ( mean1 - mean2 - HypothesizedMeanDifference ) / dev;
double normalDistTwoInv = NormalDistributionInverse( 1 - alpha / 2 );
double normalDistOneInv = NormalDistributionInverse( 1 - alpha);
double normalDistOne;
double normalDistTwo;
if( valueZ < 0.0 )
{
normalDistOne = NormalDistribution( valueZ );
}
else
{
normalDistOne = 1.0 - NormalDistribution( valueZ );
}
normalDistTwo = 2.0 * normalDistOne;
outLabels[0][0] = SR.LabelStatisticalTheFirstGroupMean;
outputValues[0][0] = 1;
outputValues[1][0] = mean1;
outLabels[0][1] = SR.LabelStatisticalTheSecondGroupMean;
outputValues[0][1] = 2;
outputValues[1][1] = mean2;
outLabels[0][2] = SR.LabelStatisticalTheFirstGroupVariance;
outputValues[0][2] = 3;
outputValues[1][2] = variance1;
outLabels[0][3] = SR.LabelStatisticalTheSecondGroupVariance;
outputValues[0][3] = 4;
outputValues[1][3] = variance2;
outLabels[0][4] = SR.LabelStatisticalZValue;
outputValues[0][4] = 5;
outputValues[1][4] = valueZ;
outLabels[0][5] = SR.LabelStatisticalPZLessEqualSmallZOneTail;
outputValues[0][5] = 6;
outputValues[1][5] = normalDistOne;
outLabels[0][6] = SR.LabelStatisticalZCriticalValueOneTail;
outputValues[0][6] = 7;
outputValues[1][6] = normalDistOneInv;
outLabels[0][7] = SR.LabelStatisticalPZLessEqualSmallZTwoTail;
outputValues[0][7] = 8;
outputValues[1][7] = normalDistTwo;
outLabels[0][8] = SR.LabelStatisticalZCriticalValueTwoTail;
outputValues[0][8] = 9;
outputValues[1][8] = normalDistTwoInv;
}
/// <summary>
/// Returns the two-tailed P-value of a z-test. The z-test
/// generates a standard score for x with respect to the data set,
/// array, and returns the two-tailed probability for the
/// normal distribution. You can use this function to assess
/// the likelihood that a particular observation is drawn
/// from a particular population.
/// </summary>
/// <param name="inputValues">Arrays of doubles - Input values</param>
/// <param name="outputValues">Arrays of doubles - Output values</param>
/// <param name="parameterList">Array of strings - Parameters</param>
/// <param name="outLabels">Array of strings - Used for Labels. Description for output results.</param>
/// <param name="equalVariances">True if Variances are equal.</param>
private void TTest(double [][] inputValues, out double [][] outputValues, string [] parameterList, out string [][] outLabels, bool equalVariances )
{
// There is no enough input series
if( inputValues.Length != 3 )
throw new ArgumentException( SR.ExceptionPriceIndicatorsFormulaRequiresTwoArrays);
outLabels = null;
double variance1;
double variance2;
double alpha;
double HypothesizedMeanDifference;
// Find Hypothesized Mean Difference parameter
try
{
HypothesizedMeanDifference = double.Parse( parameterList[0], System.Globalization.CultureInfo.InvariantCulture );
}
catch(System.Exception)
{
throw new ArgumentException(SR.ExceptionStatisticalAnalysesInvalidMeanDifference);
}
if( HypothesizedMeanDifference < 0.0 )
{
throw new ArgumentOutOfRangeException(SR.ExceptionStatisticalAnalysesNegativeMeanDifference);
}
// Alpha value
try
{
alpha = double.Parse( parameterList[1], System.Globalization.CultureInfo.InvariantCulture );
}
catch(System.Exception)
{
throw new ArgumentException(SR.ExceptionStatisticalAnalysesInvalidAlphaValue);
}
if( alpha < 0 || alpha > 1 )
{
throw new ArgumentOutOfRangeException(SR.ExceptionStatisticalAnalysesInvalidAlphaValue);
}
// The number of data points has to be > 1.
CheckNumOfPoints( inputValues );
// Output arrays
outputValues = new double [2][];
// Output Labels
outLabels = new string [1][];
// Parameters description
outLabels[0] = new string [10];
// X
outputValues[0] = new double [10];
// Y
outputValues[1] = new double [10];
// Find Mean of the first group
double mean1 = Mean( inputValues[1] );
// Find Mean of the second group
double mean2 = Mean( inputValues[2] );
variance1 = Variance( inputValues[1], true );
variance2 = Variance( inputValues[2], true );
double s;
double T;
int freedom;
if( equalVariances )
{
freedom = inputValues[1].Length + inputValues[2].Length - 2;
// S value
s = ( ( inputValues[1].Length - 1 ) * variance1 + ( inputValues[2].Length - 1 ) * variance2 ) / ( inputValues[1].Length + inputValues[2].Length - 2 );
// T value
T = ( mean1 - mean2 - HypothesizedMeanDifference ) / ( Math.Sqrt( s * ( 1.0 / inputValues[1].Length + 1.0 / inputValues[2].Length ) ) );
}
else
{
double m = inputValues[1].Length;
double n = inputValues[2].Length;
double s1 = variance1;
double s2 = variance2;
double f = ( s1 / m + s2 / n ) * ( s1 / m + s2 / n ) / ( ( s1 / m ) * ( s1 / m ) / ( m - 1 ) + ( s2 / n ) * ( s2 / n ) / ( n - 1 ) );
freedom = (int)Math.Round(f);
s = Math.Sqrt( variance1 / inputValues[1].Length + variance2 / inputValues[2].Length );
// Z Value
T = ( mean1 - mean2 - HypothesizedMeanDifference ) / s;
}
double TDistTwoInv = StudentsDistributionInverse( alpha , freedom );
bool more50 = alpha > 0.5;
if( more50 )
{
alpha = 1 - alpha;
}
double TDistOneInv = StudentsDistributionInverse( alpha * 2.0, freedom );
if( more50 )
{
TDistOneInv *= -1.0;
}
double TDistTwo = StudentsDistribution( T, freedom, false );
double TDistOne = StudentsDistribution( T, freedom, true );
outLabels[0][0] = SR.LabelStatisticalTheFirstGroupMean;
outputValues[0][0] = 1;
outputValues[1][0] = mean1;
outLabels[0][1] = SR.LabelStatisticalTheSecondGroupMean;
outputValues[0][1] = 2;
outputValues[1][1] = mean2;
outLabels[0][2] = SR.LabelStatisticalTheFirstGroupVariance;
outputValues[0][2] = 3;
outputValues[1][2] = variance1;
outLabels[0][3] = SR.LabelStatisticalTheSecondGroupVariance;
outputValues[0][3] = 4;
outputValues[1][3] = variance2;
outLabels[0][4] = SR.LabelStatisticalTValue;
outputValues[0][4] = 5;
outputValues[1][4] = T;
outLabels[0][5] = SR.LabelStatisticalDegreeOfFreedom;
outputValues[0][5] = 6;
outputValues[1][5] = freedom;
outLabels[0][6] = SR.LabelStatisticalPTLessEqualSmallTOneTail;
outputValues[0][6] = 7;
outputValues[1][6] = TDistOne;
outLabels[0][7] = SR.LabelStatisticalSmallTCrititcalOneTail;
outputValues[0][7] = 8;
outputValues[1][7] = TDistOneInv;
outLabels[0][8] = SR.LabelStatisticalPTLessEqualSmallTTwoTail;
outputValues[0][8] = 9;
outputValues[1][8] = TDistTwo;
outLabels[0][9] = SR.LabelStatisticalSmallTCrititcalTwoTail;
outputValues[0][9] = 10;
outputValues[1][9] = TDistTwoInv;
}
/// <summary>
/// Returns the two-tailed P-value of a z-test. The z-test
/// generates a standard score for x with respect to the data set,
/// array, and returns the two-tailed probability for the
/// normal distribution. You can use this function to assess
/// the likelihood that a particular observation is drawn
/// from a particular population.
/// </summary>
/// <param name="inputValues">Arrays of doubles - Input values</param>
/// <param name="outputValues">Arrays of doubles - Output values</param>
/// <param name="parameterList">Array of strings - Parameters</param>
/// <param name="outLabels">Array of strings - Used for Labels. Description for output results.</param>
private void TTestPaired(double [][] inputValues, out double [][] outputValues, string [] parameterList, out string [][] outLabels )
{
// There is no enough input series
if( inputValues.Length != 3 )
throw new ArgumentException( SR.ExceptionPriceIndicatorsFormulaRequiresTwoArrays);
if( inputValues[1].Length != inputValues[2].Length )
throw new ArgumentException(SR.ExceptionStatisticalAnalysesInvalidVariableRanges);
outLabels = null;
double variance;
double alpha;
double HypothesizedMeanDifference;
int freedom;
// Find Hypothesized Mean Difference parameter
try
{
HypothesizedMeanDifference = double.Parse( parameterList[0], System.Globalization.CultureInfo.InvariantCulture );
}
catch(System.Exception)
{
throw new ArgumentException(SR.ExceptionStatisticalAnalysesInvalidMeanDifference);
}
if( HypothesizedMeanDifference < 0.0 )
{
throw new ArgumentOutOfRangeException(SR.ExceptionStatisticalAnalysesNegativeMeanDifference);
}
// Alpha value
try
{
alpha = double.Parse( parameterList[1], System.Globalization.CultureInfo.InvariantCulture );
}
catch(System.Exception)
{
throw new ArgumentException(SR.ExceptionStatisticalAnalysesInvalidAlphaValue);
}
if( alpha < 0 || alpha > 1 )
{
throw new ArgumentOutOfRangeException(SR.ExceptionStatisticalAnalysesInvalidAlphaValue);
}
// The number of data points has to be > 1.
CheckNumOfPoints( inputValues );
// Output arrays
outputValues = new double [2][];
// Output Labels
outLabels = new string [1][];
// Parameters description
outLabels[0] = new string [10];
// X
outputValues[0] = new double [10];
// Y
outputValues[1] = new double [10];
double [] difference = new double[inputValues[1].Length];
for( int item = 0; item < inputValues[1].Length; item++ )
{
difference[item] = inputValues[1][item] - inputValues[2][item];
}
// Find Mean of the second group
double mean = Mean( difference );
variance = Math.Sqrt( Variance( difference, true ) );
double T = ( Math.Sqrt( inputValues[1].Length ) * ( mean - HypothesizedMeanDifference ) ) / variance;
freedom = inputValues[1].Length - 1;
double TDistTwoInv = StudentsDistributionInverse( alpha , freedom );
double TDistOneInv = alpha <= 0.5 ? StudentsDistributionInverse(2 * alpha, freedom) : double.NaN;
double TDistTwo = StudentsDistribution( T, freedom, false );
double TDistOne = StudentsDistribution( T, freedom, true );
outLabels[0][0] = SR.LabelStatisticalTheFirstGroupMean;
outputValues[0][0] = 1;
outputValues[1][0] = Mean(inputValues[1]);
outLabels[0][1] = SR.LabelStatisticalTheSecondGroupMean;
outputValues[0][1] = 2;
outputValues[1][1] = Mean(inputValues[2]);
outLabels[0][2] = SR.LabelStatisticalTheFirstGroupVariance;
outputValues[0][2] = 3;
outputValues[1][2] = Variance(inputValues[1],true);
outLabels[0][3] = SR.LabelStatisticalTheSecondGroupVariance;
outputValues[0][3] = 4;
outputValues[1][3] = Variance(inputValues[2],true);
outLabels[0][4] = SR.LabelStatisticalTValue;
outputValues[0][4] = 5;
outputValues[1][4] = T;
outLabels[0][5] = SR.LabelStatisticalDegreeOfFreedom;
outputValues[0][5] = 6;
outputValues[1][5] = freedom;
outLabels[0][6] = SR.LabelStatisticalPTLessEqualSmallTOneTail;
outputValues[0][6] = 7;
outputValues[1][6] = TDistOne;
outLabels[0][7] = SR.LabelStatisticalSmallTCrititcalOneTail;
outputValues[0][7] = 8;
outputValues[1][7] = TDistOneInv;
outLabels[0][8] = SR.LabelStatisticalPTLessEqualSmallTTwoTail;
outputValues[0][8] = 9;
outputValues[1][8] = TDistTwo;
outLabels[0][9] = SR.LabelStatisticalSmallTCrititcalTwoTail;
outputValues[0][9] = 10;
outputValues[1][9] = TDistTwoInv;
}
#endregion // Statistical Tests
#region Public distributions
/// <summary>
/// Returns the Percentage Points (probability) for the Student
/// t-distribution. The t-distribution is used in the hypothesis
/// testing of small sample data sets. Use this function in place
/// of a table of critical values for the t-distribution.
/// </summary>
/// <param name="outputValues">Arrays of doubles - Output values</param>
/// <param name="parameterList">Array of strings - Parameters</param>
/// <param name="outLabels">Array of strings - Used for Labels. Description for output results.</param>
private void TDistribution(out double [][] outputValues, string [] parameterList, out string [][] outLabels )
{
// T value value
double tValue;
try
{
tValue = double.Parse( parameterList[0], System.Globalization.CultureInfo.InvariantCulture );
}
catch(System.Exception)
{
throw new ArgumentException(SR.ExceptionStatisticalAnalysesInvalidTValue);
}
// DegreeOfFreedom
int freedom;
try
{
freedom = int.Parse( parameterList[1], System.Globalization.CultureInfo.InvariantCulture );
}
catch(System.Exception)
{
throw new ArgumentException(SR.ExceptionStatisticalAnalysesInvalidDegreeOfFreedom);
}
// One Tailed distribution
int oneTailed;
try
{
oneTailed = int.Parse( parameterList[2], System.Globalization.CultureInfo.InvariantCulture );
}
catch(System.Exception)
{
throw new ArgumentException(SR.ExceptionStatisticalAnalysesInvalidTailedParameter);
}
outLabels = null;
// Output arrays
outputValues = new double [2][];
// Output Labels
outLabels = new string [1][];
// Parameters description
outLabels[0] = new string [1];
// X
outputValues[0] = new double [1];
// Y
outputValues[1] = new double [1];
outLabels[0][0] = SR.LabelStatisticalProbability;
outputValues[0][0] = 1;
outputValues[1][0] = StudentsDistribution( tValue, freedom, oneTailed == 1 );
}
/// <summary>
/// Returns the F probability distribution. You can use
/// this function to determine whether two data sets have
/// different degrees of diversity. For example, you can
/// examine test scores given to men and women entering
/// high school and determine if the variability in the
/// females is different from that found in the males.
/// </summary>
/// <param name="outputValues">Arrays of doubles - Output values</param>
/// <param name="parameterList">Array of strings - Parameters</param>
/// <param name="outLabels">Array of strings - Used for Labels. Description for output results.</param>
private void FDistribution(out double [][] outputValues, string [] parameterList, out string [][] outLabels )
{
// F value value
double fValue;
try
{
fValue = double.Parse( parameterList[0], System.Globalization.CultureInfo.InvariantCulture );
}
catch(System.Exception)
{
throw new ArgumentException(SR.ExceptionStatisticalAnalysesInvalidTValue);
}
// Degree Of Freedom 1
int freedom1;
try
{
freedom1 = int.Parse( parameterList[1], System.Globalization.CultureInfo.InvariantCulture );
}
catch(System.Exception)
{
throw new ArgumentException(SR.ExceptionStatisticalAnalysesInvalidDegreeOfFreedom);
}
// Degree Of Freedom 2
int freedom2;
try
{
freedom2 = int.Parse( parameterList[2], System.Globalization.CultureInfo.InvariantCulture );
}
catch(System.Exception)
{
throw new ArgumentException(SR.ExceptionStatisticalAnalysesInvalidDegreeOfFreedom);
}
outLabels = null;
// Output arrays
outputValues = new double [2][];
// Output Labels
outLabels = new string [1][];
// Parameters description
outLabels[0] = new string [1];
// X
outputValues[0] = new double [1];
// Y
outputValues[1] = new double [1];
outLabels[0][0] = SR.LabelStatisticalProbability;
outputValues[0][0] = 1;
outputValues[1][0] = FDistribution( fValue, freedom1, freedom2 );
}
/// <summary></summary>
/// <param name="outputValues">Arrays of doubles - Output values</param>
/// <param name="parameterList">Array of strings - Parameters</param>
/// <param name="outLabels">Array of strings - Used for Labels. Description for output results.</param>
private void NormalDistribution(out double [][] outputValues, string [] parameterList, out string [][] outLabels )
{
// F value value
double zValue;
try
{
zValue = double.Parse( parameterList[0], System.Globalization.CultureInfo.InvariantCulture );
}
catch(System.Exception)
{
throw new ArgumentException(SR.ExceptionStatisticalAnalysesInvalidZValue);
}
outLabels = null;
// Output arrays
outputValues = new double [2][];
// Output Labels
outLabels = new string [1][];
// Parameters description
outLabels[0] = new string [1];
// X
outputValues[0] = new double [1];
// Y
outputValues[1] = new double [1];
outLabels[0][0] = SR.LabelStatisticalProbability;
outputValues[0][0] = 1;
outputValues[1][0] = this.NormalDistribution( zValue );
}
/// <summary>
/// Returns the t-value of the Student's t-distribution
/// as a function of the probability and the degrees
/// of freedom.
/// </summary>
/// <param name="outputValues">Arrays of doubles - Output values</param>
/// <param name="parameterList">Array of strings - Parameters</param>
/// <param name="outLabels">Array of strings - Used for Labels. Description for output results.</param>
private void TDistributionInverse(out double [][] outputValues, string [] parameterList, out string [][] outLabels )
{
// T value value
double probability;
try
{
probability = double.Parse( parameterList[0], System.Globalization.CultureInfo.InvariantCulture );
}
catch(System.Exception)
{
throw new ArgumentException(SR.ExceptionStatisticalAnalysesInvalidProbabilityValue);
}
// DegreeOfFreedom
int freedom;
try
{
freedom = int.Parse( parameterList[1], System.Globalization.CultureInfo.InvariantCulture );
}
catch(System.Exception)
{
throw new ArgumentException(SR.ExceptionStatisticalAnalysesInvalidDegreeOfFreedom);
}
outLabels = null;
// Output arrays
outputValues = new double [2][];
// Output Labels
outLabels = new string [1][];
// Parameters description
outLabels[0] = new string [1];
// X
outputValues[0] = new double [1];
// Y
outputValues[1] = new double [1];
outLabels[0][0] = SR.LabelStatisticalProbability;
outputValues[0][0] = 1;
outputValues[1][0] = StudentsDistributionInverse( probability, freedom );
}
/// <summary>
/// Returns the inverse of the F probability distribution.
/// If p = FDIST(x,...), then FINV(p,...) = x. The F distribution
/// can be used in an F-test that compares the degree of
/// variability in two data sets. For example, you can analyze
/// income distributions in the United States and Canada to
/// determine whether the two ---- have a similar degree
/// of diversity.
/// </summary>
/// <param name="outputValues">Arrays of doubles - Output values</param>
/// <param name="parameterList">Array of strings - Parameters</param>
/// <param name="outLabels">Array of strings - Used for Labels. Description for output results.</param>
private void FDistributionInverse(out double [][] outputValues, string [] parameterList, out string [][] outLabels )
{
// Probability value value
double probability;
try
{
probability = double.Parse( parameterList[0], System.Globalization.CultureInfo.InvariantCulture );
}
catch(System.Exception)
{
throw new ArgumentException(SR.ExceptionStatisticalAnalysesInvalidProbabilityValue);
}
// Degree Of Freedom 1
int freedom1;
try
{
freedom1 = int.Parse( parameterList[1], System.Globalization.CultureInfo.InvariantCulture );
}
catch(System.Exception)
{
throw new ArgumentException(SR.ExceptionStatisticalAnalysesInvalidDegreeOfFreedom);
}
// Degree Of Freedom 2
int freedom2;
try
{
freedom2 = int.Parse( parameterList[2], System.Globalization.CultureInfo.InvariantCulture );
}
catch(System.Exception)
{
throw new ArgumentException(SR.ExceptionStatisticalAnalysesInvalidDegreeOfFreedom);
}
outLabels = null;
// Output arrays
outputValues = new double [2][];
// Output Labels
outLabels = new string [1][];
// Parameters description
outLabels[0] = new string [1];
// X
outputValues[0] = new double [1];
// Y
outputValues[1] = new double [1];
outLabels[0][0] = SR.LabelStatisticalProbability;
outputValues[0][0] = 1;
outputValues[1][0] = FDistributionInverse( probability, freedom1, freedom2 );
}
/// <summary>
/// Returns the inverse of the standard normal
/// cumulative distribution. The distribution
/// has a mean of zero and a standard deviation
/// of one.
/// </summary>
/// <param name="outputValues">Arrays of doubles - Output values</param>
/// <param name="parameterList">Array of strings - Parameters</param>
/// <param name="outLabels">Array of strings - Used for Labels. Description for output results.</param>
private void NormalDistributionInverse(out double [][] outputValues, string [] parameterList, out string [][] outLabels )
{
// Alpha value value
double alpha;
try
{
alpha = double.Parse( parameterList[0], System.Globalization.CultureInfo.InvariantCulture );
}
catch(System.Exception)
{
throw new ArgumentException(SR.ExceptionStatisticalAnalysesInvalidAlphaValue);
}
outLabels = null;
// Output arrays
outputValues = new double [2][];
// Output Labels
outLabels = new string [1][];
// Parameters description
outLabels[0] = new string [1];
// X
outputValues[0] = new double [1];
// Y
outputValues[1] = new double [1];
outLabels[0][0] = SR.LabelStatisticalProbability;
outputValues[0][0] = 1;
outputValues[1][0] = this.NormalDistributionInverse( alpha );
}
#endregion
#region Utility Statistical Functions
/// <summary>
/// Check number of data points. The number should be greater then 1.
/// </summary>
/// <param name="inputValues">Input series</param>
private void CheckNumOfPoints( double [][] inputValues )
{
if( inputValues[1].Length < 2 )
{
throw new ArgumentException(SR.ExceptionStatisticalAnalysesNotEnoughDataPoints);
}
if( inputValues.Length > 2 )
{
if( inputValues[2].Length < 2 )
{
throw new ArgumentException(SR.ExceptionStatisticalAnalysesNotEnoughDataPoints);
}
}
}
/// <summary>
/// Returns covariance, the average of the products of deviations
/// for each data point pair. Use covariance to determine the
/// relationship between two data sets. For example, you can
/// examine whether greater income accompanies greater
/// levels of education.
/// </summary>
/// <param name="arrayX">First data set from X random variable.</param>
/// <param name="arrayY">Second data set from Y random variable.</param>
/// <returns>Returns covariance</returns>
private double Covar( double [] arrayX, double [] arrayY )
{
// Check the number of data points
if( arrayX.Length != arrayY.Length )
{
throw new ArgumentException(SR.ExceptionStatisticalAnalysesCovariance);
}
double [] arrayXY = new double[arrayX.Length];
// Find XY
for( int index = 0; index < arrayX.Length; index++ )
{
arrayXY[index] = arrayX[index] * arrayY[index];
}
// Find means
double meanXY = Mean( arrayXY );
double meanX = Mean( arrayX );
double meanY = Mean( arrayY );
// return covariance
return meanXY - meanX * meanY;
}
/// <summary>
/// Returns the natural logarithm of the gamma function, G(x).
/// </summary>
/// <param name="n">The value for which you want to calculate gamma function.</param>
/// <returns>Returns the natural logarithm of the gamma function.</returns>
private double GammLn( double n )
{
double x;
double y;
double tmp;
double sum;
double [] cof = {76.18009172947146, -86.50532032941677, 24.01409824083091, -1.231739572450155, 0.1208650973866179e-2, -0.5395239384953e-5};
if( n < 0 )
{
throw new ArgumentOutOfRangeException(SR.ExceptionStatisticalAnalysesGammaBetaNegativeParameters);
}
// Iterative method for Gamma function
y = x = n;
tmp = x + 5.5;
tmp -= ( x + 0.5 ) * Math.Log( tmp );
sum = 1.000000000190015;
for( int item = 0; item <=5; item++ )
{
sum += cof[item] / ++y;
}
return -tmp + Math.Log( 2.5066282746310005 * sum / x );
}
/// <summary>
/// Calculates Beta function
/// </summary>
/// <param name="m">First parameter for beta function</param>
/// <param name="n">Second parameter for beta function</param>
/// <returns>returns beta function</returns>
private double BetaFunction( double m, double n )
{
return Math.Exp( GammLn( m ) + GammLn( n ) - GammLn( m + n ) );
}
/// <summary>
/// Used by betai: Evaluates continued fraction for
/// incomplete beta function by modified Lentzs
/// </summary>
/// <param name="a">Beta incomplete parameter</param>
/// <param name="b">Beta incomplete parameter</param>
/// <param name="x">Beta incomplete parameter</param>
/// <returns>Value used for Beta incomplete function</returns>
private double BetaCF( double a, double b, double x )
{
int MAXIT = 100;
double EPS = 3.0e-7;
double FPMIN = 1.0e-30;
int m,m2;
double aa,c,d,del,h,qab,qam,qap;
qab = a + b;
qap= a + 1.0;
qam = a - 1.0;
c = 1.0;
d = 1.0 - qab * x / qap;
if ( Math.Abs(d) < FPMIN ) d=FPMIN;
d = 1.0 / d;
h = d;
// Numerical approximation for Beta incomplete function
for( m=1; m<=MAXIT; m++ )
{
m2 = 2*m;
aa = m*(b-m)*x/((qam+m2)*(a+m2));
// Find d coeficient
d = 1.0 + aa*d;
if( Math.Abs(d) < FPMIN ) d=FPMIN;
// Find c coeficient
c = 1.0 + aa / c;
if( Math.Abs(c) < FPMIN ) c = FPMIN;
// Find d coeficient
d = 1.0 / d;
// Find h coeficient
h *= d*c;
aa = -(a+m)*(qab+m)*x/((a+m2)*(qap+m2));
// Recalc d coeficient
d=1.0+aa*d;
if (Math.Abs(d) < FPMIN) d=FPMIN;
// Recalc c coeficient
c=1.0+aa/c;
if (Math.Abs(c) < FPMIN) c=FPMIN;
// Recalc d coeficient
d=1.0/d;
del=d*c;
// Recalc h coeficient
h *= del;
if (Math.Abs(del-1.0) < EPS)
{
break;
}
}
if (m > MAXIT)
{
throw new InvalidOperationException(SR.ExceptionStatisticalAnalysesIncompleteBetaFunction);
}
return h;
}
/// <summary>
/// Standard normal density function
/// </summary>
/// <param name="t">T Value</param>
/// <returns>Standard normal density</returns>
private double NormalDistributionFunction(double t)
{
return 0.398942280401433 * Math.Exp( -t * t / 2 );
}
/// <summary>
/// Returns the incomplete beta function Ix(a, b).
/// </summary>
/// <param name="a">Beta incomplete parameter</param>
/// <param name="b">Beta incomplete parameter</param>
/// <param name="x">Beta incomplete parameter</param>
/// <returns>Beta Incomplete value</returns>
private double BetaIncomplete( double a, double b, double x )
{
double bt;
if (x < 0.0 || x > 1.0)
throw new ArgumentOutOfRangeException(SR.ExceptionStatisticalAnalysesInvalidInputParameter);
if (x == 0.0 || x == 1.0)
{
bt = 0.0;
}
else
{ // Factors in front of the continued fraction.
bt = Math.Exp(GammLn(a + b) - GammLn(a) - GammLn(b) + a * Math.Log(x) + b * Math.Log(1.0 - x));
}
if (x < (a + 1.0) / (a + b + 2.0))
{ //Use continued fraction directly.
return bt * BetaCF(a, b, x) / a;
}
else
{ // Use continued fraction after making the symmetry transformation.
return 1.0 - bt * BetaCF(b, a, 1.0 - x) / b;
}
}
#endregion // Utility Statistical Functions
#region Statistical Parameters
/// <summary>
/// Returns the average (arithmetic mean) of the arguments.
/// </summary>
/// <param name="inputValues">Arrays of doubles - Input values</param>
/// <param name="outputValues">Arrays of doubles - Output values</param>
/// <param name="outLabels">Array of strings - Used for Labels. Description for output results.</param>
private void Average(double [][] inputValues, out double [][] outputValues, out string [][] outLabels )
{
outLabels = null;
// Invalid number of data series
if( inputValues.Length != 2 )
throw new ArgumentException(SR.ExceptionStatisticalAnalysesInvalidSeriesNumber);
// Output arrays
outputValues = new double [2][];
// Output Labels
outLabels = new string [1][];
// Parameters description
outLabels[0] = new string [1];
// X
outputValues[0] = new double [1];
// Y
outputValues[1] = new double [1];
outLabels[0][0] = SR.LabelStatisticalAverage;
outputValues[0][0] = 1;
outputValues[1][0] = Mean( inputValues[1] );
}
/// <summary>
/// Calculates variance
/// </summary>
/// <param name="inputValues">Arrays of doubles - Input values</param>
/// <param name="outputValues">Arrays of doubles - Output values</param>
/// <param name="parameterList">Array of strings - Parameters</param>
/// <param name="outLabels">Array of strings - Used for Labels. Description for output results.</param>
private void Variance(double [][] inputValues, out double [][] outputValues, string [] parameterList, out string [][] outLabels )
{
// Sample Variance value
bool sampleVariance;
try
{
sampleVariance = bool.Parse( parameterList[0] );
}
catch(System.Exception)
{
throw new ArgumentException(SR.ExceptionStatisticalAnalysesInvalidVariance);
}
CheckNumOfPoints(inputValues);
// Invalid number of data series
if( inputValues.Length != 2 )
throw new ArgumentException(SR.ExceptionStatisticalAnalysesInvalidSeriesNumber);
outLabels = null;
// Output arrays
outputValues = new double [2][];
// Output Labels
outLabels = new string [1][];
// Parameters description
outLabels[0] = new string [1];
// X
outputValues[0] = new double [1];
// Y
outputValues[1] = new double [1];
outLabels[0][0] = SR.LabelStatisticalVariance;
outputValues[0][0] = 1;
outputValues[1][0] = Variance( inputValues[1], sampleVariance );
}
/// <summary>
/// Calculates Median
/// </summary>
/// <param name="inputValues">Arrays of doubles - Input values</param>
/// <param name="outputValues">Arrays of doubles - Output values</param>
/// <param name="outLabels">Array of strings - Used for Labels. Description for output results.</param>
private void Median(double [][] inputValues, out double [][] outputValues, out string [][] outLabels )
{
outLabels = null;
// Invalid number of data series
if( inputValues.Length != 2 )
throw new ArgumentException(SR.ExceptionStatisticalAnalysesInvalidSeriesNumber);
// Output arrays
outputValues = new double [2][];
// Output Labels
outLabels = new string [1][];
// Parameters description
outLabels[0] = new string [1];
// X
outputValues[0] = new double [1];
// Y
outputValues[1] = new double [1];
outLabels[0][0] = SR.LabelStatisticalMedian;
outputValues[0][0] = 1;
outputValues[1][0] = Median( inputValues[1] );
}
/// <summary>
/// Calculates Beta Function
/// </summary>
/// <param name="outputValues">Arrays of doubles - Output values</param>
/// <param name="parameterList">Array of strings - Parameters</param>
/// <param name="outLabels">Array of strings - Used for Labels. Description for output results.</param>
private void BetaFunction(out double [][] outputValues, string [] parameterList, out string [][] outLabels )
{
// Degree of freedom
double m;
try
{
m = double.Parse( parameterList[0], System.Globalization.CultureInfo.InvariantCulture );
}
catch(System.Exception)
{
throw new ArgumentException(SR.ExceptionStatisticalAnalysesInvalidDegreeOfFreedom);
}
// Degree of freedom
double n;
try
{
n = double.Parse( parameterList[1], System.Globalization.CultureInfo.InvariantCulture );
}
catch(System.Exception)
{
throw new ArgumentException(SR.ExceptionStatisticalAnalysesInvalidDegreeOfFreedom);
}
outLabels = null;
// Output arrays
outputValues = new double [2][];
// Output Labels
outLabels = new string [1][];
// Parameters description
outLabels[0] = new string [1];
// X
outputValues[0] = new double [1];
// Y
outputValues[1] = new double [1];
outLabels[0][0] = SR.LabelStatisticalBetaFunction;
outputValues[0][0] = 1;
outputValues[1][0] = BetaFunction( m, n );
}
/// <summary>
/// Calculates Gamma Function
/// </summary>
/// <param name="outputValues">Arrays of doubles - Output values</param>
/// <param name="parameterList">Array of strings - Parameters</param>
/// <param name="outLabels">Array of strings - Used for Labels. Description for output results.</param>
private void GammaFunction(out double [][] outputValues, string [] parameterList, out string [][] outLabels )
{
// Degree of freedom
double m;
try
{
m = double.Parse( parameterList[0], System.Globalization.CultureInfo.InvariantCulture );
}
catch(System.Exception)
{
throw new ArgumentException(SR.ExceptionStatisticalAnalysesInvalidInputParameter);
}
if( m < 0 )
{
throw new ArgumentOutOfRangeException(SR.ExceptionStatisticalAnalysesGammaBetaNegativeParameters);
}
outLabels = null;
// Output arrays
outputValues = new double [2][];
// Output Labels
outLabels = new string [1][];
// Parameters description
outLabels[0] = new string [1];
// X
outputValues[0] = new double [1];
// Y
outputValues[1] = new double [1];
outLabels[0][0] = SR.LabelStatisticalGammaFunction;
outputValues[0][0] = 1;
outputValues[1][0] = Math.Exp( GammLn( m ) );
}
/// <summary>
/// Sort array of double values.
/// </summary>
/// <param name="values">Array of doubles which should be sorted.</param>
private void Sort( ref double [] values )
{
double tempValue;
for( int outLoop = 0; outLoop < values.Length; outLoop++ )
{
for( int inLoop = outLoop + 1; inLoop < values.Length; inLoop++ )
{
if( values[ outLoop ] > values[ inLoop ] )
{
tempValue = values[ outLoop ];
values[ outLoop ] = values[ inLoop ];
values[ inLoop ] = tempValue;
}
}
}
}
/// <summary>
/// Returns the median of the given numbers
/// </summary>
/// <param name="values">Array of double numbers</param>
/// <returns>Median</returns>
private double Median( double [] values )
{
// Exception for zero lenght of series.
if( values.Length == 0 )
{
throw new ArgumentException(SR.ExceptionStatisticalAnalysesInvalidMedianConditions);
}
// Sort array
Sort( ref values );
int position = values.Length / 2;
// if number of points is even
if( values.Length % 2 == 0 )
{
return ( values[position-1] + values[position] ) / 2.0;
}
else
{
return values[position];
}
}
/// <summary>
/// Calculates a Mean for a series of numbers.
/// </summary>
/// <param name="values">series with double numbers</param>
/// <returns>Returns Mean</returns>
private double Mean( double [] values )
{
// Exception for zero lenght of series.
if( values.Length == 0 )
{
throw new ArgumentException(SR.ExceptionStatisticalAnalysesInvalidMeanConditions);
}
// Find sum of values
double sum = 0;
foreach( double item in values )
{
sum += item;
}
// Calculate Mean
return sum / values.Length;
}
/// <summary>
/// Calculates a Variance for a series of numbers.
/// </summary>
/// <param name="values">double values</param>
/// <param name="sampleVariance">If variance is calculated from sample sum has to be divided by n-1.</param>
/// <returns>Variance</returns>
private double Variance( double [] values, bool sampleVariance )
{
// Exception for zero lenght of series.
if( values.Length < 1 )
{
throw new ArgumentException(SR.ExceptionStatisticalAnalysesInvalidVarianceConditions);
}
// Find sum of values
double sum = 0;
double mean = Mean( values );
foreach( double item in values )
{
sum += (item - mean) * (item - mean);
}
// Calculate Variance
if( sampleVariance )
{
return sum / ( values.Length - 1 );
}
else
{
return sum / values.Length;
}
}
#endregion // Statistical Parameters
# region Distributions
/// <summary>
/// Calculates the Percentage Points (probability) for the Student
/// t-distribution. The t-distribution is used in the hypothesis
/// testing of small sample data sets. Use this function in place
/// of a table of critical values for the t-distribution.
/// </summary>
/// <param name="tValue">The numeric value at which to evaluate the distribution.</param>
/// <param name="n">An integer indicating the number of degrees of freedom.</param>
/// <param name="oneTailed">Specifies the number of distribution tails to return.</param>
/// <returns>Returns the Percentage Points (probability) for the Student t-distribution.</returns>
private double StudentsDistribution( double tValue, int n, bool oneTailed )
{
// Validation
tValue = Math.Abs( tValue );
if( n > 300 )
{
n = 300;
}
if( n < 1 )
{
throw new ArgumentOutOfRangeException(SR.ExceptionStatisticalAnalysesStudentsNegativeFreedomDegree);
}
double result = 1 - BetaIncomplete( n / 2.0, 0.5, n / (n + tValue * tValue) );
if( oneTailed )
return ( 1.0 - result ) / 2.0;
else
return 1.0 - result;
}
/// <summary>
/// Returns the standard normal cumulative distribution
/// function. The distribution has a mean of 0 (zero) and
/// a standard deviation of one. Use this function in place
/// of a table of standard normal curve areas.
/// </summary>
/// <param name="zValue">The value for which you want the distribution.</param>
/// <returns>Returns the standard normal cumulative distribution.</returns>
private double NormalDistribution( double zValue )
{
double [] a = {0.31938153,-0.356563782,1.781477937,-1.821255978,1.330274429};
double result;
if (zValue<-7.0)
{
result = NormalDistributionFunction(zValue)/Math.Sqrt(1.0+zValue*zValue);
}
else if (zValue>7.0)
{
result = 1.0 - NormalDistribution(-zValue);
}
else
{
result = 0.2316419;
result=1.0/(1+result*Math.Abs(zValue));
result=1-NormalDistributionFunction(zValue)*(result*(a[0]+result*(a[1]+result*(a[2]+result*(a[3]+result*a[4])))));
if (zValue<=0.0)
result=1.0-result;
}
return result;
}
private double FDistribution( double x, int freedom1, int freedom2 )
{
if (x < 0)
throw new ArgumentOutOfRangeException(SR.ExceptionStatisticalAnalysesInvalidTValue);
if (freedom1 <= 0)
throw new ArgumentOutOfRangeException(SR.ExceptionStatisticalAnalysesInvalidDegreeOfFreedom);
if (freedom2 <= 0)
throw new ArgumentOutOfRangeException(SR.ExceptionStatisticalAnalysesInvalidDegreeOfFreedom);
if (x == 0)
return 1;
if (x == double.PositiveInfinity)
return 0;
return BetaIncomplete( freedom2 / 2.0, freedom1 / 2.0, freedom2 / ( freedom2 + freedom1 * x ) );
}
#endregion // Distributions
# region Inverse Distributions
/// <summary>
/// Calculates the t-value of the Student's t-distribution
/// as a function of the probability and the degrees of freedom.
/// </summary>
/// <param name="probability">The probability associated with the two-tailed Student's t-distribution.</param>
/// <param name="n">The number of degrees of freedom to characterize the distribution.</param>
/// <returns>Returns the t-value of the Student's t-distribution.</returns>
private double StudentsDistributionInverse( double probability, int n )
{
//Fix for boundary cases
if (probability == 0)
return double.PositiveInfinity;
else if (probability == 1)
return 0;
else if (probability < 0 || probability > 1)
throw new ArgumentOutOfRangeException(SR.ExceptionStatisticalAnalysesInvalidProbabilityValue);
int step = 0;
return StudentsDistributionSearch( probability, n, step, 0.0, 100000.0 );
}
/// <summary>
/// Method for calculation of Inverse T Distribution (Binary tree)
/// solution for non linear equations
/// </summary>
/// <param name="probability">Probability value</param>
/// <param name="n">Degree of freedom</param>
/// <param name="step">Step for Numerical solution for non linear equations</param>
/// <param name="start">Start for numerical process</param>
/// <param name="end">End for numerical process</param>
/// <returns>Returns F ditribution inverse</returns>
private double StudentsDistributionSearch( double probability, int n, int step, double start, double end )
{
step++;
double mid = ( start + end ) / 2.0;
double result = StudentsDistribution( mid, n, false );
double resultX;
if( step > 100 )
{
return mid;
}
if( result <= probability )
{
resultX = StudentsDistributionSearch( probability, n, step, start, mid );
}
else
{
resultX = StudentsDistributionSearch( probability, n, step, mid, end );
}
return resultX;
}
/// <summary>
/// Returns the inverse of the standard normal cumulative distribution.
/// The distribution has a mean of zero and a standard deviation of one.
/// </summary>
/// <param name="probability">A probability corresponding to the normal distribution.</param>
/// <returns>Returns the inverse of the standard normal cumulative distribution.</returns>
private double NormalDistributionInverse( double probability )
{
// Validation
if( probability < 0.00001 || probability > 0.99999 )
{
throw new ArgumentOutOfRangeException(SR.ExceptionStatisticalAnalysesNormalInvalidProbabilityValue);
}
double [] a = { 2.50662823884, -18.61500062529, 41.39119773534, -25.44106049637 };
double [] b = { -8.47351093090, 23.08336743743, -21.06224101826, 3.13082909833 };
double [] c = { 0.3374754822726147, 0.9761690190917186, 0.1607979714918209, 0.0276438810333863, 0.0038405729373609, 0.0003951896511919, 0.0000321767881768, 0.0000002888167364, 0.0000003960315187};
double x,r;
// Numerical Integration
x = probability - 0.5;
if ( Math.Abs(x) < 0.42 )
{
r = x * x;
r = x * ( ( ( a[3] * r + a[2] ) * r + a[1] ) * r + a[0] ) / ( ( ( ( b[3] * r + b[2] ) * r + b[1] ) * r + b[0] ) * r + 1.0 );
return( r );
}
r= probability;
if( x > 0.0 )
{
r = 1.0 - probability;
}
r = Math.Log( -Math.Log( r ) );
r = c[0] + r * ( c[1] + r * ( c[2] + r * ( c[3] + r * ( c[4] + r * ( c[5] + r * ( c[6] + r * ( c[7]+r * c[8] ) ) ) ) ) ) );
if( x < 0.0 )
{
r = -r;
}
return r;
}
/// <summary>
/// Calculates the inverse of the F probability distribution.
/// The F distribution can be used in an F-test that compares
/// the degree of variability in two data sets.
/// </summary>
/// <param name="probability">A probability associated with the F cumulative distribution.</param>
/// <param name="m">The numerator degrees of freedom.</param>
/// <param name="n">The denominator degrees of freedom.</param>
/// <returns>Returns the inverse of the F probability distribution.</returns>
private double FDistributionInverse( double probability, int m, int n )
{
//Fix for boundary cases
if (probability == 0)
return double.PositiveInfinity;
else if (probability == 1)
return 0;
else if (probability < 0 || probability > 1)
throw new ArgumentOutOfRangeException(SR.ExceptionStatisticalAnalysesInvalidProbabilityValue);
int step = 0;
return FDistributionSearch( probability, m, n, step, 0.0, 10000.0 );
}
/// <summary>
/// Method for calculation of Inverse F Distribution (Binary tree)
/// solution for non linear equations
/// </summary>
/// <param name="probability">Probability value</param>
/// <param name="m">Degree of freedom</param>
/// <param name="n">Degree of freedom</param>
/// <param name="step">Step for solution for non linear equations.</param>
/// <param name="start">Start for numerical process</param>
/// <param name="end">End for numerical process</param>
/// <returns>Returns F ditribution inverse</returns>
private double FDistributionSearch( double probability, int m, int n, int step, double start, double end )
{
step++;
double mid = ( start + end ) / 2.0;
double result = FDistribution( mid, m, n );
double resultX;
if( step > 30 )
{
return mid;
}
if( result <= probability )
{
resultX = FDistributionSearch( probability, m, n, step, start, mid );
}
else
{
resultX = FDistributionSearch( probability, m, n, step, mid, end );
}
return resultX;
}
#endregion // Inverse Distributions
}
}