using System; namespace CenterSpace.NMath.Examples.CSharp { /// <summary> /// A .NET example in C# showing some of the advanced features of the class /// TwoWayAnova. /// </summary> class AdvancedTwoWayAnovaExample { private static string materialColumnName_ = "Material"; private static string tempColumnName_ = "Temperature"; private static string lifetimeColumnName_ = "Lifetime"; static void Main( string[] args ) { // Create the DataFrame that will hold the data to analyze. The variable // being measured is battery lifetime. The two factors are material and // temperature. The data must have at least three columns. One column // must be numeric and contain the values of the variable being measured, // battery life in this case, the other two columns must contain the values // of the two factors that correspond to the measurement. Thus a row of the // the DataFrame that we are going to use contains a value for the battery // material (M1, M2, or M3), a temperature (15, 70, or 175), and a lifetime // (in hours). The method CreateBatteryData() builds the DataFrame. DataFrame batteryData = CreateBatteryData(); // Now create a TwoWayAnova object from the battery data. The three // integer arguments indicate the following column indices, respectively: // index of the column containing factor A, index of the column containing /// factor B, index of the column containing the measured values. var anova = new TwoWayAnova( batteryData, 0, 1, 2 ); // Class TwoWayAnova provides access to the data in a particular // cell. A cell is defined by the values of the two factors. For // example, the following code prints out all the battery lifetimes // for batteries made from material M2 at temperature 70. DFNumericColumn mTwoSeventyValues = anova.GetCellData( materialColumnName_, "M2", tempColumnName_, "70" ); Console.WriteLine(); Console.WriteLine( "Lifetimes of M2 batteries at 70 degrees: {0}", mTwoSeventyValues ); // You can also get the means for each cell: double mean = anova.GetMeanForCell( materialColumnName_, "M2", tempColumnName_, "70" ); Console.WriteLine( "Mean lifetime of M2 batteries at 70 degrees: {0}", mean ); // Means for a given factor level can also be accessed. For example, the // following code gets the mean lifetime for all batteries made from material // M1 mean = anova.GetMeanForFactorLevel( materialColumnName_, "M1" ); Console.WriteLine( "Mean lifetime for M1 batteries = {0}", mean ); // You can also get the grand mean. Console.WriteLine( "Overall mean lifetime is {0}", anova.GrandMean ); // The TwoWayAnovaTable class is used to access all the traditional // two way ANOVA data. TwoWayAnovaTable anovaTable = anova.AnovaTable; Console.WriteLine( Environment.NewLine + "Source: " + materialColumnName_ ); Console.WriteLine( " Degrees of Freedom: {0}", anovaTable.DegreesOfFreedom( materialColumnName_ ) ); Console.WriteLine( " Sum of Squares : {0}", anovaTable.SumOfSquares( materialColumnName_ ) ); Console.WriteLine( " Mean Square : {0}", anovaTable.MeanSquare( materialColumnName_ ) ); Console.WriteLine( " F : {0}", anovaTable.Fstatistic( materialColumnName_ ) ); Console.WriteLine( " P : {0}", anovaTable.FstatisticPvalue( materialColumnName_ ) ); Console.WriteLine( Environment.NewLine + "Source: " + tempColumnName_ ); Console.WriteLine( " Degrees of Freedom: {0}", anovaTable.DegreesOfFreedom( tempColumnName_ ) ); Console.WriteLine( " Sum of Squares : {0}", anovaTable.SumOfSquares( tempColumnName_ ) ); Console.WriteLine( " Mean Square : {0}", anovaTable.MeanSquare( tempColumnName_ ) ); Console.WriteLine( " F : {0}", anovaTable.Fstatistic( tempColumnName_ ) ); Console.WriteLine( " P : {0}", anovaTable.FstatisticPvalue( tempColumnName_ ) ); Console.WriteLine( Environment.NewLine + "Source: Interaction" ); Console.WriteLine( " Degrees of Freedom: {0}", anovaTable.InteractionDegreesOfFreedom ); Console.WriteLine( " Sum of Squares : {0}", anovaTable.InteractionSumOfSquares ); Console.WriteLine( " Mean Square : {0}", anovaTable.InteractionMeanSquare ); Console.WriteLine( " F : {0}", anovaTable.InteractionFstatistic ); Console.WriteLine( " P : {0}", anovaTable.InteractionFstatisticPvalue ); Console.WriteLine( Environment.NewLine + "Source: Error" ); Console.WriteLine( " Degrees of Freedom: {0}", anovaTable.ErrorDegreesOfFreedom ); Console.WriteLine( " Sum of Squares : {0}", anovaTable.ErrorSumOfSquares ); Console.WriteLine( " Mean Square : {0}", anovaTable.ErrorMeanSquare ); Console.WriteLine( Environment.NewLine + "Total" ); Console.WriteLine( " Degrees of Freedom: {0}", anovaTable.TotalDegreesOfFreedom ); Console.WriteLine( " Sum of Squares : {0}", anovaTable.TotalSumOfSquares ); // Class TwoWayAnova computes a two way ANOVA using a multiple linear // regression. The following function prints out details of the regression. // See the function WriteRegressionInfo() for more information. Console.WriteLine( Environment.NewLine + "-------- Regression Information -----------" ); WriteRegressionInfo( anova ); Console.WriteLine(); Console.WriteLine( "Press Enter Key" ); Console.Read(); } /// <summary> /// Two way ANOVAs are computed using a multiple linear regression. The /// details of this regression are available from the TwoWayAnova class. /// This functions shows how to access these details and sends the /// information to the Console. /// </summary> /// <param name="anova">ANOVA to process.</param> private static void WriteRegressionInfo( TwoWayAnova anova ) { // A multiple linear regression is used to solve a two way ANOVA // problem by creating dummy variables using an encoding. The // TwoWayAnova class uses "effects" encoding to accomplish this. // In effects encoding we define k - 1 dummy variables to encode // k levels of the factor in interest. A dummy variable di for the // the ith level is then defined as // // di = 1 if ith level, // di = -1 if kth level, // di = 0 otherwise // // If factor A has k levels, and factor B has m levels, there will also // be (k - 1) * (m - 1) interaction variables in the regression. It // follows that there will not be a regression parameter for every factor // level, or interaction. In the code below you will notice that we check // for a null return value when attempting to retrieve a regression // parameter object for a particular factor level or interaction of // factor levels. This is the reason. // First print out information for the intercept parameter. The class // AnovaRegressionParameter is derived from LinearRegressionParameter. // It merely adds the SumOfSquares property. AnovaRegressionParameter interceptParam = anova.RegressionInterceptParameter; Console.WriteLine( Environment.NewLine + "Parameter: Intercept" ); Console.WriteLine( " Estimate : {0}", interceptParam.Value ); Console.WriteLine( " Standard Error : {0}", interceptParam.StandardError ); Console.WriteLine( " T for H0 Parameter = 0: {0}", interceptParam.TStatistic( 0 ) ); Console.WriteLine( " Prob > |T| : {0}", interceptParam.TStatisticPValue( 0 ) ); Console.WriteLine( " Type I SS : {0}", interceptParam.SumOfSquares ); Console.WriteLine( " Variable Label: INTERCEPT" + Environment.NewLine ); // Next print out information for the Material factor parameters. Since there // is one less parameters than there are levels, well have to check for null // return values from GetRegressionFactorParameter(). // AnovaRegressionFactorParam is derived from AnovaRegressionParameter, and // hence from LinearRegressionParameter, adding the Encoding property. AnovaRegressionFactorParam factorParam; string[] materialLevels = { "M1", "M2", "M3" }; for ( int i = 0; i < materialLevels.Length; ++i ) { factorParam = anova.GetRegressionFactorParameter( materialColumnName_, materialLevels[i] ); if ( factorParam == null ) { continue; } Console.WriteLine( string.Format( "Parameter: {0}", materialLevels[i] ) ); Console.WriteLine( " Estimate : {0}", factorParam.Value ); Console.WriteLine( " Standard Error : {0}", factorParam.StandardError ); Console.WriteLine( " T for H0 Parameter = 0: {0}", factorParam.TStatistic( 0 ) ); Console.WriteLine( " Prob > |T| : {0}", factorParam.TStatisticPValue( 0 ) ); Console.WriteLine( " Type I SS : {0}", factorParam.SumOfSquares ); string encoding = string.Format( " Variable Label: dummy variable = {0} if {1} = {2}", factorParam.Encoding, materialColumnName_, materialLevels[i] ); Console.WriteLine( encoding + Environment.NewLine ); } // Now, do the same for the temperature factor parameter. string[] tempLevels = { "15", "70", "125" }; for ( int i = 0; i < materialLevels.Length; ++i ) { factorParam = anova.GetRegressionFactorParameter( tempColumnName_, tempLevels[i] ); if ( factorParam == null ) { continue; } Console.WriteLine( string.Format( "Parameter: {0}", tempLevels[i] ) ); Console.WriteLine( " Estimate : {0}", factorParam.Value ); Console.WriteLine( " Standard Error : {0}", factorParam.StandardError ); Console.WriteLine( " T for H0 Parameter = 0: {0}", factorParam.TStatistic( 0 ) ); Console.WriteLine( " Prob > |T| : {0}", factorParam.TStatisticPValue( 0 ) ); Console.WriteLine( " Type I SS : {0}", factorParam.SumOfSquares ); string encoding = string.Format( " Variable Label: dummy variable = {0} if {1} = {2}", factorParam.Encoding, tempColumnName_, tempLevels[i] ); Console.WriteLine( encoding + Environment.NewLine ); } // Finally, print out information for the interaction parameters. // AnovaRegressionInteractionParam is derived from AnovaRegressionParameter, and // hence from LinearRegressionParameter. It does not contain an Encoding // property. The value of the interaction variables is just the product of // the values of their corresponding factor variables. AnovaRegressionInteractionParam interactionParam; for ( int i = 0; i < materialLevels.Length; ++i ) { for ( int j = 0; j < tempLevels.Length; ++j ) { interactionParam = anova.GetRegressionInteractionParameter( materialColumnName_, materialLevels[i], tempColumnName_, tempLevels[j] ); if ( interactionParam == null ) { continue; } Console.WriteLine( string.Format( "Parameter: {0}, {1}", materialLevels[i], tempLevels[j] ) ); Console.WriteLine( " Estimate : {0}", interactionParam.Value ); Console.WriteLine( " Standard Error : {0}", interactionParam.StandardError ); Console.WriteLine( " T for H0 Parameter = 0: {0}", interactionParam.TStatistic( 0 ) ); Console.WriteLine( " Prob > |T| : {0}", interactionParam.TStatisticPValue( 0 ) ); Console.WriteLine( " Type I SS : {0}", interactionParam.SumOfSquares ); string encoding = string.Format( " Variable Label: interaction of {0} and {1}", materialLevels[i], tempLevels[j] ); Console.WriteLine( encoding + Environment.NewLine ); } } } private static DataFrame CreateBatteryData() { var data = new DataFrame(); data.AddColumn( new DFStringColumn( materialColumnName_ ) ); data.AddColumn( new DFStringColumn( tempColumnName_ ) ); var batteryLifetimeColumn = new DFIntColumn( lifetimeColumnName_ ); data.AddColumn( batteryLifetimeColumn ); int rowNumber = 0; data.AddRow( ++rowNumber, "M1", "15", 130 ); data.AddRow( ++rowNumber, "M1", "15", 155 ); data.AddRow( ++rowNumber, "M1", "15", 74 ); data.AddRow( ++rowNumber, "M1", "15", 180 ); data.AddRow( ++rowNumber, "M1", "70", 34 ); data.AddRow( ++rowNumber, "M1", "70", 40 ); data.AddRow( ++rowNumber, "M1", "70", 80 ); data.AddRow( ++rowNumber, "M1", "70", 75 ); data.AddRow( ++rowNumber, "M1", "125", 20 ); data.AddRow( ++rowNumber, "M1", "125", 70 ); data.AddRow( ++rowNumber, "M1", "125", 82 ); data.AddRow( ++rowNumber, "M1", "125", 58 ); data.AddRow( ++rowNumber, "M2", "15", 150 ); data.AddRow( ++rowNumber, "M2", "15", 188 ); data.AddRow( ++rowNumber, "M2", "15", 159 ); data.AddRow( ++rowNumber, "M2", "15", 126 ); data.AddRow( ++rowNumber, "M2", "70", 136 ); data.AddRow( ++rowNumber, "M2", "70", 122 ); data.AddRow( ++rowNumber, "M2", "70", 106 ); data.AddRow( ++rowNumber, "M2", "70", 115 ); data.AddRow( ++rowNumber, "M2", "125", 25 ); data.AddRow( ++rowNumber, "M2", "125", 70 ); data.AddRow( ++rowNumber, "M2", "125", 58 ); data.AddRow( ++rowNumber, "M2", "125", 45 ); data.AddRow( ++rowNumber, "M3", "15", 138 ); data.AddRow( ++rowNumber, "M3", "15", 110 ); data.AddRow( ++rowNumber, "M3", "15", 168 ); data.AddRow( ++rowNumber, "M3", "15", 160 ); data.AddRow( ++rowNumber, "M3", "70", 174 ); data.AddRow( ++rowNumber, "M3", "70", 120 ); data.AddRow( ++rowNumber, "M3", "70", 150 ); data.AddRow( ++rowNumber, "M3", "70", 139 ); data.AddRow( ++rowNumber, "M3", "125", 96 ); data.AddRow( ++rowNumber, "M3", "125", 104 ); data.AddRow( ++rowNumber, "M3", "125", 82 ); data.AddRow( ++rowNumber, "M3", "125", 60 ); return data; } } // class } // namespace← All NMath Code Examples