Lecture 6—Monday, January 23, 2012

Topics

R functions and commands demonstrated

An error bar plot for pairwise comparisons

You should recall from your elementary statistics course that a one-sample α-level significance test that tests whether the true value of a parameter is equal to zero is equivalent to determining whether the (1 – α)%-level confidence interval for that parameter contains zero. When we consider the two-sample case, testing the hypothesis that the two parameters are equal to each other, the two approaches are no longer equivalent. Using individual confidence intervals to carry out the two-sample hypothesis test leads to overly conservative results: one fails to reject the null hypothesis too often. The individual 95% confidence intervals can overlap even though a hypothesis test would conclude that the parameter values are significantly different at α = .05. This lack of equivalence is well-known and has been discussed repeatedly in the literature (Cumming 2009, Schenker and Gentleman 2001). The bottom line is that error bar displays of individual parameter estimates and their 95% confidence intervals cannot reliably be used to assess the statistical significance of differences between pairs of parameters.

A "solution" to this problem is to choose a confidence level for the individual confidence intervals that guarantees that non-overlapping pairs of confidence intervals do indicate statistically significant differences at α = .05. For independent parameters with roughly the same standard errors, the choice of 83.5% confidence intervals accomplishes this (Goldstein and Healy 1995, Payton et al. 2000, 2003). The more general case of dependent parameters has been discussed by Afshartous and Preston (2010) and their method can be adapted to our regression problem as I now demonstrate.

Theoretical derivation

The basic idea is simple. Under the null hypothesis of no significant difference between the parameters, we wish to choose a confidence level α for the individual confidence intervals such that the probability that they overlap is 0.95 (for a 5% test). Now,

overlap

The two individual confidence intervals can fail to overlap in two distinct ways. Let b1 and b2 be two slopes from two different weeks that we wish to compare, let s1 and s2 be their respective standard errors, and let t quantile be the alpha level quantile of a t-distribution with degrees of freedom equal to the residual degrees of freedom of the regression model.

fig 1

Fig. 1  b1 < b2 and the confidence intervals do not overlap

Fig. 1 shows the case when b1 < b2 and the confidence intervals fail to overlap. As the figure indicates the confidence intervals for the slopes from the two weeks don't overlap if the upper confidence limit of b1 is strictly less than the lower confidence limit of b2, i.e.,

inequality 1.

The roles of b1 and b2 could be reverse with b2 < b1. In that case the confidence intervals don't overlap if the upper limit of b2 is strictly less than the lower limit of b1 so that

inequality 2.

Thus we can write

overlap

I next carry out some algebra on these two inequalities starting by moving the parameters to the left side of the inequality.

overlap

In the last step I multiply both sides of the second inequality by minus one (thereby reversing the inequality).

Recall from lecture 5 that b1b2 can be written as vector dot product.

dot product

In lecture 5 we also saw that the variance of this dot product is given by

variance

where Σb is the variance-covariance matrix of b1 and b2. Under the null hypothesis that the mean difference of b1 and b2 is zero, the statistic,

z-statistic,

the parameter estimate minus its mean divided by its standard error, is a z-statistic. When ordinary least squares is used to obtain the parameter estimates of a regression model, the difference b1b2 will have a normal distribution. Hence this z-statistic will have a t-distribution with degrees of freedom given by the residual degrees of freedom of the regression model. Using this fact the probability that the intervals overlap can be written as follows.

overlap

where T is a t-statistic. The only unknown in this expression is α which controls the confidence level of our individual confidence intervals. We need to choose α so that the probability that the intervals overlap is equal to 0.95.

Implementing the calculations in R

The R function below calculates the probability of interval overlap using the formula derived above. I write it as a function of three quantities: the unknown α-level, the regression model, and the variance-covariance matrix for the parameters being compared.

nor.func1 <- function(alpha, model, sig) 1 - pt(-qt(1-alpha/2,model$df.residual) * sum(sqrt(diag(sig))) / sqrt(c(1,-1) %*% sig %*%c (1,-1)), model$df.residual) - pt(qt(1-alpha/2,model$df.residual) * sum(sqrt(diag(sig))) / sqrt(c(1,-1) %*% sig %*% c(1,-1)), model$df.residual, lower.tail=F)

I write a second function that takes this function evaluated at its arguments and subtracts 0.95 from it.

nor.func2 <- function(a,model,sigma) nor.func1(a,model,sigma)-.95

Finding the α that makes the nor.func1 function equal to 0.95 is the same as finding the α that makes the nor.func2 function equal to zero. The reason for reformulating things in this way is that there are standard protocols for finding the zeros of functions. In R there is a function called uniroot that will do this for us.

I next read in the data and fit the model. The model we need is the one I called mod3a. This is the re-parameterized version of model mod3 that returns the estimates and standard errors of the individual slopes and intercepts, rather than the differences from the reference group, week 1.

rikz <- read.table( 'ecol 562/RIKZ.txt', header=TRUE)
rikz$richness <- apply(rikz[,2:76], 1, function(x) sum(x>0))
mod3 <- lm(richness~NAP*factor(week), data=rikz)
mod3a <- lm(richness~factor(week) + factor(week):NAP - 1, data=rikz)

With four weeks of intercepts and slopes there are six pairwise comparisons we can make for each. I start by doing the calculations for the intercepts. I use the numeric function to initialize a vector with six slots, initially filled with zeros.

#initialize storage vector
xvec1b <- numeric(6)
xvec1b
[1] 0 0 0 0 0 0

Next I extract the portion of the variance-covariance matrix that corresponds to just the four intercepts. This is the submatrix consisting of rows 1 through 4 and columns 1 through 4 of the matrix that is returned by vcov when applied to the lm model object.

#create sigma for intercepts
vmat <- vcov(mod3a)[1:4,1:4]

To find the confidence levels needed for the six different pairwise comparisons I use a nested for loop. The outside loop chooses the first member of the comparison while the inside loop chooses the second member of the comparison. The index for the outer loop i runs from 1:3 while the index for the inner loop j runs from (i+1):4. The result is that each comparison is different and we do a total of six.

ind <- 1
for(i in 1:3) {
  for(j in (i+1):4){
     sig <- vmat[c(i,j), c(i,j)]
     #solve for alpha
     xvec1b[ind] <- uniroot(function(x) nor.func2(x,mod3a, sig), c(.001,.999))$root
     ind <- ind+1
}}
xvec1b
[1] 0.1599852 0.1594201 0.1446751 0.1602253 0.1404851 0.1378858
1-xvec1b
[1] 0.8400148 0.8405799 0.8553249 0.8397747 0.8595149 0.8621142

The confidence levels are not all the same but they're fairly similar varying from 84.0% to 86.2%. So, each pairwise comparison requires a slightly different confidence level. This would be impossible to display graphically and when the values are this close will typically not make much of a difference, so I take the mean of the six values as the confidence level to use in constructing the individual confidence intervals. I round the value to three decimal places to avoid numerical problems with the confint function that will be used to calculate the confidence intervals.

ci1b <- round(mean(1-xvec1b),3)
ci1b
[1] 0.85

I next repeat these calculations for the slopes. This involves choosing rows 5 through 8 and columns 5 through 8 of the variance-covariance matrix.

#obtain confidence level for slopes
#initialize storage
xvec1c <- numeric(6)
#create sigma for slopes
vmat <- vcov(mod3a)[5:8,5:8]
#location in storage vector
ind <- 1
for(i in 1:3) {
 for(j in (i+1):4) {
     sig <- vmat[c(i,j), c(i,j)]
     #solve for alpha
     xvec1c[ind] <- uniroot(function(x) nor.func2(x, mod3a, sig), c(.001,.999))$root
     ind <- ind+1
}}
#average the confidence levels
ci1c <- round(mean(1-xvec1c),3)
1-xvec1c
[1] 0.8418427 0.8479629 0.8517045 0.8417620 0.8617851 0.8728127
ci1c
[1] 0.853

This time the confidence levels vary from 84.2% to 87.3% so once again the mean, 85.3%, is probably a reasonable choice for all six.

Producing the error bar plot

In lecture 5 we created a data frame out.mod that contained the variables we needed for the error bar plot.

out.mod <- data.frame(est=coef(mod3a), confint(mod3a), week=rep(1:4,2),     parm=rep(c('Intercept', 'Slope'), c(4,4)))
names(out.mod)[2:3] <- c('low95','up95')

I need to add to this the confidence intervals for the slopes and intercepts using the newly calculated confidence levels. Because the levels are slightly different for the slopes and intercepts I need to do two calculations and extract the intervals for the slopes from one and the intervals for the intercepts from the other.

#calculate confidence intervals for slopes and intercepts
slope.ci <- confint(mod3a, level=ci1c)[5:8,]
int.ci <- confint(mod3a, level=ci1b)[1:4,]

I then add them as two new columns of the data frame out.mod first concatenating the intercept and slope left interval endpoints and then the right interval endpoints.

# add CI to the data frame from before
out.mod$low50 <- c(int.ci[,1], slope.ci[,1])
out.mod$up50 <- c(int.ci[,2], slope.ci[,2])
out.mod
                        est      low95        up95 week      parm
factor(week)1     11.405614   9.830654 12.98057382    1 Intercept
factor(week)2      3.365321   1.919411  4.81123200    2 Intercept
factor(week)3      5.034074   3.659578  6.40856863    3 Intercept
factor(week)4     12.782828   9.948359 15.61729647    4 Intercept
factor(week)1:NAP -1.900156  -3.662941 -0.13737206    1     Slope
factor(week)2:NAP -1.474577  -2.903985 -0.04516933    2     Slope
factor(week)3:NAP -1.913598  -3.077255 -0.74994090    3     Slope
factor(week)4:NAP -8.900178 -11.829266 -5.97108970    4     Slope
                       low50       up50
factor(week)1      10.262940 12.5482878
factor(week)2       2.316276  4.4143667
factor(week)3       4.036842  6.0313051
factor(week)4      10.726348 14.8393076
factor(week)1:NAP  -3.188863 -0.6114496
factor(week)2:NAP  -2.519565 -0.4295896
factor(week)3:NAP  -2.764305 -1.0628911
factor(week)4:NAP -11.041527 -6.7588292

To produce the graph we can use the code from last time except that we need to add one more panel.segments call in the panel function to draw the error bars for the confidence intervals just calculated. Because they're shorter than the 95% confidence intervals I make them thicker and a lighter color.

myprepanel.ci <- function(x,y,lx,ux,subscripts,...) {
list(xlim=range(x, ux[subscripts], lx[subscripts], finite=TRUE))
}
library(lattice)
#add a new line to the panel function from before
dotplot(week~est|parm, data=out.mod, xlab='Estimate', ylab='Week', prepanel=myprepanel.ci, lx=out.mod$low95, ux=out.mod$up95, layout=c(2,1), panel=function(x, y, subscripts){
panel.dotplot(x, y, col=4, pch='+', cex=.6)
panel.segments(out.mod$low95[subscripts], y, out.mod$up95[subscripts], y, lwd=3, col='dodgerblue4', lineend=1)
#new line
panel.segments(out.mod$low50[subscripts], y, out.mod$up50[subscripts], y, lwd=6, col='dodgerblue1', lineend=1)
panel.points(x, y, col='white', pch=16, cex=1.1)
panel.points(x, y, col='dodgerblue4', pch=1, cex=1.2)
panel.abline(v=0, col=2, lty=2)
}, scales=list(x='free'))

fig. 2
Fig. 2  Confidence intervals and point estimates of the slopes and intercepts from the regression model relating richness and NAP. Thin bars are 95% confidence intervals. Thick bars represent confidence intervals at confidence levels (here 85%) that permit making all pairwise comparisons between the different weeks.

Using the dark, skinny bars that are the 95% confidence intervals we see that all the slopes and intercepts are significantly different from zero. To make pairwise comparisons between the slopes and intercepts across different weeks we check to see whether the short, thick error bars overlap. In the slopes column we see that the slopes in weeks 1, 2, and 3 are not significantly different from each other but they are each significantly different from the slope in week 4. In the intercepts panel we see that the week 1 and 4 intercepts are not significantly different, and the week 2 and week 3 intercepts are not significantly different, but the week 1 and week 4 intercepts are both significantly different from each of the week 2 and week 3 intercepts.

Cited references

Course Home Page


Jack Weiss
Phone: (919) 962-5930
E-Mail: jack_weiss@unc.edu
Address: Curriculum of the Environment and Ecology, Box 3275, University of North Carolina, Chapel Hill, 27599
Copyright © 2012
Last Revised--Jan 24, 2012
URL: https://sakai.unc.edu/access/content/group/2842013b-58f5-4453-aa8d-3e01bacbfc3d/public/Ecol562_Spring2012/docs/lectures/lecture6.htm