/// <summary> /// Constructs a new <see cref="TwoWayAnova"/>. /// </summary> /// /// <param name="samples">The samples.</param> /// <param name="firstFactorLabels">The first factor labels.</param> /// <param name="secondFactorLabels">The second factor labels.</param> /// <param name="type">The type of the analysis.</param> /// public TwoWayAnova(double[] samples, int[] firstFactorLabels, int[] secondFactorLabels, TwoWayAnovaModel type = TwoWayAnovaModel.Mixed) { FirstFactorSamples = firstFactorLabels.Max() + 1; SecondFactorSamples = secondFactorLabels.Max() + 1; List <double>[][] groups = new List <double> [FirstFactorSamples][]; for (int i = 0; i < groups.Length; i++) { groups[i] = new List <double> [SecondFactorSamples]; for (int j = 0; j < groups[i].Length; j++) { groups[i][j] = new List <double>(); } } for (int i = 0; i < samples.Length; i++) { int f = firstFactorLabels[i]; int s = secondFactorLabels[i]; groups[f][s].Add(samples[i]); } // Transform into array double[][][] sets = new double[FirstFactorSamples][][]; for (int i = 0; i < sets.Length; i++) { sets[i] = new double[SecondFactorSamples][]; for (int j = 0; j < sets[i].Length; j++) { sets[i][j] = groups[i][j].ToArray(); } } Replications = sets[0][0].Length; // Assert equal number of replicates for (int i = 0; i < sets.Length; i++) { for (int j = 0; j < sets[i].Length; j++) { if (sets[i][j].Length != Replications) { throw new ArgumentException("Samples do not have the same number of replicates.", "samples"); } } } initialize(sets, type); }
/// <summary> /// Constructs a new <see cref="TwoWayAnova"/>. /// </summary> /// /// <param name="samples">The samples in grouped form.</param> /// <param name="type">The type of the analysis.</param> /// public TwoWayAnova(double[][][] samples, TwoWayAnovaModel type = TwoWayAnovaModel.Mixed) { FirstFactorSamples = samples.Length; SecondFactorSamples = samples[0].Length; Replications = samples[0][0].Length; Observations = FirstFactorSamples * SecondFactorSamples * Replications; // Assert equal number of replicates for (int i = 0; i < samples.Length; i++) { for (int j = 0; j < samples[i].Length; j++) { if (samples[i][j].Length != Replications) { throw new ArgumentException("Samples do not have the same number of replicates.", "samples"); } } } initialize(samples, type); }
private void initialize(double[][][] samples, TwoWayAnovaModel type) { // References: // - http://www.smi.hst.aau.dk/~cdahl/BiostatPhD/ANOVA.pdf ModelType = type; Observations = FirstFactorSamples * SecondFactorSamples * Replications; // Step 1. Initialize all degrees of freedom int cellDegreesOfFreedom = FirstFactorSamples * SecondFactorSamples - 1; int aDegreesOfFreedom = FirstFactorSamples - 1; int bDegreesOfFreedom = SecondFactorSamples - 1; int abDegreesOfFreedom = cellDegreesOfFreedom - aDegreesOfFreedom - bDegreesOfFreedom; int errorDegreesOfFreedom = FirstFactorSamples * SecondFactorSamples * (Replications - 1); int totalDegreesOfFreedom = Observations - 1; // Step 1. Calculate cell means cellMeans = new double[FirstFactorSamples, SecondFactorSamples]; double sum = 0; for (int i = 0; i < samples.Length; i++) { for (int j = 0; j < samples[i].Length; j++) { sum += cellMeans[i, j] = Measures.Mean(samples[i][j]); } } // Step 2. Calculate the total mean (grand mean) totalMean = sum / (FirstFactorSamples * SecondFactorSamples); // Step 3. Calculate factor means aMean = new double[FirstFactorSamples]; for (int i = 0; i < samples.Length; i++) { sum = 0; for (int j = 0; j < samples[i].Length; j++) { for (int k = 0; k < samples[i][j].Length; k++) { sum += samples[i][j][k]; } } aMean[i] = sum / (SecondFactorSamples * Replications); } bMean = new double[SecondFactorSamples]; for (int j = 0; j < samples[0].Length; j++) { sum = 0; for (int i = 0; i < samples.Length; i++) { for (int k = 0; k < samples[i][j].Length; k++) { sum += samples[i][j][k]; } } bMean[j] = sum / (FirstFactorSamples * Replications); } // Step 4. Calculate total sum of squares double ssum = 0; for (int i = 0; i < samples.Length; i++) { for (int j = 0; j < samples[i].Length; j++) { for (int k = 0; k < samples[i][j].Length; k++) { double u = samples[i][j][k] - totalMean; ssum += u * u; } } } double totalSumOfSquares = ssum; // Step 5. Calculate the cell sum of squares ssum = 0; for (int i = 0; i < FirstFactorSamples; i++) { for (int j = 0; j < SecondFactorSamples; j++) { double u = cellMeans[i, j] - totalMean; ssum += u * u; } } double cellSumOfSquares = ssum * Replications; // Step 6. Compute within-cells error sum of squares ssum = 0; for (int i = 0; i < samples.Length; i++) { for (int j = 0; j < samples[i].Length; j++) { for (int k = 0; k < samples[i][j].Length; k++) { double u = samples[i][j][k] - cellMeans[i, j]; ssum += u * u; } } } double errorSumOfSquares = ssum; // Step 7. Compute factors sum of squares ssum = 0; for (int i = 0; i < aMean.Length; i++) { double u = aMean[i] - totalMean; ssum += u * u; } double aSumOfSquares = ssum * SecondFactorSamples * Replications; ssum = 0; for (int i = 0; i < bMean.Length; i++) { double u = bMean[i] - totalMean; ssum += u * u; } double bSumOfSquares = ssum * FirstFactorSamples * Replications; // Step 9. Compute interaction sum of squares double abSumOfSquares = cellSumOfSquares - aSumOfSquares - bSumOfSquares; // Step 10. Compute mean squares double aMeanSquares = aSumOfSquares / aDegreesOfFreedom; double bMeanSquares = bSumOfSquares / bDegreesOfFreedom; double abMeanSquares = abSumOfSquares / abDegreesOfFreedom; double errorMeanSquares = errorSumOfSquares / errorDegreesOfFreedom; // Step 10. Create the F-Statistics FTest aSignificance, bSignificance, abSignificance; if (type == TwoWayAnovaModel.Fixed) { // Model 1: Factors A and B fixed aSignificance = new FTest(aMeanSquares / abMeanSquares, aDegreesOfFreedom, abDegreesOfFreedom); bSignificance = new FTest(bMeanSquares / abMeanSquares, bDegreesOfFreedom, abDegreesOfFreedom); abSignificance = new FTest(abMeanSquares / errorMeanSquares, abDegreesOfFreedom, errorDegreesOfFreedom); } else if (type == TwoWayAnovaModel.Mixed) { // Model 2: Factors A and B random aSignificance = new FTest(aMeanSquares / errorMeanSquares, aDegreesOfFreedom, errorDegreesOfFreedom); bSignificance = new FTest(bMeanSquares / errorMeanSquares, bDegreesOfFreedom, errorDegreesOfFreedom); abSignificance = new FTest(abMeanSquares / errorMeanSquares, abDegreesOfFreedom, errorDegreesOfFreedom); } else if (type == TwoWayAnovaModel.Random) { // Model 3: Factor A fixed, factor B random aSignificance = new FTest(aMeanSquares / abMeanSquares, aDegreesOfFreedom, abDegreesOfFreedom); bSignificance = new FTest(bMeanSquares / errorMeanSquares, bDegreesOfFreedom, errorDegreesOfFreedom); abSignificance = new FTest(abMeanSquares / errorMeanSquares, abDegreesOfFreedom, errorDegreesOfFreedom); } else { throw new ArgumentException("Unhandled analysis type.", "type"); } // Step 11. Create the ANOVA table and sources AnovaVariationSource cell = new AnovaVariationSource(this, "Cells", cellSumOfSquares, cellDegreesOfFreedom); AnovaVariationSource a = new AnovaVariationSource(this, "Factor A", aSumOfSquares, aDegreesOfFreedom, aMeanSquares, aSignificance); AnovaVariationSource b = new AnovaVariationSource(this, "Factor B", bSumOfSquares, bDegreesOfFreedom, bMeanSquares, bSignificance); AnovaVariationSource ab = new AnovaVariationSource(this, "Interaction AxB", abSumOfSquares, abDegreesOfFreedom, abMeanSquares, abSignificance); AnovaVariationSource error = new AnovaVariationSource(this, "Within-cells (error)", errorSumOfSquares, errorDegreesOfFreedom, errorMeanSquares); AnovaVariationSource total = new AnovaVariationSource(this, "Total", totalSumOfSquares, totalDegreesOfFreedom); this.Sources = new TwoWayAnovaVariationSources() { Cells = cell, FactorA = a, FactorB = b, Interaction = ab, Error = error, Total = total }; this.Table = new AnovaSourceCollection(cell, a, b, ab, error, total); }
private void initialize(double[][][] samples, TwoWayAnovaModel type) { // References: // - http://www.smi.hst.aau.dk/~cdahl/BiostatPhD/ANOVA.pdf ModelType = type; Observations = FirstFactorSamples * SecondFactorSamples * Replications; // Step 1. Initialize all degrees of freedom int cellDegreesOfFreedom = FirstFactorSamples * SecondFactorSamples - 1; int aDegreesOfFreedom = FirstFactorSamples - 1; int bDegreesOfFreedom = SecondFactorSamples - 1; int abDegreesOfFreedom = cellDegreesOfFreedom - aDegreesOfFreedom - bDegreesOfFreedom; int errorDegreesOfFreedom = FirstFactorSamples * SecondFactorSamples * (Replications - 1); int totalDegreesOfFreedom = Observations - 1; // Step 1. Calculate cell means cellMeans = new double[FirstFactorSamples, SecondFactorSamples]; double sum = 0; for (int i = 0; i < samples.Length; i++) for (int j = 0; j < samples[i].Length; j++) sum += cellMeans[i, j] = Measures.Mean(samples[i][j]); // Step 2. Calculate the total mean (grand mean) totalMean = sum / (FirstFactorSamples * SecondFactorSamples); // Step 3. Calculate factor means aMean = new double[FirstFactorSamples]; for (int i = 0; i < samples.Length; i++) { sum = 0; for (int j = 0; j < samples[i].Length; j++) for (int k = 0; k < samples[i][j].Length; k++) sum += samples[i][j][k]; aMean[i] = sum / (SecondFactorSamples * Replications); } bMean = new double[SecondFactorSamples]; for (int j = 0; j < samples[0].Length; j++) { sum = 0; for (int i = 0; i < samples.Length; i++) for (int k = 0; k < samples[i][j].Length; k++) sum += samples[i][j][k]; bMean[j] = sum / (FirstFactorSamples * Replications); } // Step 4. Calculate total sum of squares double ssum = 0; for (int i = 0; i < samples.Length; i++) { for (int j = 0; j < samples[i].Length; j++) { for (int k = 0; k < samples[i][j].Length; k++) { double u = samples[i][j][k] - totalMean; ssum += u * u; } } } double totalSumOfSquares = ssum; // Step 5. Calculate the cell sum of squares ssum = 0; for (int i = 0; i < FirstFactorSamples; i++) { for (int j = 0; j < SecondFactorSamples; j++) { double u = cellMeans[i, j] - totalMean; ssum += u * u; } } double cellSumOfSquares = ssum * Replications; // Step 6. Compute within-cells error sum of squares ssum = 0; for (int i = 0; i < samples.Length; i++) { for (int j = 0; j < samples[i].Length; j++) { for (int k = 0; k < samples[i][j].Length; k++) { double u = samples[i][j][k] - cellMeans[i, j]; ssum += u * u; } } } double errorSumOfSquares = ssum; // Step 7. Compute factors sum of squares ssum = 0; for (int i = 0; i < aMean.Length; i++) { double u = aMean[i] - totalMean; ssum += u * u; } double aSumOfSquares = ssum * SecondFactorSamples * Replications; ssum = 0; for (int i = 0; i < bMean.Length; i++) { double u = bMean[i] - totalMean; ssum += u * u; } double bSumOfSquares = ssum * FirstFactorSamples * Replications; // Step 9. Compute interaction sum of squares double abSumOfSquares = cellSumOfSquares - aSumOfSquares - bSumOfSquares; // Step 10. Compute mean squares double aMeanSquares = aSumOfSquares / aDegreesOfFreedom; double bMeanSquares = bSumOfSquares / bDegreesOfFreedom; double abMeanSquares = abSumOfSquares / abDegreesOfFreedom; double errorMeanSquares = errorSumOfSquares / errorDegreesOfFreedom; // Step 10. Create the F-Statistics FTest aSignificance, bSignificance, abSignificance; if (type == TwoWayAnovaModel.Fixed) { // Model 1: Factors A and B fixed aSignificance = new FTest(aMeanSquares / abMeanSquares, aDegreesOfFreedom, abDegreesOfFreedom); bSignificance = new FTest(bMeanSquares / abMeanSquares, bDegreesOfFreedom, abDegreesOfFreedom); abSignificance = new FTest(abMeanSquares / errorMeanSquares, abDegreesOfFreedom, errorDegreesOfFreedom); } else if (type == TwoWayAnovaModel.Mixed) { // Model 2: Factors A and B random aSignificance = new FTest(aMeanSquares / errorMeanSquares, aDegreesOfFreedom, errorDegreesOfFreedom); bSignificance = new FTest(bMeanSquares / errorMeanSquares, bDegreesOfFreedom, errorDegreesOfFreedom); abSignificance = new FTest(abMeanSquares / errorMeanSquares, abDegreesOfFreedom, errorDegreesOfFreedom); } else if (type == TwoWayAnovaModel.Random) { // Model 3: Factor A fixed, factor B random aSignificance = new FTest(aMeanSquares / abMeanSquares, aDegreesOfFreedom, abDegreesOfFreedom); bSignificance = new FTest(bMeanSquares / errorMeanSquares, bDegreesOfFreedom, errorDegreesOfFreedom); abSignificance = new FTest(abMeanSquares / errorMeanSquares, abDegreesOfFreedom, errorDegreesOfFreedom); } else throw new ArgumentException("Unhandled analysis type.","type"); // Step 11. Create the ANOVA table and sources AnovaVariationSource cell = new AnovaVariationSource(this, "Cells", cellSumOfSquares, cellDegreesOfFreedom); AnovaVariationSource a = new AnovaVariationSource(this, "Factor A", aSumOfSquares, aDegreesOfFreedom, aMeanSquares, aSignificance); AnovaVariationSource b = new AnovaVariationSource(this, "Factor B", bSumOfSquares, bDegreesOfFreedom, bMeanSquares, bSignificance); AnovaVariationSource ab = new AnovaVariationSource(this, "Interaction AxB", abSumOfSquares, abDegreesOfFreedom, abMeanSquares, abSignificance); AnovaVariationSource error = new AnovaVariationSource(this, "Within-cells (error)", errorSumOfSquares, errorDegreesOfFreedom, errorMeanSquares); AnovaVariationSource total = new AnovaVariationSource(this, "Total", totalSumOfSquares, totalDegreesOfFreedom); this.Sources = new TwoWayAnovaVariationSources() { Cells = cell, FactorA = a, FactorB = b, Interaction = ab, Error = error, Total = total }; this.Table = new AnovaSourceCollection(cell, a, b, ab, error, total); }
/// <summary> /// Constructs a new <see cref="TwoWayAnova"/>. /// </summary> /// /// <param name="samples">The samples in grouped form.</param> /// <param name="type">The type of the analysis.</param> /// public TwoWayAnova(double[][][] samples, TwoWayAnovaModel type = TwoWayAnovaModel.Mixed) { FirstFactorSamples = samples.Length; SecondFactorSamples = samples[0].Length; Replications = samples[0][0].Length; Observations = FirstFactorSamples * SecondFactorSamples * Replications; // Assert equal number of replicates for (int i = 0; i < samples.Length; i++) for (int j = 0; j < samples[i].Length; j++) if (samples[i][j].Length != Replications) throw new ArgumentException("Samples do not have the same number of replicates.", "samples"); initialize(samples, type); }
/// <summary> /// Constructs a new <see cref="TwoWayAnova"/>. /// </summary> /// /// <param name="samples">The samples.</param> /// <param name="firstFactorLabels">The first factor labels.</param> /// <param name="secondFactorLabels">The second factor labels.</param> /// <param name="type">The type of the analysis.</param> /// public TwoWayAnova(double[] samples, int[] firstFactorLabels, int[] secondFactorLabels, TwoWayAnovaModel type = TwoWayAnovaModel.Mixed) { FirstFactorSamples = firstFactorLabels.Max() + 1; SecondFactorSamples = secondFactorLabels.Max() + 1; List<double>[][] groups = new List<double>[FirstFactorSamples][]; for (int i = 0; i < groups.Length; i++) { groups[i] = new List<double>[SecondFactorSamples]; for (int j = 0; j < groups[i].Length; j++) groups[i][j] = new List<double>(); } for (int i = 0; i < samples.Length; i++) { int f = firstFactorLabels[i]; int s = secondFactorLabels[i]; groups[f][s].Add(samples[i]); } // Transform into array double[][][] sets = new double[FirstFactorSamples][][]; for (int i = 0; i < sets.Length; i++) { sets[i] = new double[SecondFactorSamples][]; for (int j = 0; j < sets[i].Length; j++) sets[i][j] = groups[i][j].ToArray(); } Replications = sets[0][0].Length; // Assert equal number of replicates for (int i = 0; i < sets.Length; i++) for (int j = 0; j < sets[i].Length; j++) if (sets[i][j].Length != Replications) throw new ArgumentException("Samples do not have the same number of replicates.", "samples"); initialize(sets, type); }
/// <summary> /// Constructs a new <see cref="TwoWayAnova"/>. /// </summary> /// /// <param name="samples">The samples in grouped form.</param> /// <param name="type">The type of the analysis.</param> /// public TwoWayAnova(double[,,] samples, TwoWayAnovaModel type = TwoWayAnovaModel.Mixed) : this(jagged(samples), type) { }
private void initialize(double[][][] samples, TwoWayAnovaModel type) { // References: // - http://www.smi.hst.aau.dk/~cdahl/BiostatPhD/ANOVA.pdf ModelType = type; Observations = FirstFactorSamples * SecondFactorSamples * Replications; // Step 0. Initialize variables AnovaVariationSource cell = new AnovaVariationSource(this, "Cells"); AnovaVariationSource a = new AnovaVariationSource(this, "Factor A"); AnovaVariationSource b = new AnovaVariationSource(this, "Factor B"); AnovaVariationSource ab = new AnovaVariationSource(this, "Interaction AxB"); AnovaVariationSource error = new AnovaVariationSource(this, "Within-cells (error)"); AnovaVariationSource total = new AnovaVariationSource(this, "Total"); // Step 1. Initialize all degrees of freedom cell.DegreesOfFreedom = FirstFactorSamples * SecondFactorSamples - 1; a.DegreesOfFreedom = FirstFactorSamples - 1; b.DegreesOfFreedom = SecondFactorSamples - 1; ab.DegreesOfFreedom = cell.DegreesOfFreedom - a.DegreesOfFreedom - b.DegreesOfFreedom; error.DegreesOfFreedom = FirstFactorSamples * SecondFactorSamples * (Replications - 1); total.DegreesOfFreedom = Observations - 1; // Step 1. Calculate cell means cellMeans = new double[FirstFactorSamples, SecondFactorSamples]; double sum = 0; for (int i = 0; i < samples.Length; i++) { for (int j = 0; j < samples[i].Length; j++) { sum += cellMeans[i, j] = Statistics.Tools.Mean(samples[i][j]); } } // Step 2. Calculate the total mean (grand mean) totalMean = sum / (FirstFactorSamples * SecondFactorSamples); // Step 3. Calculate factor means aMean = new double[FirstFactorSamples]; for (int i = 0; i < samples.Length; i++) { sum = 0; for (int j = 0; j < samples[i].Length; j++) { for (int k = 0; k < samples[i][j].Length; k++) { sum += samples[i][j][k]; } } aMean[i] = sum / (SecondFactorSamples * Replications); } bMean = new double[SecondFactorSamples]; for (int j = 0; j < samples[0].Length; j++) { sum = 0; for (int i = 0; i < samples.Length; i++) { for (int k = 0; k < samples[i][j].Length; k++) { sum += samples[i][j][k]; } } bMean[j] = sum / (FirstFactorSamples * Replications); } // Step 4. Calculate total sum of squares double ssum = 0; for (int i = 0; i < samples.Length; i++) { for (int j = 0; j < samples[i].Length; j++) { for (int k = 0; k < samples[i][j].Length; k++) { double u = samples[i][j][k] - totalMean; ssum += u * u; } } } total.SumOfSquares = ssum; // Step 5. Calculate the cell sum of squares ssum = 0; for (int i = 0; i < FirstFactorSamples; i++) { for (int j = 0; j < SecondFactorSamples; j++) { double u = cellMeans[i, j] - totalMean; ssum += u * u; } } cell.SumOfSquares = ssum * Replications; // Step 6. Compute within-cells error sum of squares ssum = 0; for (int i = 0; i < samples.Length; i++) { for (int j = 0; j < samples[i].Length; j++) { for (int k = 0; k < samples[i][j].Length; k++) { double u = samples[i][j][k] - cellMeans[i, j]; ssum += u * u; } } } error.SumOfSquares = ssum; // Step 7. Compute factors sum of squares ssum = 0; for (int i = 0; i < aMean.Length; i++) { double u = aMean[i] - totalMean; ssum += u * u; } a.SumOfSquares = ssum * SecondFactorSamples * Replications; ssum = 0; for (int i = 0; i < bMean.Length; i++) { double u = bMean[i] - totalMean; ssum += u * u; } b.SumOfSquares = ssum * FirstFactorSamples * Replications; // Step 9. Compute interaction sum of squares ab.SumOfSquares = cell.SumOfSquares - a.SumOfSquares - b.SumOfSquares; // Step 10. Create the F-Statistics if (type == TwoWayAnovaModel.Fixed) { // Model 1: Factors A and B fixed a.Significance = new FTest(a.MeanSquares / ab.MeanSquares, a.DegreesOfFreedom, ab.DegreesOfFreedom); b.Significance = new FTest(b.MeanSquares / ab.MeanSquares, b.DegreesOfFreedom, ab.DegreesOfFreedom); ab.Significance = new FTest(ab.MeanSquares / error.MeanSquares, ab.DegreesOfFreedom, error.DegreesOfFreedom); } else if (type == TwoWayAnovaModel.Mixed) { // Model 2: Factors A and B random a.Significance = new FTest(a.MeanSquares / error.MeanSquares, a.DegreesOfFreedom, error.DegreesOfFreedom); b.Significance = new FTest(b.MeanSquares / error.MeanSquares, b.DegreesOfFreedom, error.DegreesOfFreedom); ab.Significance = new FTest(ab.MeanSquares / error.MeanSquares, ab.DegreesOfFreedom, error.DegreesOfFreedom); } else if (type == TwoWayAnovaModel.Random) { // Model 3: Factor A fixed, factor B random a.Significance = new FTest(a.MeanSquares / ab.MeanSquares, a.DegreesOfFreedom, ab.DegreesOfFreedom); b.Significance = new FTest(b.MeanSquares / error.MeanSquares, b.DegreesOfFreedom, error.DegreesOfFreedom); ab.Significance = new FTest(ab.MeanSquares / error.MeanSquares, ab.DegreesOfFreedom, error.DegreesOfFreedom); } // Step 10. Create the ANOVA table and sources this.Sources = new TwoWayAnovaVariationSources() { Cells = cell, FactorA = a, FactorB = b, Interaction = ab, Error = error, Total = total }; this.Table = new AnovaSourceCollection(cell, a, b, ab, error, total); }
private void initialize(double[][][] samples, TwoWayAnovaModel type) { // References: // - http://www.smi.hst.aau.dk/~cdahl/BiostatPhD/ANOVA.pdf ModelType = type; Observations = FirstFactorSamples * SecondFactorSamples * Replications; // Step 0. Initialize variables AnovaVariationSource cell = new AnovaVariationSource(this, "Cells"); AnovaVariationSource a = new AnovaVariationSource(this, "Factor A"); AnovaVariationSource b = new AnovaVariationSource(this, "Factor B"); AnovaVariationSource ab = new AnovaVariationSource(this, "Interaction AxB"); AnovaVariationSource error = new AnovaVariationSource(this, "Within-cells (error)"); AnovaVariationSource total = new AnovaVariationSource(this, "Total"); // Step 1. Initialize all degrees of freedom cell.DegreesOfFreedom = FirstFactorSamples * SecondFactorSamples - 1; a.DegreesOfFreedom = FirstFactorSamples - 1; b.DegreesOfFreedom = SecondFactorSamples - 1; ab.DegreesOfFreedom = cell.DegreesOfFreedom - a.DegreesOfFreedom - b.DegreesOfFreedom; error.DegreesOfFreedom = FirstFactorSamples * SecondFactorSamples * (Replications - 1); total.DegreesOfFreedom = Observations - 1; // Step 1. Calculate cell means cellMeans = new double[FirstFactorSamples, SecondFactorSamples]; double sum = 0; for (int i = 0; i < samples.Length; i++) for (int j = 0; j < samples[i].Length; j++) sum += cellMeans[i, j] = Statistics.Tools.Mean(samples[i][j]); // Step 2. Calculate the total mean (grand mean) totalMean = sum / (FirstFactorSamples * SecondFactorSamples); // Step 3. Calculate factor means aMean = new double[FirstFactorSamples]; for (int i = 0; i < samples.Length; i++) { sum = 0; for (int j = 0; j < samples[i].Length; j++) for (int k = 0; k < samples[i][j].Length; k++) sum += samples[i][j][k]; aMean[i] = sum / (SecondFactorSamples * Replications); } bMean = new double[SecondFactorSamples]; for (int j = 0; j < samples[0].Length; j++) { sum = 0; for (int i = 0; i < samples.Length; i++) for (int k = 0; k < samples[i][j].Length; k++) sum += samples[i][j][k]; bMean[j] = sum / (FirstFactorSamples * Replications); } // Step 4. Calculate total sum of squares double ssum = 0; for (int i = 0; i < samples.Length; i++) { for (int j = 0; j < samples[i].Length; j++) { for (int k = 0; k < samples[i][j].Length; k++) { double u = samples[i][j][k] - totalMean; ssum += u * u; } } } total.SumOfSquares = ssum; // Step 5. Calculate the cell sum of squares ssum = 0; for (int i = 0; i < FirstFactorSamples; i++) { for (int j = 0; j < SecondFactorSamples; j++) { double u = cellMeans[i, j] - totalMean; ssum += u * u; } } cell.SumOfSquares = ssum * Replications; // Step 6. Compute within-cells error sum of squares ssum = 0; for (int i = 0; i < samples.Length; i++) { for (int j = 0; j < samples[i].Length; j++) { for (int k = 0; k < samples[i][j].Length; k++) { double u = samples[i][j][k] - cellMeans[i, j]; ssum += u * u; } } } error.SumOfSquares = ssum; // Step 7. Compute factors sum of squares ssum = 0; for (int i = 0; i < aMean.Length; i++) { double u = aMean[i] - totalMean; ssum += u * u; } a.SumOfSquares = ssum * SecondFactorSamples * Replications; ssum = 0; for (int i = 0; i < bMean.Length; i++) { double u = bMean[i] - totalMean; ssum += u * u; } b.SumOfSquares = ssum * FirstFactorSamples * Replications; // Step 9. Compute interaction sum of squares ab.SumOfSquares = cell.SumOfSquares - a.SumOfSquares - b.SumOfSquares; // Step 10. Create the F-Statistics if (type == TwoWayAnovaModel.Fixed) { // Model 1: Factors A and B fixed a.Significance = new FTest(a.MeanSquares / ab.MeanSquares, a.DegreesOfFreedom, ab.DegreesOfFreedom); b.Significance = new FTest(b.MeanSquares / ab.MeanSquares, b.DegreesOfFreedom, ab.DegreesOfFreedom); ab.Significance = new FTest(ab.MeanSquares / error.MeanSquares, ab.DegreesOfFreedom, error.DegreesOfFreedom); } else if (type == TwoWayAnovaModel.Mixed) { // Model 2: Factors A and B random a.Significance = new FTest(a.MeanSquares / error.MeanSquares, a.DegreesOfFreedom, error.DegreesOfFreedom); b.Significance = new FTest(b.MeanSquares / error.MeanSquares, b.DegreesOfFreedom, error.DegreesOfFreedom); ab.Significance = new FTest(ab.MeanSquares / error.MeanSquares, ab.DegreesOfFreedom, error.DegreesOfFreedom); } else if (type == TwoWayAnovaModel.Random) { // Model 3: Factor A fixed, factor B random a.Significance = new FTest(a.MeanSquares / ab.MeanSquares, a.DegreesOfFreedom, ab.DegreesOfFreedom); b.Significance = new FTest(b.MeanSquares / error.MeanSquares, b.DegreesOfFreedom, error.DegreesOfFreedom); ab.Significance = new FTest(ab.MeanSquares / error.MeanSquares, ab.DegreesOfFreedom, error.DegreesOfFreedom); } // Step 10. Create the ANOVA table and sources this.Sources = new TwoWayAnovaVariationSources() { Cells = cell, FactorA = a, FactorB = b, Interaction = ab, Error = error, Total = total }; this.Table = new AnovaSourceCollection(cell, a, b, ab, error, total); }