I want to implement basic randomization tests as described in Ernst, 2004 Permutation methods for exact inference. I have observations of a single continuous variable for n individuals falling into k groups. I want to know if differences in mean score per group are greater than would be expected to occur by chance.
Consider the following data (n=106 observations, k=8 groups):
score<-c(71,57,52,44,67,53,40,59,46,64,58,57,54,74,48,54,57,59,72,59,73,66,67,70,66,44,65,57,54,41,57,50,51,51,50,58,66,69,54,63,44,73,63,56,57,58,50,64,61,56,55,65,60,58,46,64,66,62,63,71,56,53,39,66,35,46,62,39,64,65,43,61,67,54,54,56,61,67,59,56,61,45,44,69,60,53,64,51,61,68,60,59,53,63,52,65,68,59,71,63,62,64,61,47,50,69)
group<-c(5,2,5,6,4,6,5,5,5,3,4,5,7,3,6,5,5,7,2,6,4,4,8,5,4,6,4,5,2,6,6,5,6,6,5,5,5,5,5,2,6,5,5,6,3,6,5,5,4,4,6,3,5,6,6,5,5,4,5,4,5,6,5,5,6,5,5,3,8,2,2,4,6,6,5,6,5,5,4,8,5,3,6,5,5,4,6,5,5,6,8,5,6,5,6,6,5,4,5,5,5,5,5,4,6,5)
Following Ernst, 2004: 5.1 a test for differences between means is:
obs_means<-aggregate(values~group,FUN=mean)
group_size<-table(group)
T_stat<-sum((obs_means$values^2)*group_size) #the test statistic
#shuffle the data and recalculate
results<-numeric(10000)
for (i in 1:length(results)){
draw<-sample(values,length(values),replace=FALSE) #no replacement!
shuffled<-data.frame(group,draw)
shuffled_means<-aggregate(draw~group,data=shuffled,FUN=mean)
shuffled_T_stat<-sum((shuffled_means$draw^2)*group_size)
results[i]<-shuffled_T_stat
}
crit_val<-quantile(results,0.95)
T_stat>crit_val #are there significant differences between means?
The test statistic here ("T_stat") is apparently equivalent to the F-statistic in a one-way ANOVA, so these results indicate that there is a significant difference between means at p=0.05.
Now, we want to know where that difference lies. Following Ernst, 2004: 5.2 the (approximate!) test is:
#mean scores per group
obs_means<-aggregate(values~group,FUN=mean)
#get pairwise differences
pairs<-combn(obs_means[,2],2)
pairnames<-combn(obs_means[,1],2)
diffs<-abs(pairs[1,]-pairs[2,])
names(diffs)<-paste(pairnames[1,],"vs",pairnames[2,]) # add names
#randomization
results<-numeric(10000)
for (i in 1:length(results)){
draw<-sample(values,length(values),replace=FALSE)
shuffled<-data.frame(group,draw)
shuffled_means<-aggregate(draw~group,data=shuffled,FUN=mean)
shuffled_pairs<-combn(shuffled_means[,2],2)
shuffled_differences<-abs(shuffled_pairs[1,]-shuffled_pairs[2,])
results[i]<-max(shuffled_differences)
}
crit_val<-quantile(results,0.95)
#print pairs with differences greater than the empirical critical value (there aren't any)
diffs[diffs>crit_val]
Assuming I've done that right, we find no differences between means when making pairwise comparisons. Since the test statistic we calculated in the first part for the overall difference between means was only slightly above the 'critical value' (the 95th percentile of the empirical distribution of test statistics that we simulated) I would chalk this up to this not being an exact test and conclude there are no differences between groups.
My questions are (i) is this computation and interpretation correct? (ii) is there an existing function in R that does this, perhaps better? For example, I would use the XNomial package if these data were categorical.
coin
. $\endgroup$