When to use this test
A permutation test of symmetry can be used for one-way data with an ordinal dependent variable where observations are paired within a blocking variable. It will determine if there is a difference in the response variable among groups when controlling for the effect of the blocking variable. There can be two or more groups.
The coin package can accommodate designs used with Friedman, Quade, paired t-test, repeated measures one-way anova, and their ordinal regression equivalents.
The test does not make assumptions about the distribution of values.
The test is performed with the symmetry_test function in the coin package.
Post-hoc testing can be conducted with pairwise permutation tests across groups.
Appropriate data
• One-way data plus a blocking variable. That is, one measurement variable in two or more groups, where observations are paired within levels of a blocking variable
• Here, the dependent variable is ordinal
• The independent variable is a factor with two or more levels. That is, two or more groups. The blocking variable is also a factor variable
• Here, the data is arranged in an unreplicated complete block design, but there could be one or more observations per cell
Hypotheses
• Null hypothesis: The response of the dependent variable among groups are equal n the sampled population.
• Alternative hypothesis (two-sided): The response of the dependent variable among groups are not equal in the sampled population.
Interpretation
• Reporting significant results for the omnibus test as “Significant differences were found in the response among groups.” is acceptable. Alternatively, “A significant effect for Independent Variable on Dependent Variable was found when controlling for the effect of Blocking Variable.”
• Reporting significant results for mean separation post-hoc tests as “Response of Dependent Variable for group A was different than that for group B.” is acceptable.
Other notes and alternative tests
Ordinal regression is an alternative.
The traditional nonparametric tests Friedman, Quade, Paired rank-sum test, or Sign test may be alternatives depending on the design of the experiment.
Packages used in this chapter
The packages used in this chapter include:
• psych
• lattice
• FSA
• coin
• rcompanion
• multcompView
The following commands will install these packages if they are not already installed:
if(!require(psych)){install.packages("psych")}
if(!require(FSA)){install.packages("FSA")}
if(!require(lattice)){install.packages("lattice")}
if(!require(coin)){install.packages("coin")}
if(!require(rcompanion)){install.packages("rcompanion")}
if(!require(multcompView)){install.packages("multcompView")}
One-way ordinal permutation test of symmetry example
This example re-visits the Belcher data from the Friedman Test chapter. Note that each instructor is rated by each of eight raters. Because of this, we want to stratify the responses by Rater.
Here, the ytrafo=rank_tranfo argument is passed to symmetry_test to indicate that the dependent variable should be rank transformed.
Data = read.table(header=TRUE, stringsAsFactors=TRUE, text="
Instructor Rater Likert
'Bob Belcher' a 4
'Bob Belcher' b 5
'Bob Belcher' c 4
'Bob Belcher' d 6
'Bob Belcher' e 6
'Bob Belcher' f 6
'Bob Belcher' g 10
'Bob Belcher' h 6
'Linda Belcher' a 8
'Linda Belcher' b 6
'Linda Belcher' c 8
'Linda Belcher' d 8
'Linda Belcher' e 8
'Linda Belcher' f 7
'Linda Belcher' g 10
'Linda Belcher' h 9
'Tina Belcher' a 7
'Tina Belcher' b 5
'Tina Belcher' c 7
'Tina Belcher' d 8
'Tina Belcher' e 8
'Tina Belcher' f 9
'Tina Belcher' g 10
'Tina Belcher' h 9
'Gene Belcher' a 6
'Gene Belcher' b 4
'Gene Belcher' c 5
'Gene Belcher' d 5
'Gene Belcher' e 6
'Gene Belcher' f 6
'Gene Belcher' g 5
'Gene Belcher' h 5
'Louise Belcher' a 8
'Louise Belcher' b 7
'Louise Belcher' c 8
'Louise Belcher' d 8
'Louise Belcher' e 9
'Louise Belcher' f 9
'Louise Belcher' g 8
'Louise Belcher' h 10
")
### Order levels of the factor; otherwise R will
alphabetize them
Data$Instructor = factor(Data$Instructor,
levels=unique(Data$Instructor))
### Create a new variable which is the likert
scores as an ordered factor
Data$Likert.f = factor(Data$Likert,
ordered=TRUE)
### Check the data frame
library(psych)
headTail(Data)
str(Data)
summary(Data)
Summarize data treating Likert scores as factors
Note that the variable we want to count is Likert.f, which is a factor variable. Counts for Likert.f are cross tabulated over values of Instructor. The prop.table function translates a table into proportions. The margin=1 option indicates that the proportions are calculated for each row.
xtabs( ~ Instructor + Likert.f,
data = Data)
Likert.f
Instructor 4 5 6 7 8 9 10
Bob Belcher 2 1 4 0 0 0 1
Linda Belcher 0 0 1 1 4 1 1
Tina Belcher 0 1 0 2 2 2 1
Gene Belcher 1 4 3 0 0 0 0
Louise Belcher 0 0 0 1 4 2 1
XT = xtabs( ~ Instructor + Likert.f,
data = Data)
prop.table(XT,
margin = 1)
Likert.f
Instructor 4 5 6 7 8 9 10
Bob Belcher 0.250 0.125 0.500 0.000 0.000 0.000 0.125
Linda Belcher 0.000 0.000 0.125 0.125 0.500 0.125 0.125
Tina Belcher 0.000 0.125 0.000 0.250 0.250 0.250 0.125
Gene Belcher 0.125 0.500 0.375 0.000 0.000 0.000 0.000
Louise Belcher 0.000 0.000 0.000 0.125 0.500 0.250 0.125
Bar plots by group
Note that the variable we want to count is Likert.f, which is a factor variable. Counts for Likert.f are presented for values of Speaker. Also note that the bar plots don’t show the effect of the blocking variable.
library(lattice)
histogram(~ Likert.f | Instructor,
data=Data,
layout=c(1,5) # columns and rows of
individual plots
)

Summarize data treating Likert scores as numeric
It may be useful to look at the minimum, first quartile, median, third quartile, and maximum for Likert for each group.
library(FSA)
Summarize(Likert ~ Instructor,
data=Data,
digits=3)
Instructor n mean sd min Q1 median Q3 max percZero
1 Bob Belcher 8 5.875 1.885 4 4.75 6 6.00 10 0
2 Linda Belcher 8 8.000 1.195 6 7.75 8 8.25 10 0
3 Tina Belcher 8 7.875 1.553 5 7.00 8 9.00 10 0
4 Gene Belcher 8 5.250 0.707 4 5.00 5 6.00 6 0
5 Louise Belcher 8 8.375 0.916 7 8.00 8 9.00 10 0
Permutation symmetry test
Instructor is the independent variable, and Rater is the blocking variable. The data= option indicates the data frame that contains the variables. For the meaning of other options, see library(coin); ?symmetry_test.
library(coin)
symmetry_test(Likert ~ Instructor | Rater,
data = Data,
ytrafo = rank_trafo,
teststat = "quadratic")
Asymptotic General Symmetry Test
chi-squared = 22.283, df = 4, p-value = 0.0001761
Note that there are built-in functions in the coin package to conduct an analysis analogous to the Friedman test and Quade test. These give different results than the symmetry_test used above.
friedman_test(Likert ~ Instructor | Rater,
data = Data)
Asymptotic Friedman Test
chi-squared = 23.139, df = 4, p-value = 0.0001188
quade_test(Likert ~ Instructor | Rater,
data = Data)
Asymptotic Quade Test
chi-squared = 17.092, df = 4, p-value = 0.001855
See Hothorn et al. for options in the symmetry_test function that correspond to common tests.
Post-hoc test: pairwise permutation tests
If the symmetry test is significant, a post-hoc analysis can be performed to determine which groups differ from which other groups.
The pairwisePermutationSymmetry and pairwisePermutationSymmetryMatrix functions in the rcompanion package conduct permutation tests across groups in a pairwise manner. See library(rcompanion); ?pairwisePermutationSymmetry for further details.
Because the post-hoc test will produce multiple p-values, adjustments to the p-values can be made to avoid inflating the possibility of making a type-I error. Here, the method of adjustment is indicated with the method option. There are a variety of methods for controlling the familywise error rate or for controlling the false discovery rate. See ?p.adjust for details on these methods.
Before conducting the pairwise tests, we will re-order the levels of the grouping variable by the median of each group. This makes interpretation of the pairwise comparisons and compact letter display easier.
Table output and compact letter display
### Order groups by median
Data$Instructor = factor(Data$Instructor,
levels = c("Linda Belcher", "Louise
Belcher",
"Tina Belcher", "Bob
Belcher",
"Gene Belcher"))
### Pairwise permutation tests
library(rcompanion)
PT = pairwisePermutationSymmetry(Likert ~ Instructor | Rater,
data = Data,
ytrafo = rank_trafo,
teststat = "quadratic",
method = "fdr")
PT
Comparison Stat p.value
p.adjust
1 Linda Belcher - Louise Belcher = 0 0.6761 0.4109 0.51360
2 Linda Belcher - Tina Belcher = 0 0.008163 0.928 0.92800
3 Linda Belcher - Bob Belcher = 0 5.912 0.01503 0.03210
4 Linda Belcher - Gene Belcher = 0 6.778 0.00923 0.03210
5 Louise Belcher - Tina Belcher = 0 0.8491 0.3568 0.50970
6 Louise Belcher - Bob Belcher = 0 5.163 0.02307 0.03845
7 Louise Belcher - Gene Belcher = 0 7.516 0.006117 0.03210
8 Tina Belcher - Bob Belcher = 0 5.797 0.01605 0.03210
9 Tina Belcher - Gene Belcher = 0 6.531 0.0106 0.03210
10 Bob Belcher - Gene Belcher = 0 0.4737 0.4913 0.54590
### Compact letter display
library(rcompanion)
cldList(p.adjust ~ Comparison,
data = PT,
threshold = 0.05)
Group Letter MonoLetter
1 LindaBelcher a a
2 LouiseBelcher a a
3 TinaBelcher a a
4 BobBelcher b b
5 GeneBelcher b b
Groups sharing a letter are not significantly different (alpha = 0.05).
Matrix output and compact letter display
A compact letter display condenses a table of p-values into a simpler format. In the output, groups sharing a same letter are not significantly different. Compact letter displays are a clear and succinct way to present results of multiple comparisons.
Here the fdr p-value adjustment method is used. See ?p.adjust for details on available methods.
The code creates a matrix of p-values called PM which is then passed to the multcompLetters function to be converted to a compact letter display.
### Order groups by median
Data$Instructor = factor(Data$Instructor,
levels = c("Linda Belcher", "Louise
Belcher",
"Tina Belcher", "Bob
Belcher",
"Gene Belcher"))
### Pairwise permutation tests
library(rcompanion)
PM = pairwisePermutationSymmetryMatrix(Likert ~ Instructor | Rater,
data = Data,
ytrafo = rank_trafo,
teststat = "quadratic",
method = "fdr")
PM$Adjusted
Linda Belcher Louise Belcher Tina
Belcher Bob Belcher Gene Belcher
Linda Belcher 1.0000 0.51360 0.9280 0.03210
0.0321
Louise Belcher 0.5136 1.00000 0.5097 0.03845
0.0321
Tina Belcher 0.9280 0.50970 1.0000 0.03210
0.0321
Bob Belcher 0.0321 0.03845 0.0321 1.00000
0.5459
Gene Belcher 0.0321 0.03210 0.0321 0.54590
1.0000
# Produce compact letter display
library(multcompView)
multcompLetters(PM$Adjusted,
compare="<",
threshold=0.05,
Letters=letters,
reversed = FALSE)
Linda Belcher Louise
Belcher Tina Belcher Bob Belcher Gene Belcher
"a" "a"
"a" "b" "b"
### Groups sharing a letter are not significantly
different (alpha = 0.05).