#load packages
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
library(lattice)

function to simulate simple linear regression data

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

#run simulation

set.seed(123)
datasingle <- simulateplantgrowth()
head(datasingle)
##   soilmoisture growthrate
## 1    1.5091298   37.17777
## 2    3.9626952   84.75889
## 3    2.1039869   49.32840
## 4    4.4267853   99.25968
## 5    4.7082897  116.95386
## 6    0.3232268   15.75602

loook at data

# Check the structure and variable types
str(datasingle)
## 'data.frame':    500 obs. of  2 variables:
##  $ soilmoisture: num  1.51 3.96 2.1 4.43 4.71 ...
##  $ growthrate  : num  37.2 84.8 49.3 99.3 117 ...
# Check the number of observations and variables
dim(datasingle)
## [1] 500   2
# Display the first six observations
head(datasingle)
##   soilmoisture growthrate
## 1    1.5091298   37.17777
## 2    3.9626952   84.75889
## 3    2.1039869   49.32840
## 4    4.4267853   99.25968
## 5    4.7082897  116.95386
## 6    0.3232268   15.75602
# Display variable names
names(datasingle)
## [1] "soilmoisture" "growthrate"
# Summarize the variables
summary(datasingle)
##   soilmoisture      growthrate    
##  Min.   :0.1023   Min.   :  2.07  
##  1st Qu.:1.3054   1st Qu.: 35.89  
##  Median :2.4351   Median : 58.18  
##  Mean   :2.5269   Mean   : 60.71  
##  3rd Qu.:3.6912   3rd Qu.: 86.04  
##  Max.   :4.9971   Max.   :123.89
# Check for missing values
colSums(is.na(datasingle))
## soilmoisture   growthrate 
##            0            0
# Check the range of each numeric variable
sapply(datasingle, range)
##      soilmoisture growthrate
## [1,]    0.1022802   2.069615
## [2,]    4.9970822 123.885300
# Check the distribution of the numeric variables
datasingle %>%
  pivot_longer(
    cols = everything(),
    names_to = "variable",
    values_to = "value"
  ) %>%
  ggplot(aes(x = value)) +
  geom_histogram(bins = 30, fill = "pink", colour = "black") +
  facet_wrap(~variable, scales = "free") +
  theme_minimal() +
  labs(
    title = "Distributions of Simulated Plant Growth Variables",
    x = "Value",
    y = "Frequency"
  )

plot relationship between soil moisture and plant growth

# Create a scatterplot to investigate the relationship
plot(
  growthrate ~ soilmoisture,
  data = datasingle,
  pch = 19,
  col = "purple",
  xlab = "Soil Moisture",
  ylab = "Plant Growth Rate",
  main = "Plant Growth Rate vs. Soil Moisture"
)


## Fit linear model 


``` r
# Fit a linear regression model
fitsingle <- lm(
  growthrate ~ soilmoisture,
  data = datasingle
)

# Display the model results
summary(fitsingle)
## 
## Call:
## lm(formula = growthrate ~ soilmoisture, data = datasingle)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -22.6237  -4.9465   0.2842   5.5494  21.4450 
## 
## Coefficients:
##              Estimate Std. Error t value Pr(>|t|)    
## (Intercept)    9.9927     0.7461   13.39   <2e-16 ***
## soilmoisture  20.0717     0.2586   77.62   <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 8.051 on 498 degrees of freedom
## Multiple R-squared:  0.9237, Adjusted R-squared:  0.9235 
## F-statistic:  6025 on 1 and 498 DF,  p-value: < 2.2e-16
# Extract fitted values and residuals
datasingle <- datasingle %>%
  mutate(
    fitted = predict(fitsingle),
    residuals = resid(fitsingle)
  )

# Display the updated data
head(datasingle)
##   soilmoisture growthrate    fitted  residuals
## 1    1.5091298   37.17777  40.28344 -3.1056647
## 2    3.9626952   84.75889  89.53055 -4.7716535
## 3    2.1039869   49.32840  52.22320 -2.8948018
## 4    4.4267853   99.25968  98.84560  0.4140779
## 5    4.7082897  116.95386 104.49586 12.4580048
## 6    0.3232268   15.75602  16.48041 -0.7243912

plot regression line

# Plot the data and fitted regression line
ggplot(datasingle, aes(x = soilmoisture, y = growthrate)) +
  geom_point(alpha = 0.6, colour = "pink") +
  geom_smooth(method = "lm", se = TRUE, colour = "purple") +
  theme_minimal() +
  labs(
    title = "Linear Regression of Plant Growth on Soil Moisture",
    x = "Soil Moisture",
    y = "Plant Growth Rate"
  )
## `geom_smooth()` using formula = 'y ~ x'

check model asumptions

# Create diagnostic plots for the linear regression
par(mfrow = c(2, 2))
plot(fitsingle)

par(mfrow = c(1, 1))

residuals

# Plot residuals against fitted values
plot(
  datasingle$fitted,
  datasingle$residuals,
  pch = 19,
  col = "pink",
  xlab = "Fitted Values",
  ylab = "Residuals",
  main = "Residuals vs. Fitted Values"
)

# Add a horizontal reference line at zero
abline(h = 0, lty = 2, col = "purple")

Test hypothesis

# Test whether soil moisture is significantly associated with growth
summary(fitsingle)
## 
## Call:
## lm(formula = growthrate ~ soilmoisture, data = datasingle)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -22.6237  -4.9465   0.2842   5.5494  21.4450 
## 
## Coefficients:
##              Estimate Std. Error t value Pr(>|t|)    
## (Intercept)    9.9927     0.7461   13.39   <2e-16 ***
## soilmoisture  20.0717     0.2586   77.62   <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 8.051 on 498 degrees of freedom
## Multiple R-squared:  0.9237, Adjusted R-squared:  0.9235 
## F-statistic:  6025 on 1 and 498 DF,  p-value: < 2.2e-16
# Extract the estimated slope and its p-value
slope <- coef(summary(fitsingle))["soilmoisture", "Estimate"]
pvalue <- coef(summary(fitsingle))["soilmoisture", "Pr(>|t|)"]

# Print the results
cat("Estimated slope:", slope, "\n")
## Estimated slope: 20.07165
cat("P-value:", pvalue, "\n")
## P-value: 2.451417e-280
# Interpret the statistical result
if (pvalue < 0.05) {
  print("Soil moisture has a statistically significant relationship with plant growth.")
} else {
  print("There is insufficient evidence of a statistically significant relationship.")
}
## [1] "Soil moisture has a statistically significant relationship with plant growth."

conclusion

The simulated data were used to investigate the relationship between soil moisture and plant growth rate. A scatterplot and linear regression model were used to examine whether plant growth changes with soil moisture.

The regression slope estimates the change in growth rate associated with a one-unit increase in soil moisture. The p-value indicates whether the observed relationship is statistically significant at the 0.05 significance level. The diagnostic plots help assess whether the linear regression assumptions are reasonable