1 Development of the Contrast Sensitivity Function

The contrast sensitivity function (CSF) relates visual sensitivity (i.e., the reciprocal of minimum contrast needed to detect a pattern) to the spatial frequency of the visual target (i.e., a sine wave grating). The CSF is an important clinical tool and also has been used to characterize visual mechanisms that constrain vision in a variety of contexts. An experiment was conducted to assess the change in the CSF in 1-3 month old human infants. Contrast sensitivity was measured for sine wave gratins with spatial frequencies of 1, 2, 3, and 4 cycles per degree.Twenty infants in three age groups (4, 8, and 12 weeks) participated in the study and each infant was tested with all four spatial frequencies. The data are stored in the long- and wide-format data frames csf.long and csf.wide, and in the matrix csf.mat.

options(contrasts=c("contr.sum","contr.poly"))
load(url("http://pnb.mcmaster.ca/bennett/psy710/datasets/csf2022.rda") )
summary(csf.long)
##      subjID     age       sf      sensitivity      
##  s1     :  4   w12:80   sf1:60   Min.   :  0.2558  
##  s2     :  4   w4 :80   sf2:60   1st Qu.:  2.9995  
##  s3     :  4   w8 :80   sf3:60   Median :  6.7183  
##  s4     :  4            sf4:60   Mean   : 11.7792  
##  s5     :  4                     3rd Qu.: 14.5027  
##  s6     :  4                     Max.   :112.1023  
##  (Other):216
sapply(csf.wide,class)
##    subjID       age       sf1       sf2       sf3       sf4 
##  "factor"  "factor" "numeric" "numeric" "numeric" "numeric"
  1. Use ANOVA to evaluate the effects of age and sf on sensitivity. Where necessary, correct the \(p\) values for deviations from sphericity. Do all of the \(p\) have to be adjusted? Why or why not?
options(contrasts=c("contr.sum","contr.poly"))
csf.aov.00 <- aov(sensitivity~age*sf+Error(subjID/(sf)),data=csf.long)
summary(csf.aov.00) # assumes sphericity
## 
## Error: subjID
##           Df Sum Sq Mean Sq F value  Pr(>F)
## age        2   6259  3129.4   7.355 0.00144
## Residuals 57  24251   425.5                
## 
## Error: subjID:sf
##            Df Sum Sq Mean Sq F value   Pr(>F)
## sf          3   9611    3204  33.125  < 2e-16
## age:sf      6   3843     640   6.622 2.59e-06
## Residuals 171  16538      97
# next anova corrects p values:
library(afex)
csf.aov_car.00 <- aov_car(sensitivity~age*sf+Error(subjID/(sf)),data=csf.long)
summary(csf.aov_car.00)
## 
## Univariate Type III Repeated-Measures ANOVA Assuming Sphericity
## 
##             Sum Sq num Df Error SS den Df F value    Pr(>F)
## (Intercept)  33300      1    24251     57 78.2700 2.747e-12
## age           6259      2    24251     57  7.3555   0.00144
## sf            9611      3    16538    171 33.1253 < 2.2e-16
## age:sf        3843      6    16538    171  6.6223 2.594e-06
## 
## 
## Mauchly Tests for Sphericity
## 
##        Test statistic    p-value
## sf            0.17456 2.0783e-19
## age:sf        0.17456 2.0783e-19
## 
## 
## Greenhouse-Geisser and Huynh-Feldt Corrections
##  for Departure from Sphericity
## 
##         GG eps Pr(>F[GG])
## sf     0.52055  6.306e-10
## age:sf 0.52055  0.0003606
## 
##           HF eps   Pr(>F[HF])
## sf     0.5325793 4.199534e-10
## age:sf 0.5325793 3.180706e-04
# anova(csf.aov_car.00,correction="HF") # lists anova table with corrected p values
## Sphericity does not apply to age because it is a between-subject variable, but sphericity is relevant to all of the other effects becuase they are within-subject factors that have more than 1 degree of freedom. Note that the Mauchly Test is significant, so the variance-covariance matrix of the residuals deviates significantly from sphericity.
  1. Use lmer in the lmerTest package to evaluate the effects of age, and sf (and interactions) with a mixed model. Treat subj as a random factor and all the other factors as fixed. Evaluate the fixed effects with \(F\) tests that assume sphericity and chi-square tests that do not assume sphericity.
library(lmerTest)
csf.lmer.01 <- lmer(sensitivity~age*sf + (1|subjID),data=csf.long)

# F tests:
print(anova(csf.lmer.01)) # assumes sphericity/independence
## Type III Analysis of Variance Table with Satterthwaite's method
##        Sum Sq Mean Sq NumDF DenDF F value    Pr(>F)
## age    1422.8   711.4     2    57  7.3555   0.00144
## sf     9611.0  3203.7     3   171 33.1253 < 2.2e-16
## age:sf 3842.8   640.5     6   171  6.6223 2.594e-06

# chi-square tests:
library(car)
print(Anova(csf.lmer.01,type="III")) # does not assume sphericity
## Analysis of Deviance Table (Type III Wald chisquare tests)
## 
## Response: sensitivity
##              Chisq Df Pr(>Chisq)
## (Intercept) 78.270  1  < 2.2e-16
## age         14.711  2  0.0006391
## sf          99.376  3  < 2.2e-16
## age:sf      39.734  6  5.138e-07
  1. Use lme in the nlme package to evaluate the effects of age, and sf (and interactions) with a mixed model. Treat subj as a random factor and all the other factors as fixed. For this model, assume that the variance-covariance matrix of the residuals is not compound symmetric. In other words, allow the correlations between levels of the within-subject factor to vary (i.e., not be a constant value). List the ANOVA table for the fixed effects.
# we use correlation=corSym... allows correlations to vary
library(nlme)
csf.lme.01 <- lme(fixed = sensitivity~age*sf,
                  data=csf.long,
                  random = ~1|subjID,
                  correlation=corSymm(form=~1|subjID))
print(anova(csf.lme.01)) # does not assume compound symmetry
##             numDF denDF  F-value p-value
## (Intercept)     1   171 69.69831  <.0001
## age             2    57  6.81418  0.0022
## sf              3   171 20.89030  <.0001
## age:sf          6   171  6.51185  <.0001


# the correlations are listed in the output of the summary command:
# summary(csf.lme.01)
# Correlation Structure: General
#  Formula: ~1 | subjID 
#  Parameter estimate(s):
#  Correlation: 
#   1      2      3     
# 2 -0.130              
# 3  0.647 -0.524       
# 4  0.795 -0.511  0.806
  1. Use Tukey tests to evaluate the pairwise differences among age groups (while ignoring spatial frequency).
# with emmeans:
library(emmeans)
csf.emm <- emmeans(csf.aov_car.00,specs="age")
contrast(csf.emm,method="pairwise",adjust="tukey")
##  contrast estimate   SE df t.ratio p.value
##  w12 - w4    12.38 3.26 57   3.795  0.0010
##  w12 - w8     7.76 3.26 57   2.378  0.0534
##  w4 - w8     -4.62 3.26 57  -1.417  0.3391
## 
## Results are averaged over the levels of: sf 
## P value adjustment: tukey method for comparing a family of 3 estimates

# with wide-format df
print(csf.wide[1,]) # check columns
##   subjID age      sf1      sf2      sf3      sf4
## 1     s1  w4 18.72468 13.24864 21.88602 8.299064

avg.sens <- rowMeans(csf.wide[,3:6]) # average sensitivity for each subject
ageGroup <- csf.wide$age
age.aov.01 <- aov(avg.sens~ageGroup)
TukeyHSD(age.aov.01)
##   Tukey multiple comparisons of means
##     95% family-wise confidence level
## 
## Fit: aov(formula = avg.sens ~ ageGroup)
## 
## $ageGroup
##              diff        lwr         upr     p adj
## w4-w12 -12.377067 -20.225188 -4.52894532 0.0010338
## w8-w12  -7.756493 -15.604614  0.09162851 0.0533853
## w8-w4    4.620574  -3.227547 12.46869506 0.3391456
  1. Use a linear contrast to determine if the quadratic trend of sensitivity across spatial frequency differed across ages. Use Tukey tests to do pairwise comparisons of the quadratic trends in each age group.
sort(unique(csf.long$sf)) # get the values on the sf variable
## [1] sf1 sf2 sf3 sf4
## Levels: sf1 sf2 sf3 sf4
quad.weights <- contr.poly(n=4,scores=c(1,2,3,4))[,2] # just need 2nd column
csf.mat[1,] # check column names of matrix
##       sf1       sf2       sf3       sf4 
## 18.724685 13.248642 21.886018  8.299064
quad.scores <- csf.mat %*% quad.weights
ageGroup <- csf.wide$age
quad.aov.01 <- aov(quad.scores~ageGroup)
summary(quad.aov.01,intercept=TRUE)
##             Df Sum Sq Mean Sq F value   Pr(>F)
## (Intercept)  1   5458    5458   38.29 7.07e-08
## ageGroup     2   3021    1510   10.59 0.000122
## Residuals   57   8126     143

# grand mean is signficantly different from zero
# and quadratic trend differs across groups

# Tukey test(below) indicates that quadratic trend in 12 week olds differs from
# quadratic trend in the other two groups (but 4 & 8 week olds do not differ
# from each other)

TukeyHSD(quad.aov.01)
##   Tukey multiple comparisons of means
##     95% family-wise confidence level
## 
## Fit: aov(formula = quad.scores ~ ageGroup)
## 
## $ageGroup
##             diff        lwr       upr     p adj
## w4-w12 17.250708   8.164760 26.336655 0.0000786
## w8-w12 10.458769   1.372821 19.544716 0.0203371
## w8-w4  -6.791939 -15.877887  2.294008 0.1791234

# These results are reasonably consistent with a graphical depiction of the results...