The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

Statistics::ANOVA - Parametric and nonparametric 1-way analyses of variance for means-comparison and clustering per differences/trends over independent or repeated measures of groups or levels

VERSION

This is documentation for Version 0.08 of Statistics::ANOVA.

SYNOPSIS

 use Statistics::ANOVA 0.08;
 my $aov = Statistics::ANOVA->new();

 # Some data:
 my @gp1 = (qw/8 7 11 14 9/);
 my @gp2 = (qw/11 9 8 11 13/);

 # Load the data (names should be stringy or numerical, depending on level of measurement):
 $aov->load_data({1 => \@gp1, 2 => \@gp2}); # NB: hashref
 # or $aov->load_data([ [1, \@gp1], [2, \@gp2] ]);
 # or $aov->load_data([ [1, @gp1], [2, @gp2] ]);

 # Now here comes another one - too late for just comparing the two:
 my @gp3 = (qw/7 13 12 8 10/);
 $aov->add_data(3 => \@gp3);
 
 # All loaded as Statistics::Descriptive objects in hash named "data", so, e.g.,
 printf("Mean for Group $_ = %.2f\n", $aov->{'data'}->{$_}->mean) foreach sort {$a cmp $b} keys %{$aov->{'data'}};

 #  Test equality of variances before omnibus comparison:
 $aov->obrien()->dump(title => 'O\'Brien\'s test of equality of variances');
 $aov->levene()->dump(title => 'Levene\'s test of equality of variances');

 # 1.10 Independent nominal groups ANOVA - parametric testing:
 $aov->anova(independent => 1, parametric => 1)->dump(title => 'Indep. groups parametric ANOVA', eta_squared => 1, omega_squared => 1);
 # 1.11 Independent nominal groups ANOVA - NON-parametric:
 $aov->anova(independent => 1, parametric => 0)->dump(title => 'Kruskal-Wallis test');

 #  or if independent AND ordered groups/levels: test linear/non-linear trend:
 # 1.20 Independent ordinal groups ANOVA - parametric testing:
 $aov->anova(independent => 1, parametric => 1, ordinal => 1)->dump(title => 'Indep. groups parametric ANOVA: Linear trend');
 $aov->anova(independent => 1, parametric => 1, ordinal => -1)->dump(title => 'Indep. groups parametric ANOVA: Non-linear trend');
 # 1.21 Independent ordinal groups ANOVA - NONparametric testing:
 $aov->anova(independent => 1, parametric => 0, ordinal => 1)->dump(title => 'Jonckheere-Terpstra test');
 
 #  If they are repeated measures:
 # 2.10 Dependent nominal groups ANOVA - parametric testing:
 $aov->anova(independent => 0, parametric => 1)->dump(title => 'Dependent groups ANOVA');
 # 2.11 Dependent nominal groups ANOVA - NONparametric testing:
 $aov->anova(independent => 0, parametric => 0, f_equiv => 0)->dump(title => 'Friedman test');
 
 # or if repeated AND ordinal measures:
 # 2.20 Dependent ordinal groups ANOVA - parametric testing: NOT yet IMPLEMENTED
 #$aov->anova(independent => 0, parametric => 1)->dump(title => '');
 # 2.21 Dependent ordinal groups test - NONparametric testing:
 $aov->anova(independent => 0, parametric => 0, ordinal => 1, f_equiv => 0)->dump(title => 'Page test');

 # Get pairwise comparisons (nominality of the factor assumed):
 $aov->compare(independent => 1, parametric => 1, flag => 1, alpha => .05, dump => 1); # Indep. obs. F- (or t-)tests
 $aov->compare(independent => 0, parametric => 1, flag => 1, alpha => .05, dump => 1); # Paired obs. F (or t-)tests
 $aov->compare(independent => 1, parametric => 0, flag => 1, alpha => .05, dump => 1); # Wilcoxon (between-groups) sum-of-ranks (Dwass Procedure)
 $aov->compare(independent => 0, parametric => 0, flag => 1, alpha => .05, dump => 1); # Friedman-type (within-groups) sum-of-ranks
 
 # Cluster analysis: the least variant of all possible first-order binary-splits of the data (indep. assumed):
 $aov->cluster(parametric => 1, dump => 1); # Scott-Knott method (default)
 $aov->cluster(parametric => 0, dump => 1); # Worsley method

 print $aov->table(precision_p => 3, precision_s => 3);
 
 $aov->unload('g3'); # back to 2 datasets (g1 and g2) - each Statistics::Descriptive objects

DESCRIPTION

By setting the extended Boolean (0, 1 or -1) value of only three parameters (independent, parametric and ordinal), this module gives you oneway parametric or non-parametric analyses-of-variance (ANOVAs) for either nominal groups or ordinal levels (trend analysis), and for either independent or dependent (repeated measures) observations within each group/level. For the Fisher-esque ANOVAs, you can also access estimates of proportion of variance accounted for (eta-squared) and effect-size (omega-squared), plus a priori pairwise comparisons by the relevant independent or dependent t-tests. Non-Fisher-esque, non-parametric tests comprise the Kruskal-Wallis, Friedman and Page tests, all with default accounting for ties in the calculation of ranks, and standardizing of the test-statistics. Simple parametric and non-parametric post hoc clustering is also offered (Scott-Knott and Worsley methods). The module also provides for testing equality of variances (O'Brien and Levene tests) across independent groups.

A basic design principle has been to offer as few method calls as possible, and to steer queries into the proper underlying method by Boolean manipulation of a minimal parameter set. To get to any relevant test of your data, there are (only) three Boolean vars to set, and these are named adjectivally: independent, parametric and ordinal. So the relevant tests are offered not in the form of little packages specific to each test, but by specifying the attributes of the data: are they based on independent groups or repeated measures? do the groups/measures form independent categories or related levels? are relationships, likenesses or differences to be found? do the data support parametric testing? It seems more useful for programmed access to statistical algorithms to be initially sensitive to the answers to these and like questions, while keeping the methods of access and set of arguments the same across tests, and the actual tests relatively invisible, rather than bearing the statistical method up-front, each package offering a unique interface and algorithm for the same things, each dependent on a unique set of arguments and their correct norder. It could be argued that that's what an application should do, not a module. This module goes the other way, recognizing that the algorithms share arguments and internal methods, which is typically obscured by algorithm-specific packaging.

Reliability has been assayed by testing each method with at least two different published sources; and comparing the output with one or another open-source or commercial statistics package. The tests based on published examples are implemented during cpan-wise installation; see the "t" folder of cpan.org's installation-distribution of this module. News of unreliabilities are welcome; a fundamental one from Cathal Seoghie has already helped, namely, by pointing to the need to account for NaNs, empty, and invalid values.

METHODS

INTERFACE

Object-oriented. No subs are explicitly exported, no parameters are set for cross-method application.

The class-object yet always holds the myriad of statistics produced by the last test you called - i.e., it is fed with relevant values upon each method-call; a "p_value" at least.

The methods generally only return the class object itself.

Most tests set a common lot of statistical keys(e.g., denoting between- and within-groups sums-of-squares), but a few are idiosyncratic per test.

Meanwhile, just dump as much as you can, and bless your digestion.

new

 $aov = Statistics::ANOVA->new()

Create a new Statistics::ANOVA object for accessing the subs.

HANDLING DATA

load

 $aov->load('aname', @data1)
 $aov->load('aname', \@data1)
 $aov->load(['aname', @data1], ['another_name', @data2])
 $aov->load(['aname', \@data1], ['another_name', \@data2])
 $aov->load({'aname' => \@data1, 'another_name' => \@data2})

Alias: load_data

Accepts data for analysis in any of the above-shown forms, but always with the requirement that:

  1. a single set of observations (the "group" or "level") is given a unique name, and

  2. you do not mix the methods, e.g., send a bit of a hashref, plus a bit of an aref. That's perverse.

The reason for all these options is that there are so many to be found in Perl's Statistics modules that it would be a pain for you to have to re-architecture your data just to use this module. So, namely, you can load:

  1. a single name => value pair of a sample name, and a list (referenced or not) of data. This is a simple but useless load: Presumably, you will follow this up, when you're ready, with a call to add so that there's actually something relevant to test by this module. Don't try another call to load with new data because that will only clobber what you've just done.

  2. a reference to an array of (referenced) arrays, where each of the latter arrays consists of a sample name occupying the first index, and then its sample data, as an array or yet another referenced array.

  3. a hash reference of named array references of data. This is the preferred method - the one that is first checked in the elongated if clause that parses all this variety.

The data are loaded into the class object by name, within a hash named data, as Statistics::Descriptive::Full objects. So you can easily get at any descriptives for the groups you've loaded - e.g., $aov->{'data'}->{'aname'}->mean() - or you could get at the data again by going $aov->{'data'}->{'aname'}->get_data() - and so on; see Statistics::Descriptive for the full Christmas tree of possibilities available to you.

The names of the data are up to you; whatever can be set as the key in a hash. But if you intend to do trend analysis, you should, as a rule, give only numerical names to your groups/levels, at least defining their ordinality.

Each call unloads any previous loads.

Returns the Statistics::ANOVA object - nothing but its blessed self.

add

 $aov->add('another_name', @data2)
 $aov->add('another_name', \@data2)
 $aov->add(['another_name', @data2])
 $aov->add(['another_name', \@data2])
 $aov->add({'another_name' => \@data2})

Alias: add_data

Same as load except that any previous loads are not unloaded. Again, the hash-referenced list is given preferential treatment.

unload

 $aov->unload()     # bye-bye everything
 $aov->unload('g1') # so long data named "g1"

Alias: delete_data

With nil or no known arguments, empties all cached data and calculations upon them, ensuring these will not be used for testing. This will be automatically called with each new load, but, to take care of any development, it could be good practice to call it yourself whenever switching from one dataset for testing to another.

Alternatively, supply one or more names of already loaded data to clobber just them out of existence; preserving any other loads.

Missing/Invalid values

Any data-points/observations sent to load or add that are undefined or not-a-number are marked for purging before being anova-tested or tested pairwise. The data arrays accessed as above, as Statistics::Descriptive::Full, will still show the original values. When, however, you call one of the anova or pairwise methods, the data must and will be purged of these invalid values before testing.

When the independent parameter equals 1 when sent to anova, compare or cluster, each list is simply purged of any undefined or invalid values. This also occurs for the equality of variances tests.

When independent parameter equals 0 when sent to anova, compare and cluster, each list is purged of any value at all indices that, in any list, contain invalid values. So if two lists are (1, 4, 2) and (2, ' ', 3), the lists will have to become (1, 2) and (2, 3) to account for the bung value in the second list, and to keep all the observations appropriately paired.

The number of indices that were subject to purging is cached thus: $aov->{'purged'}. The dump method can also reveal this value.

The looks_like_number method in Scalar::Util is used for checking validity of values. (Although Params::Classify::is_number might be stricter, looks_like_number benchmarks at least a few thousand %s faster.)

MEASURING SIGNIFICANCE

One generic method anova (a.k.a. aov, test) is used to access parametric or nonparametric tests for independent or dependent/related observations, and categorical prediction or trend analysis. Accessing the different statistical tests depends on setting three parameters on a true/false basis: independent, parametric and ordinal. The following describes the particular tests you get upon each possible combination of these alternatives.

1. INDEPENDENT groups/levels

1.10 PARAMETRIC test for NOMINAL groups

 $aov->anova(independent => 1, parametric => 1, ordinal => 0)

Offers the standard Fisher-esque ANOVA for a single factor applied to independent groups of data-sources (people, plots-of-land, cultures, etc.). The attribute independent refers to whether or not each level of the independent variable was yielded by independent or related sources of data; e.g., If the same people provided you with ratings on the levels of "What pacifies me" and "What freaks me out," that would be a dependent, repeated measures situation; i.e., the same people, or plot-of-land, whatever, contributed an observation under each level of the predictive, factor (or the "independent variable", or "treatment"). In the latter case, independent must equal zero. But if a unique set of people, or plot-of-land, or culture, yielded the measures over the predictive factor, then independent = 1 - each data source per group/level is not derived from the same data-source.

1.11 PARAMETRIC test for ORDINAL levels

 $aov->anova(independent => 1, parametric => 1, ordinal => 1) # test linear trend
 $aov->anova(independent => 1, parametric => 1, ordinal => -1) # test non-linear trend

If the independent/treatment/between groups variable is actually measured on a continuous scale/is a quantitative factor, assess their linear trend: Instead of asking "How sure can we be that the means-per-group are equal?", ask "How sure can we be that there is a departure from flatness of the means-per-level?".

The essential difference is that in place of the the between (treatment) mean squares in the numerator is the linear sum of squares in which each "group" mean is weighted by the deviation of the level-value (the name of the "group") from the mean of the levels (and divided by the sum of the squares of these deviations).

If the number of observations per level is unequal, the module applies the simple unweighted approach. This is recommended as a general rule by Maxwell and Delaney (1990), given that the weighted approach might erroneously suggest a linear trend (unequal means) when, in fact, the trend is curvilinear (and by which the means balance out to equality); unless "there are strong theoretical reasons to believe that the only true population trend is linear" (p. 234). (But then you might be theoretically open to either. While remaining as the default, a future option might access the hierarchical, weighted approach.)

To test if there is the possibility of a non-linear trend, give the value of -1 to the ordinal argument.

Note that the contrast coefficients are calculated directly from the values of the independent variable, rather than using a look-up table. This respects the actual distance between values, but requires that the names of the sample data, of the groups (or levels), have been given numerical names when loaded - i.e., such that the data-keys can be summed and averaged.

1.20 NONPARAMETRIC test for NOMINAL groups (Kruskal-Wallis test)

 $aov->anova(independent => 1, parametric => 0, ordinal => 0)

Performs a one-way independent groups ANOVA using the non-parametric Kruskal-Wallis sum-of-ranks method for 3 or more groups of a single factor. Instead of an F-value, there is now a H-value. The p-value is read off the chi-square distribution; note that this is unreliable when there are no more than 3 groups and all groups comprise 5 or fewer observations.

By default, this method accounts for and corrects for ties, but if correct_ties = 0, H is uncorrected. The correction involves giving each tied score the mean of the ranks for which it is tied (see Siegal, 1956, p. 188ff).

1.21 NONPARAMETRIC test for ORDINAL levels (Jonckheere-Terpstra test)

 $aov->anova(independent => 1, parametric => 0, ordinal => 1)

Performs the Jonckheere-Terpstra test that respects the given, numerical order of the levels of the independent/treatment variable; unlike the Kruskal-Wallis test that will return the same result regardless of the order of levels. Its test statistic J is the sum of k(k - 1)/2 Mann-Whitney U counts (sum of 1/0 for min/max value of all possible pairs of observations, between groups). Rather than calculating the exact p-value, the present implementation calculates an expected J value and variance (sensitive to tied ranks), to provide a normalized J for which the p-value is read off the normal distribution. This is appropriate for "large" samples, e.g., greater-than 3 levels, with more than eight observations per level. Otherwise, read the value of $aov->{'j_value'} and look it up in a table of j-values, such as in Hollander & Wolfe (1999), p. 649ff. The class object is fed:

 $aov->{'j_value'}   :  the observed value of J
 $aov->{'j_exp'}     :  the expected value of J
 $aov->{'j_var'}     :  the variance of J
 $aov->{'z_value'}   :  the normalized value of J
 $aov->{'p_value'}   :  the one-tailed probability of observing a value as great as or greater than z_value.

By default, the method accounts for and corrects for ties, but if correct_ties = 0, j_var is the usual "null" distribution variance, otherwise with an elaborate correction accounting for the number of tied "groups" and each of their sizes, as offered by Hollander & Wolfe (1999) Eq 6.19, p. 204.

2. DEPENDENT groups/levels (REPEATED MEASURES)

2.10 PARAMETRIC test for NOMINAL groups

 $aov->anova(independent => 0, parametric => 1, ordinal => 0, multivariate => 0|1)

The parametric repeated measures analysis of variance is performed. By default, this is performed using the traditional univariate, or "mixed-model," approach, with sphericity assumed (i.e., equal variances of all factor differences, within each factor and all possible pairs of factors). The assumption is met when there are only two levels of the repeated measures factor; but unequal variances might be a problem when there are more than two levels.

[TO DO: In order to account for the possibility of violated sphericity, two strategies are typically used: either adjustment of the degrees-of-freedom by one or another method (e.g., Huynh-Feldt procedure) or a multivariate analysis of variance. Presently, the module permits (only) the latter option, given that it can also be used in the next stage for comparing individual means (whereas adjustments of the degrees-of-freedom in paired comparisons is not recommended) (Maxwell & Delaney, 1992, Ch. 11). In order to perform a multivariate analysis of variance, simply specify the parameter multivariate and give it a value of 1. Alternatively, call anova_mv. In fact, the multivariate approach is recommended as the default procedure, which might be implemented in a future version.]

2.11 PARAMETRIC test for ORDINAL levels

[Not implemented.]

2.20 NONPARAMETRIC test for NOMINAL groups (Friedman test)

 $aov->anova(independent => 0, parametric => 0, ordinal => 0)

Performs the Friedman nonparametric analysis of variance - for two or more dependent (matched, related) groups. A ranking procedure is used, but, unlike the case for independent groups, the ranks are taken at each common index of each group/level, i.e., within-groups, given that the observations at each index are given by the same data-source (person, plot, etc.). Some tie-handling code from Statistics::RankCorrelation is channelled here for this purpose.

The statistical attributes now within the class object (see anova) pertain to this test, e.g., $aov->{'chi_value'} gives the chi-square statistic from the Friedman test; and $aov->{'p_value'} gives the associated p-value (area under the right-side, upper tail of the distribution). There is now no defined 'f_value'.

If f_equiv => 1, then, instead of the chi-value, and p-value read off the chi-square distribution, you get the F-value equivalent, with the p-value read off the F-distribution.

By default, the method accounts for and corrects for ties, but if correct_ties = 0, the test-statistic is uncorrected. The correction involves accounting for the number of tied groups at each index, as per Hollander & Wolfe (1999), Eq. 7.8, p. 274.

Please note that parametric trend analysis for dependent/repeated measures is not (as yet) implemented.

2.21 NONPARAMETRIC test for ORDINAL levels (Page test)

 $aov->anova(independent => 0, parametric => 0, ordinal => 1, tails => 1|2)

This option implements the Page (1963) test; see Hollander and Wolfe (1999, p. 284ff) for a review. Ranks are computed exactly as for the Friedman test, but the ranks are weighted according to the ordinal position of the group/level to which they pertain. Also, the test of significance is based on a standardized value, with the p-value read off the normal distribution. Similarly to the relationship between the Kruskal-Wallis and Jonckheere-Terpstra tests for non-dependent observations, the Friedman test returns the same value regardless of the ordinality of the groups/levels, but the Page test respects - and requires - numerical labels of the groups/levels. The groups are weighted according to their Perl sort { $a <=> $b} order, so be sure to give sort-able names that reflect your pre-experimental, hypothetical ordering of the different treatments/groups.

With only two groups, the test statistic is equivalent to that provided by a sign test.

The statistical attributes now within the class object (see anova) pertain to this test, and are chiefly:

 $aov->{'l_value'} : the observed test statistic (sum of ordered and weighted ranks)
 $aov->{'l_exp'}   : expected value of the test statistic
 $aov->{'l_var'}   : variance of the test statistic (given so many groups and observations)
 $aov->{'z_value'} : the standardized l_value
 $aov->{'p_value'} : the 2-tailed probability associated with the z_value (or 1-tailed if tails => 1).

Hollander and Wolfe (1999) describe how Page's L-statistic is directly related to Spearman's rank-order correlation coefficient (see Statistics::RankCorrelation). They provide a simple "l2r" transformation, and this is also offered, so, just for this test, you can also read:

 $aov->{'r_value'} : estimate of the Spearman rank-order correlation coefficient
  based on the observed and predicted order of each associated group/level per observation.

anova

 $aov->anova(independent => 1|0, parametric => 1|0, ordinal => 0|1)

Aliases: aov, test

Generic method to access all anova functions by specifying TRUE/FALSE values for independent, parametric and ordinal.

    Independent    Parametric  Ordinal    What you get
    1              1           0          Fisher-esque independent groups ANOVA
    1              1           1          Fisher-esque independent groups ANOVA with trend analysis
    1              0           0          Kruskal-Wallis independent groups ANOVA
    1              0           1          Jonckheere-Terpstra independent groups trend analysis    
    0              1           0          Fisher-esque dependent groups ANOVA (univariate or multivariate)
    0              1           1          (Fisher-esque dependent groups ANOVA with trend analysis; not implemented)
    0              0           0          Friedman's dependent groups ANOVA
    0              0           1          Page's dependent groups trend analysis

All methods return nothing but the class object after feeding it with the relevant statistics, which you can access by name, as follows:

 $aov->{'f_value'} (or $aov->{'chi_value'}, $aov->{'h_value'}, $aov->{'j_value'}, $aov->{'l_value'} and/or $aov->{'z_value'})
 $aov->{'p_value'} : associated with the test statistic
 $aov->{'df_b'} : the between-groups or treatment or numerator degree(s) of freedom
 $aov->{'df_w'} : the within-groups or error or denominator degree(s) of freedom (also given with F-equivalent Friedman test)
 $aov->{'ss_b'} : between-groups or treatment sum of squares
 $aov->{'ss_w'} : within-groups or error sum of squares
 $aov->{'ms_b'} : between-groups or treatment mean squares
 $aov->{'ms_w'} : within-groups or error mean squares

Tests for equality of variances

obrien

 $aov->obrien()

Alias: obrien_test

Performs O'Brien's (1981) test for equality of variances within each group: based on transforming each observation in relation to its group variance and its deviation from its group mean; and performing an ANOVA on these transformed values (for which the group mean is equal to the variance of the original observations). The procedure is recognised to be robust against violations of normality (unlike F-max) (Maxwell & Delaney, 1990).

The statistical attributes now within the class object (see anova) pertain to this test, e.g., $aov->{'f_value'} gives the F-statistic for O'Brien's Test; and $aov->{'p_value'} gives the p-value associated with the F-statistic for O'Brien's Test.

levene

 $aov->levene()

Alias: levene_test

Performs Levene's (1960) test for equality of variances within each group: an ANOVA of the absolute deviations, i.e., absolute value of each observation less its group mean.

The statistical attributes now within the class object (see anova) pertain to this test, e.g., $aov->{'f_value'} gives the F-statistic for Levene's Test; and $aov->{'p_value'} gives the p-value associated with the F-statistic for Levene's Test.

MEASURING EFFECT

Follow-up parametric ANOVAs.

eta_squared

Returns eta-squared if an ANOVA has been performed; otherwise croaks. Also feeds $aov with the value, named 'eta_sq'. Values range from 0 to 1, 0 indicating no effect, 1 indicating difference between at least two DV means. Generally indicates the proportion of variance in the DV related to an effect.

omega_squared

Returns the effect size statistic omega-squared if an ANOVA has been performed; otherwise croaks. Also feeds $aov with the value, named 'omega_sq'. Generally, size is small where omega_sq = .01, medium if omega_sq = .059, and strong if omega_sq = .138.

IDENTIFYING RELATIONSHIPS/DIFFERENCES

compare

 $aov->compare(independent => 1|0, parametric => 1|0, tails => 2|1, flag => 0|1, alpha => .05,
    adjust_p => 0|1, adjust_e => 1|0|2, use_t => 0|1, dump => 0|1, str => 0|1)

The method performs all possible pairwise comparisons, with the Bonferroni approach to control experiment-wise error-rate. The particular tests depend on whether or not you want parametric (default) or nonparametric tests, and if the observations of the factor have been made between groups (default) or by repeated measures.

[TO DO: Note: The following new procedures, as implemented from v0.07 onwards, are only relevant for independent designs; for repeated measures, the comparisons are, at this time, the same as provided in earlier versions, i.e., by multiple paired comparisons t-tests.]

Parametric pairwise comparison. If parametric => 1 (default), performs F-tests on each possible pair of observations, with respect to the value of independent. Unless you have just run an equality of variances test, the omnibus equality-of-variances is first tested by the O'Brien method; otherwise, the result of the last such test is looked up.

  • If the variances are unequal (p < .05), the variance of each sample in the pair is used in the error-term of the F-value, and the denominator degrees-of-freedom is adjusted accordingly.

  • If the variances are equal, the mean-square error ($aov->{'ms_w'}) is used in the denominator.

You get direct, unadjusted use of the mean-square error, however, with no prior test of equality-of-variances, if you specifically set the parameter adjust_e => 0. On the other hand, you can force the procedure to use separate variances, and adjust the error term and degrees-of-freedom accordingly, even if the variances are equal at the .05 level, if adjust_e => 2.

Non-parametric pairwise comparison. If parametric => 0: derives the z-value and associated p-value for the standardized (a) Wilcoxon (between-groups) sum-of-ranks if independent => 1 (Dwass procedure), or (b) the Friedman-type (within-groups) sum-of-ranks if independent => 0. Naturally, the number of observations per group should be reasonably large for this p-value to be appropriate; otherwise, look-up $aov->{'s_value'} in the appropriate tables.

Nominality is always assumed. Perhaps some Monte Carlo testing could be useful if the factor is, in fact, at least ordinal.

The p-value is 2-tailed, by default, unless otherwise specified, as above. If the value of the argument adjust_p equals 1, then the probability values themselves will be adjusted according to the number of comparisons, alpha will remain as given or at .05. The correction is:

    p' = 1 – (1 – p)N

where p is the probability returned by the relevant comparison procedure, and N is the number of pairwise comparisons performed.

By default, returns a hashref of hashrefs, the outer hash keyed by the pairs compared (as a comma-separated string), each with a hashref with keys named t_value, p_value, df, sig (= 1 or 0 depending on its being below or greater than/equal to alpha).

Alternatively, if the value of str => 1, you just get back a referenced array of strings that describe the results, e.g., G1 - G2: t(39) = 2.378, 2p = 0.0224.

Give a value of 1 to dump to automatically print these strings to STDOUT. (Distinct from earlier versions, there is no default dump to STDOUT of the results.)

The output strings are appended with an asterisk if the logical value of the optional attribute flag equals 1 and the p_value is less than the Bonferroni-adjusted alpha level. This alpha level, relative to the given or default alpha of .05, for the number of paired comparisons, is printed at the end of the list.

An alternative (actually, legacy from earlier version) is to use t-tests, rather than F-tests, and this you get if the argument use_t => 1. The module uses Perl's Statistics t-test modules for this purpose, with no accounting for the variance issue.

cluster

 $aov->cluster(parametric => 1|0, tails => 1|2, flag => 1|0, alpha => .05, adjust_p => 1|0, dump => 1|0, str => 1|0)

Identifies the first-order clusters arising by all possible binary splits of the groups/levels, selecting that which gives the lowest error sum-of-squares (or greatest between sum-of-squares).

Parametric binary clustering. If parametric => 1 (default), the method is as described by Scott & Knott (1974).

Non-parametric binary clustering. If parametric => 0, Worsley's (1977) nonparametric implementation of the Scott-Knott method is offered: the observed values are replaced by their rank, and the maximum Kruskal-Wallis statistic given by the binary partitions is selected; ties are corrected as described above for the Kruskal-Wallis test, rather than the random assignment method described by Worsley.

In both the parametric and nonparametric cases, the method returns a hashref like so:

 k_value : the test statistic pertaining to the selected partition
 p_value : probability associated with the test statistic
 clusters : referenced array of referenced arrays, each giving the names of groups/levels included in each cluster

(A future version might seek second-order partitions - i.e., doing this all over again for each of the first-order partitions.)

confidence

 $itv_str = $aov->(independent => 1|0, alpha => .05, name => 'aname', limits => 0) # get interval for single group as string
 $lim_aref = $aov->(independent => 1|0, alpha => .05, name => 'aname', limits => 1) # get upper & lower limits for single group as aref
 $itv_href = $aov->(independent => 1|0, alpha => .05, name => ['aname', 'bname'], limits => 0) # get interval for 2 groups as hashref keyed by group names
 $lim_href = $aov->(independent => 1|0, alpha => .05, name => ['aname','bname'], limits => 1) # get upper & lower limits for 2 groups as hashref of group-named arefs
 $itv_href = $aov->(independent => 1|0, alpha => .05, name => undef, limits => 0) # get intervals for all groups as hashref keyed by group names
 $lim_href = $aov->(independent => 1|0, alpha => .05, name => undef, limits => 1) # upper & lower limits for all groups as hashref 

Computes confidence intervals using (by default) the pooled estimate of variability over groups/levels, rather than the standard error within each group/level, as described by Masson and Loftus (2003). For a between groups design, the confidence interval (as usual) indicates that, at a certain level of probability, the true population mean is likely to be within the interval returned. For a within-subjects design, as any effect of the variability between subjects is eliminated, the confidence interval (alternatively) indicates the reliability of the how the sample means are distributed as an estimate of the how the population means are distributed.

In either case, there is an assumption that the variances within each condition are the same between the conditions (homogeneity of variances assumption).

Actual algorithm depends on whether the measures are obtained from seperate groups (independent => 1) or by repeated measures (independent => 0) (i.e., whether between-groups or within-groups design). Default is between-groups.

The option use_mse can be set to equal 0 so that the (typical) standard error of the mean is used in place of the mean-square error. This is one option to use when the variances are unequal.

The option conditions can, optionally, include a referenced array naming the particular conditions that should be included when calculating MSe. By default, this is all the conditions, using MSe from the omnibus ANOVA. This is one option to handle the case of unequal variances between conditions.

Default

ACCESSING RESULTS

string

 $str = $aov->string(mse => 1, eta_squared => 1, omega_squared => 1, precision_p => integer, precision_s => integer)

Returns a statement of result, in the form of F(df_b, df_w) = f_value, p = p_value; or, for Friedman test chi^2(df_b) = chi_value, p = p_value (to the value of precision_p, if any); and so on for other test statistics. Optionally also get MSe, eta_squared and omega_squared values appended to the string, where relevant. These and the test statistic are "sprintf"'d to the precision_s specified (or, by default, not at all).

table

 $table = $aov->table(precision_p => integer, precision_s => integer);

Returns a table listing the degrees of freedom, sums of squares, and mean squares for the tested "factor" and "error" (between/within groups), and the F- and p-values. The test statistics are "sprintf"'d to the precision_s specified (or, by default, not at all); the p value's precision can be specified by precision_p.

Up to this version, if calculating any of these values was not essential to calculation of the test statistic, the value will simply appear as a blank in the table. If the omnibus test last made was non-parametric, and no F-value was calculated, then the table returned is entirely an empty string.

Formatting with right-justification where appropriate is left for user-joy.

dump

 $aov->dump(title => 'ANOVA test', precision_p => integer, precision_s => integer, mse => 1, eta_squared => 1, omega_squared => 1, verbose => 1)

Prints the string returned by string, or, if specified with the attribute table => 1, the table returned by table; and the string as well if string => 1. A newline - "\n" - is appended at the end of the print of the string. Above this string or table, a title can also be printed, by giving a value to the optional title attribute.

If verbose => 1, then any curiosities arising in the calculations are noted at the end of other dumps. At the moment, this is only the number of observations that might have been purged were they identified as undefined or not-a-number upon loading/adding.

REFERENCES

Hollander, M., & Wolfe, D. A. (1999). Nonparametric statistical methods. New York, NY, US: Wiley.

Levene, H. (1960). Robust tests for equality of variances. In I. Olkins (Ed.), Contributions to probability and statistics. Stanford, CA, US: Stanford University Press.

Masson, M. E. J., & Loftus, G. R. (2003). Using confidence intervals for graphically based data interpretation. Canadian Journal of Experimental Psychology, 57, 203-220.

Maxwell, S. E., & Delaney, H. D. (1990). Designing experiments and analyzing data: A model comparison perspective. Belmont, CA, US: Wadsworth.

O'Brien, R. G. (1981). A simple test for variance effects in experimental designs. Psychological Bulletin, 89, 570-574.

Page, E. B. (1963). Ordered hypotheses for multiple treatments: A significance test for linear ranks. Journal of the American Statistical Association, 58, 216-230.

Scott, A. J., & Knott, M. (1974). A cluster analysis method for grouping means in the analysis of variance. Biometrics, 30, 507-512.

Siegal, S. (1956). Nonparametric statistics for the behavioral sciences. New York, NY, US: McGraw-Hill

Worsley, K. J. (1977). A non-parametric extension of a cluster analysis method by Scott and Knott. Biometrics, 33, 532-535.

SEE ALSO

Math::Cephes Probabilities for all tests are computed using this module's functions, rather than the "in-house" Statistics::Distributions module, as the former appears to be more accurate for larger values of F.

Statistics::Descriptive Fundamental calculations of means and variances are left up to this standard; any limitations/idiosyncrasies therein are naturally passed onto the present one; although the present one purges missing and non-numerical values, unlike Statistics::Descriptive, which gives them the value of "0" (and so returns erroneous descriptives).

Statistics::FisherPitman For an alternative to independent groups ANOVA when the variances are unequal.

Statistics::KruskalWallis Offers Newman-Keuls for pairwise comparison by ranks. Also offers non-parametric independent groups ANOVA, but note it does not handle ties in rank occurring between two or more observations, nor correct for them; an erroneous H-value is calculated if ties exist in your data. Also does not handle missing/invalid values. Present module adapts its _grouped method.

Statistics::Sequences Offers methods for comparison of independent groups by split over central tendency.

Statistics::Table::F Simply returns an F value. Does not handle missing values, treating them as zero and thus returning an erroneous F-value in these cases.

BUGS/LIMITATIONS/TO DO

Optimisation welcomed.

No adjustment is offered for violations of sphericity in repeated measures ANOVA, but the multivariate approach is a work in progress.

To do: Repeated measures planned/pairwise comparisons requires bringing to the level as for independent measures.

To do: Confidence rather than/in addition to comparison and cluster breakdowns.

To do: Parametric ANOVAs for ordinal level of measurement in repeated measures designs.

To do: Verbose tracing to check-out what's actually happening internally, what defaults are being used, etc.

REVISION HISTORY

See CHANGES in installation distribution.

AUTHOR/LICENSE

rgarton AT cpan DOT org

This program is free software. It may be used, redistributed and/or modified under the same terms as Perl-5.6.1 (or later) (see http://www.perl.com/perl/misc/Artistic.html).

Disclaimer

To the maximum extent permitted by applicable law, the author of this module disclaims all warranties, either express or implied, including but not limited to implied warranties of merchantability and fitness for a particular purpose, with regard to the software and the accompanying documentation.