# Practical advice on using regression

```{r include=FALSE}
knitr::opts_chunk$set(echo = FALSE,warning = FALSE,message = FALSE,error = TRUE)
set.seed(2)
library(performance)
```

## Introduction

```{block, type="rmdstop", echo =TRUE}
Do not attempt to run through any of the code shown here yourself. This section is an illustration of the concepts involved in running and interpreting a regression. The code, as shown, hides some of the chunks that generated the illustrative data. So the code will not run without data.
```

The previous handout goes through the theory behind regression in some depth. However it not strictly necessary to understand every aspect underlying the theory of fitting a regression line in order to use the technique. There are three related reasons to use regression. The same analysis is used in all three cases, but different aspects of the output are emphasised in order to address the **scientific question**.

1.  To calibrate some form of predictive model. This is most effective when a large proportion of the variance is explained by the regression line. For this to be effective we require reasonably high values of R² and emphasis falls on the form of the model and confidence intervals for the key parameter, which is the slope of the fitted line. This is a measure of how much the dependent variable (plotted on the y axis) changes with respect to each unit change in the independent variable (plotted on the x axis).

2.  To investigate the proportion of variance "explained" by the fitted model. The R² value provides a measure of the variance explained. In the context of explanation this is the quantity that is emphasised. The R² value is a measure of how much scatter there is around the fitted relationship.

3.  To **test** whether there is any evidence **at all** of a relationship. In this context the statistical significance provided by the **p-value** is the useful part of the output, in the context of rejecting the null hypothesis if no relationship at all (slope=0). If the sample size is small the evidence for a relationship will be weaker than with a large sample size. Low R² values (i.e. high levels of scatter) also make it more difficult to detect any evidence of a trend.

## Predictive modelling: Calibration

If everything goes well you could be looking a very clear, linear trend with narrow confidence intervals. This may occur with morphological data where the width of some feature is closely related to the length, or in the context of some calibration experiment.

```{r}
library(ggplot2)
theme_set(theme_bw())
x<-1:100
y<-100+2*x+rnorm(100,0,10)
d<-data.frame(x,y)
mod<-lm(data=d,y~x)
sm<-summary(mod)
  an<-anova(mod)
  a1<-round(coef(mod)[1],2)
  b1<-round(coef(mod)[2],2)
  pval<-round(an[[5]][1],3)
  if(pval<0.001)pval<-"< 0.001"
  if(pval>=0.001)pval<-paste("=",pval,sep=" ")
rsq<-round(sm$r.squared,2)

  txt<-sprintf("The estimated regression equation is y= %s + %sx, R² = %s P-value  %s",a1,b1,rsq,pval)

```

### Plotting the model

Assuming you have a dataframe with a variable called x and another called y.

```{r, echo=TRUE}
g0<-ggplot(d,aes(x=x,y=y))
g0 + geom_point() +geom_smooth(method="lm")
```

### Summarising the model

The model is fitted and summarised using this code.

```{r, echo =TRUE}
mod<-lm(data=d,y~x)
summary(mod)
```

You should be able to look at this output and write a line that looks like this.

`r txt`

### Diagnostic checks

The performance library provides a simple way of running visual diagnostic checks. [@performance].

```{r, echo =TRUE}
performance::check_model(mod)
```

The figure provides some textual advice on what to look for. The assumptions do not all need to be met precisely. When sample sizes are small it may be difficult to spot any violations of the assumptions as the figures will be not very well formed. It may be particularly hard to see if the distribution of the residuals is approximately normal. The QQplot may be the best tool for this.

```{r, echo=TRUE}
performance::check_model(mod, check="qq")
```

Note that although the dots do not fall cleanly along the line they do fall within the confidence intervals. No major violation here. Also although the assumption of normally distributed residuals is a formal necessity for regression, minor violations are generally unimportant.

Do remember that the assumption of normality applies only to the residuals of the model,not to the data themselves. The rationale for looking at the distribution of the data is to check whether any transformations are required to give the data better statistical properties, not to check the assumptions used when fitting the statistical model itself [@zuur2009]

### Advice on writing up

In this situation you should concentrate your write up on interpreting the implications of the slope of the line. You have found a very clear relationship between x and Y. State this. Mention that diagnostic checks showed no violations of the assumptions needed for linear regression. Include the (narrow) confidence intervals for the parameters of the model. Discuss how the quantitative relationship may be used in research.

Remember that the slope represents the change in the value of y for every unit change in x. This can be an important parameter and it does have confidence intervals.

```{r, echo =TRUE}
confint(mod)
```

State the R² value and also make sure that you have clearly stated the sample size, defined the sample space and the methods used to measure the variables in the methods section. You should also state that the p-value was \<0.001 but you don't need to say very much about significance, as you are not interested in the probability that the data may be the result of chance when the scatterplot shows that the relationship is so clear cut. You can mention that diagnostic checks were conducted using the performance package [@performance] in R [@R-base]. The important part of your discussion should revolve around the fitted line itself. You may suspect that the functional form for the relationship is not in fact a straight line. In future studies you might use **nonlinear regression** to model a response, but at this stage you do not yet know how to fit such models formally, so you should just discuss whether a straight line is appropriate. If the slope has a clear interpretation and scientific relevance then discuss the value, with mention of the confidence interval.

## Explanatory modelling:

In many situations the scatter around the line may be much greater that the previous case. This will lead to much less of the variance being explained by the underlying relationship. However there is still a clear relationship visible, providing the sample size is large enough.

```{r}
x<-1:100
y<-100+2*x+rnorm(100,0,100)
d<-data.frame(x,y)
g0<-ggplot(d,aes(x=x,y=y))
g0 + geom_point() +geom_smooth(method="lm")
mod<-lm(data=d,y~x)
sm<-summary(mod)
  an<-anova(mod)
  a1<-round(coef(mod)[1],2)
  b1<-round(coef(mod)[2],2)
  pval<-round(an[[5]][1],3)
  if(pval<0.001)pval<-"< 0.001"
  if(pval>=0.001)pval<-paste("=",pval,sep=" ")
rsq<-round(sm$r.squared,2)

  txt<-sprintf("The estimated regression equation is Y= %s + %sX, R² = %s P-value  %s",a1,b1,rsq,pval)

```

`r txt`

Note that there are no major violations of the assumptions for running a regresssion. The issue is that the relationship is not very strong. There is comparatively small signal to noise ratio as shown by the $R^2$ value.

```{r}
check_model(mod)
```

### Advice on writing up

In this situation the emphasis falls more on the R² value, which here is comparatively low. You should state the p-value in order to confirm that the relationship is in fact significant. You should think about the reasons behind the scatter. It may be that the measurements themselves included a large amount of random error. However in ecological settings the error is more likely to be either simply unexplainable random noise, or some form of process error. The random noise around the line may in fact be associated with additional relationships with other variables which are not included in the simple model. This can be handled by multiple regression which uses more than one variable for prediction, and by a range of other techniques including modern machine learning. However these are more advanced, so you should concentrate on discussing how the model could be improved rather than finding ways to improve it at this stage.

It is always very important to discuss the sample size used in the study in all cases. Small samples may cause type 2 error. Type 2 error is a failure to reject the null hypothesis of no relationship even though there is some relationship there. It occurs when the sample size is too small to detect a relationship, even though one does in fact exist. Notice that we always fail to reject a null hypothesis. We do not state that there is no relationship. Instead we state that the study failed to provide **evidence** of a relationship.

## Testing for a relationship

```{r}
x<-seq(1,100,by =10)
y<-100+2*x+rnorm(10,0,120)
d<-data.frame(x,y)
g0<-ggplot(d,aes(x=x,y=y))
g0 + geom_point() +geom_smooth(method="lm")
mod<-lm(data=d,y~x)
sm<-summary(mod)
  an<-anova(mod)
  a1<-round(coef(mod)[1],2)
  b1<-round(coef(mod)[2],2)
  pval<-round(an[[5]][1],3)
  if(pval<0.001)pval<-"< 0.001"
  if(pval>=0.001)pval<-paste("=",pval,sep=" ")
rsq<-round(sm$r.squared,2)

  txt<-sprintf("The estimated regression equation is Y= %s + %sX, R² = %s P-value  %s",a1,b1,rsq,pval)
  
  Fval<-round(an[[4]][1],2)
  df1<-1
  df2<-8
  
  an
 
```

A smaller sample taken from the same sample space as the previous data set now does lead to an inconclusive study.

`r txt`

Note that there are no major violations of the assumptions for running a regression. The issue is that the relationship is not clear.

```{r}
check_model(mod)
```

### Advice on writing up

In the case of a p-value over 0.05 you may want to note that there may be some indication of a relationship but that the results are statistically inconclusive. There is **insufficient evidence** provided by this particular study to confirm any relationship. The write up should emphasis the p-value and the study size. Include the F ratio `r Fval` and the degrees of freedom of `r df1` on `r df2` . You should make suggestions regarding how future studies may be improved.

## Diagnostics show assumptions not met

There are many ways in which the assumptions of regression are not met. This is why diagnostics are needed. You should look through the handout for the last class in order to understand this more deeply.

What do we do when assumptions are not met?

There is no simple answer to this. A large number of alternative techniques have been designed to analyse data that do not meet the assumptions used in regression. In this course we cannot look at all of them. So we need some simple rules that will help to make the best of the data without introducing a large number of new concepts.

## Skewed independent variable

Sometimes the independent variable is heavily right skewed.

```{r}
x<-rlnorm(20,1,0.8)
y<-100+20*log(x)+rnorm(10,0,10)
d<-data.frame(x,y)
g0<-ggplot(d,aes(x=x,y=y))
g0 + geom_point() +geom_smooth(method="lm")
mod<-lm(data=d,y~x)
sm<-summary(mod)
  an<-anova(mod)
  a1<-round(coef(mod)[1],2)
  b1<-round(coef(mod)[2],2)
  pval<-round(an[[5]][1],3)
  if(pval<0.001)pval<-"< 0.001"
  if(pval>=0.001)pval<-paste("=",pval,sep=" ")
rsq<-round(sm$r.squared,2)

  txt<-sprintf("The estimated regression equation is Y= %s + %sX, R² = %s P-value  %s",a1,b1,rsq,pval)

```

`r txt`

Although you can still run a regression on data such as these, the diagnostic plots will show that many of the assumptions are not met.

```{r}
check_model(mod)
```

A common solution is to transform the independent variable by taking either the square root or the logarithm and then re-run the analysis.

```{r,echo=TRUE}
d$logx<-log10(x)
```

```{r}

g0<-ggplot(d,aes(x=logx,y=y))
g0 + geom_point() +geom_smooth(method="lm")
mod<-lm(data=d,y~logx)
sm<-summary(mod)
  an<-anova(mod)
  a1<-round(coef(mod)[1],2)
  b1<-round(coef(mod)[2],2)
  pval<-round(an[[5]][1],3)
  if(pval<0.001)pval<-"< 0.001"
  if(pval>=0.001)pval<-paste("=",pval,sep=" ")
rsq<-round(sm$r.squared,2)

  txt<-sprintf("The estimated regression equation is Y= %s + %slog(X), R² = %s P-value  %s",a1,b1,rsq,pval)

```

Now the regression looks somewhat better and diagnostic plots will confirm that more assumptions are met.

`r txt`

```{r}
check_model(mod)
```

### Advice on writing up

After a transformation you can write up the results in the same way that you would for any other regression model. However be careful how you interpret the slope and intercept given that you are now using a logarithmic scale.

## Spearman's rank correlation

A very simple non-parametric analysis is very commonly used when regression assumptions are not met. This is Spearman's rank correlation.

```{block, type="rmdwarn",echo=TRUE}
Although Spearman's rank correlation can occasionally be useful, it is not a parametric procedure, so would be only used if nothing else is available. It can be very useful as an input to some multivariate models. It can also be the "go to" technique for very small data sets when the only question of interest is whether some relationship can be detected. The best feature of taking ranks is that it down weights data points with high leverage (outliers at the extremes)
```

```{r}
x<-rlnorm(50,1,0.5)
y<-100+3*x -0.23*x^2+rnorm(50,0,1)
d<-data.frame(x,y)
g0<-ggplot(d,aes(x=x,y=y))
g0 + geom_point() +geom_smooth()
mod<-lm(data=d,y~x)
sm<-summary(mod)
  an<-anova(mod)
  a1<-round(coef(mod)[1],2)
  b1<-round(coef(mod)[2],2)
  pval<-round(an[[5]][1],3)
  if(pval<0.001)pval<-"< 0.001"
  if(pval>=0.001)pval<-paste("=",pval,sep=" ")
rsq<-round(sm$r.squared,2)

  txt<-sprintf(" R² = %s P-value  %s",rsq,pval)
```

### Taking ranks

Spearman's correlation essentially takes the ranks of both of the variables and uses these in a regression. However the procedure does not provide an equation. There are some rather limited circumstances when an actual regression model based on ranks would be useful. This is essentially a non parametric procedure and should only be used if nothing else is possible [@JOHNSON1995]

```{r, echo=TRUE}
d$rankx<-rank(d$x)
d$ranky<-rank(y)
```

```{r}


g0<-ggplot(d,aes(x=rankx,y=ranky))
g0 + geom_point() +geom_smooth(method="lm")
mod<-lm(data=d,ranky~rankx)
sm<-summary(mod)
  an<-anova(mod)
  a1<-round(coef(mod)[1],2)
  b1<-round(coef(mod)[2],2)
  pval<-round(an[[5]][1],3)
  if(pval<0.001)pval<-"< 0.001"
  if(pval>=0.001)pval<-paste("=",pval,sep=" ")
rsq<-round(sm$r.squared,2)

txt<-sprintf(" R² = %s P-value  %s",rsq,pval)

```

`r txt`

### Advice on writing up

Although the relationship between the ranked data can be shown on a scatter-plot with a fitted line, the slope and intercept of such a line usually has little meaning. You therefore just emphasise the R² value after noting that it refers to Spearmans rank correlation, not regression, and the p-value. A simple correlation test in R provides the p-value and the correlation coefficient (rho)

```{r,echo=TRUE}
cor.test(d$y,d$x,method="spearman")

```

```{r}
rho<-cor.test(d$y,d$x,method="spearman")$estimate
rsq<-rho^2
```

So the value of rho is `r round(rho,2)` and the R squared is `r round(rsq,2)`

A better approach may be to use a non linear smoother. See below for an example of how to do this.

## Non linear response

In many data sets the response may not follow a strictly linear trend (as above). Take for example the yearly mean temperature data we looked at previously.

```{r}
library(ggplot2)
library(dplyr)
library(reshape2)
```

```{r}
Temp<-read.csv("https://tinyurl.com/aqm-data/Temp.csv")
Temp2<-melt(Temp[,3:15],id="Year")
Temp2 %>% group_by(Year) %>% summarise(temp=mean(value)) ->TMean
```

```{r}

g0<-ggplot(TMean,aes(x=Year,y=temp))
g0 + geom_point() +geom_smooth(method="lm")
mod<-lm(data=TMean,temp~Year)
sm<-summary(mod)
  an<-anova(mod)
  a1<-round(coef(mod)[1],2)
  b1<-round(coef(mod)[2],4)
  pval<-round(an[[5]][1],3)
  if(pval<0.001)pval<-"< 0.001"
  if(pval>=0.001)pval<-paste("=",pval,sep=" ")
rsq<-round(sm$r.squared,2)

  txt<-sprintf("The estimated regression equation is y= %s + %sx, R² = %s P-value  %s",a1,b1,rsq,pval)
```

You can fit a linear model to these data and report the results.

```{r}
mod<-lm(data=TMean,temp~Year)
summary(mod)
```

`r txt`

Note that the slope of the line corresponds to a temperature increase of `r round((b1*100), 2)` degrees C per century.

However if you look carefully at the scatter-plot and model diagnostics you will see that many of the points fall in clusters on either side of the line. This known as *serial autocorrelation in the residuals*. It is an indication that the model may be ill formed, in other words that a straight line may not be the best way to describe the underlying relationship. A diagnostic check helps to establish this.

```{r}
check_model(mod, check="linearity")
```

One solution may be to use a non-linear smoother (note .. this is not the same as a non-linear model for a functional response). There are many forms of smoothers available. The theory behind their use can be quite complex, but in general terms they will tend to follow the empirical pattern in the response.

```{r,echo=TRUE}
library(mgcv)
g0<-ggplot(TMean,aes(x=Year,y=temp))
g0 + geom_point() + geom_smooth(method="gam", formula =y~s(x)) + geom_smooth(method ="lm", colour="red", se=FALSE)

```

The smoother used here is taken from the mgcv package and is a generalised additive model (GAM). Note that the R code includes se=FALSE which removes the confidence interval for the linear model. This is used here to avoid clutter when the two models are superimposed, but if only the linear model were used the confidence interval would be added as usual. However it would not be strictly valid due to the important violation of the assumption.

Smoothed models do not use an equation that can be written down. Therefore there is no slope to report. They do produce an R squared value. It is also possible to extract the residuals from the model in order to look at the differences between observations and the fitted smmoth trend.

```{r,echo=TRUE}

mod<-gam(data=TMean,temp~s(Year))
summary(mod)
```

### Advice on writing up

In this case you need to discuss the pattern of the response as shown in the scatter-plot with fitted spline. The significance of the overall model can be quoted, but the emphasis falls on the shape of the response and "local" features such a break points and changes in slope.

You might note that there was a very clear linear trend between 1975 and 2010. There was a short period of slight cooling between 1940 and 1975. In a data set with very interpretable single values such as this one you may want to mention extremely cool and warm years explicitly.

It is possible to **cautiously** report the linear trend derived from a regression, but with the caveat that the model does not provide a good fit to the data throughout the range.
