Libraries

I used the library function to load the necessary packages, so I can visulalise my data:

library(tidyverse)
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr     1.2.1     ✔ readr     2.2.0
## ✔ forcats   1.0.1     ✔ stringr   1.6.0
## ✔ ggplot2   4.0.3     ✔ tibble    3.3.1
## ✔ lubridate 1.9.5     ✔ tidyr     1.3.2
## ✔ purrr     1.2.2     
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag()    masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors

Simulating data for a linear regression

First, I created the function simulate_plant_growth to simulate plant growth data based on soil moisture. I used the base parameters from Week 5 and generated 500 random soil moisture values between 0.1 to 5, which provides a large sample pool and randomness to represent real life variation. I set alpha, the intercept of the regression equation, as 2. I set beta, the slope of the regression equation, as 20. So for every increase in soil moisture, the growth rate will increase by 20.

I generated random error with a mean of 8 and SD of 8 using rnorm function

I then used the data frame function to combine the two variables soil_moisture and growth_rate to create a data frame.

simulate_plant_growth <- function(n = 500, 
                                  alpha = 2, 
                                  beta1 = 20, 
                                  rse = 8, 
                                  moisture_range = c(0.1, 5.0)) {
  
  soil_moisture <- runif(n, min = moisture_range[1], max = moisture_range[2])
  error <- rnorm(n, mean = 8, sd = rse)
  growth_rate <- alpha + beta1 * soil_moisture + error
  
  data.frame(
    soil_moisture = soil_moisture,
    growth_rate = growth_rate
  )
}

Setting the seed using my student number

Student number is sensitive information so the output and input is hidden. Setting seed function sets a random seed so that the simulation will give the same random values each time I run the code, making the results reproducible.

I created the object data_single function to store the data frame. Then I used the head function to see the first six observations of the dataset.

data_single <- simulate_plant_growth()

head(data_single) 
##   soil_moisture growth_rate
## 1     1.9136533    46.78341
## 2     0.6724408    18.56349
## 3     2.1643016    66.48234
## 4     0.5373532    14.55844
## 5     1.3782282    39.36486
## 6     4.9358778   106.16979

Fitting a linear regression predicting growth rate from soil moisture

I used the lm function to fit a linear regression model to observe the relationship between growth rate and soil moisture. I used data = data_single to tell R to use the data_single data set for this. Overall, this tells R to find the line of best fit to describe the relationship between soil moisture and plant growth rate:

model <- lm(growth_rate~soil_moisture,data = data_single)

Displaying the regression summary table using the summary function:

summary(model) 
## 
## Call:
## lm(formula = growth_rate ~ soil_moisture, data = data_single)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -25.7796  -4.6049   0.2961   4.8724  21.7379 
## 
## Coefficients:
##               Estimate Std. Error t value Pr(>|t|)    
## (Intercept)     9.5894     0.7449   12.87   <2e-16 ***
## soil_moisture  19.9130     0.2434   81.81   <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 7.706 on 498 degrees of freedom
## Multiple R-squared:  0.9307, Adjusted R-squared:  0.9306 
## F-statistic:  6693 on 1 and 498 DF,  p-value: < 2.2e-16

Running the ANOVA test to analyse variance

Here I generated an ANOVA table using the anova function to see whether soil moisture was responsible for the observed significance in variation in plant growth rate:

anova(model)
## Analysis of Variance Table
## 
## Response: growth_rate
##                Df Sum Sq Mean Sq F value    Pr(>F)    
## soil_moisture   1 397457  397457  6693.1 < 2.2e-16 ***
## Residuals     498  29573      59                      
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Calculating the sums of squares and R-squared

Sum of squares is used to understand the dispersion of data points, and how far or close the observed numbers are from the average.

R squared is needed to determine the proportion of the total variation of the dependent variable that can be explained by the independent variable

To find these values, I first used the mutate function to add three new columns: fitted, resid model and residual_mean to my dataset. These values are necessary to find the SSE and SST:

fitted = predicted (model) is used to calculate the predicted growth rate for each plant based on the regression line

residual_model is used to tell us how far the observation is from the regression line. This will be used to calculate the SSE (residual sum of squares)

residual mean is used to calculate how far the growth rates deviate from the mean growth rate.This will be used to calculate the SST (total sum of squares)

data_single <- data_single %>%
  mutate(
    fitted = predict(model),
    residual_model = growth_rate - fitted,
    residual_mean = growth_rate - mean(growth_rate)
  )

SSE is the amount of variation unexplained by the model:

SSE <- sum(data_single$residual_model^2)

SST is the total amount of variation in the observed growth rates around the mean growth rate:

SST <- sum(data_single$residual_mean^2)

To find R squared manually based on equation:

R2 <- 1- (SSE/ SST)

To find R squared from the model I used the summary function:

R2_linear <-summary(model)$r.squared 

To get the final values, I used the cat function to print the results with the label text:

cat("SST:", SST, "\n")
## SST: 427030.1
cat("SSE:", SSE, "\n")
## SSE: 29572.77
cat("Manual R-squared:", R2, "\n")
## Manual R-squared: 0.9307478
cat("Model R-squared:", R2_linear, "\n")
## Model R-squared: 0.9307478

Visualising plant growth and soil moisture:

I used the ggplot function using the data_single dataset. I used the geom_point function to add data points to make it into a scatterplot, to better visualise the data. I set alpha as 0.6 to make points easier to see. I used the geom_smooth function to visualise the trend line of best fit, and se= TRUE to add a shaded 95% confidence band next to the regression line. I used fill() to colour the confidence band red. I coloured the regression line dark blue using the function color. The function theme_classic was used to make the graph look cleaner. Finally I used the labs function to add the x and y labels to the graph:

ggplot(data_single,
       aes(x = soil_moisture, y = growth_rate)) + 
  geom_point(alpha = 0.6) + 
  geom_smooth(method = "lm",
              se = TRUE,
              fill = "red",
              color = "darkblue")+ 
  theme_classic() + 
  labs(
    title = "The Effect of Soil Moisture on Plant Growth Rate", 
    x = "Soil Moisture Content",
    y = "Plant Growth Rate" 
  )
## `geom_smooth()` using formula = 'y ~ x'