# Analysis of Covariance

```# R from zero to hero # Marco Plebani 29 May 2018```

`rm(list=ls())`

Often we are dealing with experiments or studies in which more than one treatment is applied simultaneously and we want to know what’s their relative effect on the response variable.
We will look at cases in which we are manipulating two explanatory variables.

If one explanatory variable is categorical and the other is continuous, the analysis traditionally used is: Analysis of Covariance (ANCOVA).

```# data from: https://rcompanion.org/rcompanion/e_04.html Input = (" Species Temp Pulse ex 20.8 67.9 ex 20.8 65.1 ex 24 77.3 ex 24 78.7 ex 24 79.4 ex 24 80.4 ex 26.2 85.8 ex 26.2 86.6 ex 26.2 87.5 ex 26.2 89.1 ex 28.4 98.6 ex 29 100.8 ex 30.4 99.3 ex 30.4 101.7 niv 17.2 44.3 niv 18.3 47.2 niv 18.3 47.6 niv 18.3 49.6 niv 18.9 50.3 niv 18.9 51.8 niv 20.4 60 niv 21 58.5 niv 21 58.9 niv 22.1 60.7 niv 23.5 69.8 niv 24.2 70.9 niv 25.9 76.2 niv 26.5 76.1 niv 26.5 77 niv 26.5 77.7 niv 28.6 84.7 ")```
``` dd <- read.table(textConnection(Input),header=TRUE) str(dd) names(dd) <- c("Species","Temp","Pulse") # make column names more readable library(lattice) xyplot(Pulse ~ Temp, groups=Species, data=dd, type=c("p", "r"), auto.key=T) lm1 <- lm(Pulse ~ Temp*Species, data=dd) lm2 <- lm(Pulse ~ Temp+Species, data=dd) lm3 <- lm(Pulse ~ Temp, data=dd) lm4 <- lm(Pulse ~ Species, data=dd) lm0 <- lm(Pulse ~ 1, data=dd) AIC(lm1,lm2,lm3,lm4,lm0) # lm2 is the most "economical" model summary(lm1) summary(lm2)```

```# let's plot a nicer graph with plot() # first subset by species: unique(dd\$Species) ex <- subset(dd, dd\$Species=="ex") niv <- dd[dd\$Species=="niv",] # this normally work... I think the species names have some spaces before or after the visible characters. # this way will work: ex <- subset(dd, dd\$Species==unique(dd\$Species)) niv <- dd[dd\$Species==unique(dd\$Species),] # run a regression for each: lm_ex <- lm(Pulse~Temp, data=ex) lm_niv <- lm(Pulse~Temp, data=niv) # plot the first subset plot(Pulse~Temp, data=ex, xlim=c(16,33), ylim=c(40,105), pch=19, # or 16 col="red" )```
```# add the second subset: points(Pulse~Temp, data=niv) # plot regression lines: abline(lm_ex, lty="solid", col="red" ) abline(lm_niv, lty="dashed", col="black" ) legend("topleft", title="Species:", legend=unique(dd\$Species), pch=c(19,1), lty=c("solid", "dashed"), col=c("red", "black") )```

Plot the lines so that they only predict values within the range of observed values:

```# Set a sequence of hypothetic values for the explanatory variable: temps_ex <- data.frame(Temp=seq(min(ex\$Temp), max(ex\$Temp), 0.01)) # This just helps keeping the following lines of code short and clean: texT<- temps_ex\$Temp # predict values with standard error yy_ex<- predict(lm_ex, data.frame(x=temps_ex), type="response", se=T)```
``` # do the same for niv: temps_niv <- data.frame(Temp=seq(min(niv\$Temp), max(niv\$Temp), 0.01)) tnivT<- temps_niv\$Temp yy_niv<- predict(lm_niv, data.frame(x=temps_niv), type="response", se=T)```
``` plot(Pulse~Temp, data=ex, xlim=c(16,33), ylim=c(40,105), pch=NA ) # this plots a blank graph # plot points: points(Pulse~Temp, data=ex, pch=19, # or 16 col="red" ) points(Pulse~Temp, data=niv) # plot fitted models: # I'm using points() again but with the argument type="l", which plots lines points(x=texT,y=yy_ex\$fit, type="l", lty="solid", col="red" ) points(x=tnivT,y=yy_niv\$fit, type="l", lty="dashed", col="black" ) legend("topleft", title="Species:", legend=unique(dd\$Species), pch=c(19,1), lty=c("solid", "dashed"), col=c("red", "black") )```

Add CI – this bit of code is a bit messy-looking but it works:

```# this just helps keeping the following lines of code short and clean: yysep_ex <- yy_ex\$fit+1.96 * yy_ex\$se yysem_ex <- yy_ex\$fit-1.96 * yy_ex\$se```

```# Again, this just helps keeping the following lines of code short and clean: yysep_niv <- yy_niv\$fit+1.96 * yy_niv\$se yysem_niv <- yy_niv\$fit-1.96 * yy_niv\$se```

Function for making transparent colors (found here):

```makeTransparent<-function(someColor, alpha=100) { newColor<-col2rgb(someColor) apply(newColor, 2, function(curcoldata){rgb(red=curcoldata, green=curcoldata, blue=curcoldata,alpha=alpha, maxColorValue=255)}) }```

Confidence interval as a shaded area:

```polygon(c(texT,rev(texT)),c(yysep_ex,rev(yysem_ex)), col= makeTransparent("red"), border=NA) polygon(c(tnivT,rev(tnivT)),c(yysep_niv,rev(yysem_niv)),col=makeTransparent("black"), border=NA)```

Here I explain how to interpret the results of a slightly more complicated example, with three explanatory variables, two categorical and one continuous.
{"ft_lang_label":"__label__en","ft_lang_prob":0.56190765,"math_prob":0.8751313,"size":4495,"snap":"2021-04-2021-17","text_gpt3_token_len":1555,"char_repetition_ratio":0.10309508,"word_repetition_ratio":0.069846675,"special_character_ratio":0.345495,"punctuation_ratio":0.1935167,"nsfw_num_words":0,"has_unicode_error":false,"math_prob_llama3":0.99718726,"pos_list":[0],"im_url_duplicate_count":[null],"WARC_HEADER":"{\"WARC-Type\":\"response\",\"WARC-Date\":\"2021-04-16T02:38:33Z\",\"WARC-Record-ID\":\"<urn:uuid:a04152e6-17ce-4515-834e-ab45c02cf7a3>\",\"Content-Length\":\"43252\",\"Content-Type\":\"application/http; msgtype=response\",\"WARC-Warcinfo-ID\":\"<urn:uuid:92a583b7-8bec-4bc6-a216-bb5522f1d2a6>\",\"WARC-Concurrent-To\":\"<urn:uuid:cb8fb718-9e60-428f-80ac-f48209ebdc20>\",\"WARC-IP-Address\":\"192.0.78.12\",\"WARC-Target-URI\":\"https://somerscripts.wordpress.com/analysis-of-covariance/\",\"WARC-Payload-Digest\":\"sha1:TAXVCFBJVYMWZD5UK3NCRQURAZY3DUK3\",\"WARC-Block-Digest\":\"sha1:DMNX6JCR4YONWKHXPHFAAEQOMGFE4E7X\",\"WARC-Identified-Payload-Type\":\"text/html\",\"warc_filename\":\"/cc_download/warc_2021/CC-MAIN-2021-17/CC-MAIN-2021-17_segments_1618038088471.40_warc_CC-MAIN-20210416012946-20210416042946-00566.warc.gz\"}"}