-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathreproducibleReport.qmd
More file actions
281 lines (188 loc) · 10.1 KB
/
Copy pathreproducibleReport.qmd
File metadata and controls
281 lines (188 loc) · 10.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
---
title: "Reproducible Report"
author:
- name:
given: VB
family: Network
affiliation: VectorByte
citation: true
date: 2026-05-31
format: html
editor: visual
---
```{r, include = F, message = F}
# We can hide our set up code chunk using the "echo = FALSE" option.
# We can make sure no messages pop up by adding "message = FALSE".
# Include = FALSE doesn't show the code OR the output
# Load libraries we need
library(tidyverse)
library(kableExtra)
# Get the API ready to access data
source("VecDyn_Dataset_Access.R")
# Get data sets
list_of_dataframes <- searchDatasets("Suffolk Virginia mosquito control")
```
```{r, echo=FALSE}
######## Data Cleaning ##########
# Collapse the datasets into one dataset
mosqDF <- data.frame()
for (i in 1:length(list_of_dataframes)) {
df <- list_of_dataframes[[i]]
mosqDF <- rbind(mosqDF, df)
}
# Make sure date is a date variable
mosqDF$sample_start_date <- ymd(mosqDF$sample_start_date)
# Combine observations from the same date
mosqDFcomb <- mosqDF %>%
group_by(sample_start_date) %>%
summarize(totalMos = sum(sample_value))
# Add year and month variables
mosqDFcomb$month <- month(mosqDFcomb$sample_start_date)
mosqDFcomb$year <- year(mosqDFcomb$sample_start_date)
```
```{r, eval = F, echo = F}
# The eval = F option prevents this chunk from running when we render the document.
# You can use this to turn optional data filters on and off. Try setting eval = T
# and see how the report changes.
mosqDFcomb <- mosqDFcomb %>% filter(year > 2015)
```
## Background
In this section, you can write some background information to set up the rest of the report. This file is set up to help you explore how you can create reports that re-generate automatically when new data are introduced. We will explore ways that you can show or hide code as needed. You will use some of the concepts from the time-dependent regression practical into the report to see how it works.
In this section, we might want to tell the reader what kind of data we are looking at. For example, we might want to tell readers about the time frame represented in the data set and how many data points we have so far. For example:
This report includes mosquito abundance data collected by the Suffolk Virginia Mosquito Control group. It spans `{r} length(unique(mosqDFcomb$year))` years, from `{r} min(mosqDFcomb$year)` to `{r} max(mosqDFcomb$year)`. The data set contains a total of `{r} nrow(mosqDFcomb)` collection days and `{r} nrow(mosqDF)` unique collections.
**Add at least one more sentence to this section using inline code.**
## Data Summaries
In this section, we will display a table of the summary statistics. We will format it nicely instead of leaving it as is.
```{r, echo = FALSE}
# Make an empty table to print later
summaryDat <- data.frame(year = numeric(0),
n = numeric(0),
mean = numeric(0),
median = numeric(0),
min = numeric(0),
max = numeric(0),
outliers = numeric(0))
mosqYears <- unique(mosqDFcomb$year)
# Get the summary statistics for each year
for (i in 1:length(mosqYears)) {
df <- mosqDFcomb %>% filter(year == mosqYears[i])
year <- df$year[1]
n <- nrow(df)
mean <- mean(df$totalMos, na.omit = T)
median <- median(df$totalMos, na.omit = T)
min <- min(df$totalMos, na.omit = T)
max <- max(df$totalMos, na.omit = T)
outliers <- length(boxplot.stats(mosqDFcomb$totalMos)$out) # Note there are other ways to find outliers
sumDF <- c(year, n, mean, median, min, max, outliers)
summaryDat[i, ] <- sumDF
}
```
**This table is a very simple version of what is possible. If you want, research the kableExtra package and see if you can add some simple customizations to this table to make it look nicer.**
```{r, echo = F}
kable(summaryDat, caption = "Summary statistics by year")
```
## Data Exploration
In this section, we will visualized the raw and summarized collection data. In the raw data, we can easily see that data collection occurs seasonally. In other words, we have gaps in the data that we will need to deal with if we decide to model theses data.
```{r, echo = F}
ggplot(mosqDFcomb, aes(x = sample_start_date, y = totalMos))+
geom_point()
```
Using summary statistics can help us visualize big picture patterns better. We can use the mean and median to see how they differ.
```{r, echo = F}
# Make a quick plot of the mean abundance
colors <- c("median" = "blue", "mean" = "red")
ggplot(summaryDat, aes(x = year, y = mean))+
geom_line(aes(color = "mean"))+
geom_point(aes(color = "mean"))+
geom_line(aes(y = median, color = "median"))+
geom_point(aes(y = median, color = "median"))+
theme_bw()+
scale_color_manual(
name = "Statistic",
values = colors)+
labs(x = "Year", y = "Mean Abundance",
title = "Mean and Median Abundance by Year")
```
The year `{r} summaryDat$year[which.max(summaryDat$mean)]` had the highest average mosquito abundance, with an average of `r max(summaryDat$mean)` mosquitoes observed. The year `{r} summaryDat$year[which.max(summaryDat$outliers)]` had the most outlier abundance observations. There were `{r} length(boxplot.stats(mosqDFcomb$totalMos)$out)` total outliers in the data set.
**Make one more plot that might be interesting and add some text to describe it using inline code**
## Model Fitting
We are going to fit a simple model to these data and look at the results. Note that there are gaps in these data, so our typical time series models may have trouble. However, we can collapse the data by month and impute 0s where collections did not occur (presumably because mosquitoes were absent or very nearly so). Then we can fit some simple time series models. Here, we will clean the data in secret but we will display the model fitting code to our readers (using echo = T) for full transparency.
```{r, include = F}
# include = FALSE prevents the code and the output from being displayed, but
# the code chunk is still evaluated.
# Data Cleaning
# Aggregate the totals by month
mosqMonth <- mosqDFcomb %>% group_by(month, year) %>% summarize(totalMos = sum(totalMos)) %>% ungroup()
# See what months are in the data set
unique(mosqMonth$month)
# Expand the data to include all months in the range
mosqMonth <- mosqMonth %>%
complete(month = 1:12 , nesting(year), fill = list(totalMos = 0)) %>%
arrange(year, month)
# Add date column
mosqMonth <- mosqMonth %>%
mutate(date = make_date(year = year, month = month))
```
Here are the aggregated data with zeros imputed for months where collections did not occur.
```{r, echo = F}
ggplot(data = mosqMonth, aes(x = date, y = totalMos))+
geom_line()+
geom_point()
```
We can look at an autocorrelation function plot like we did in our examples to see if there is consistent autocorrelation between observations. It looks like the strongest correlations are with the 6- and 12-month lags.This suggests there is likely an annual pattern of fluctuation. We already saw that from the last graph as well.
```{r, echo = F}
acf(mosqMonth$totalMos)
```
```{r, echo = F}
# Add a general time counter variable
mosqMonth$time <- 1:nrow(mosqMonth)
# Add sine and cosine seasonality terms - k = 12 because t is in months
mosqMonth$sinSeason <- sin((2*pi*mosqMonth$time)/12)
mosqMonth$cosSeason <- cos((2*pi*mosqMonth$time)/12)
# Add lagged predictors
mosqMonth$totalMos_lag1 <- lag(mosqMonth$totalMos, 1)
# Remove new NAs
mosqMonth <- mosqMonth %>% na.omit(totalMos_lag1)
```
**There are two versions of the model to try out. Change the include and eval options on the code chunks and see how the rendered report differs.**
**Advanced option: try fitting your own model**
```{r, include = F, eval = F}
mosqMod <- lm(totalMos ~ time + totalMos_lag1 + sinSeason + cosSeason,
data = mosqMonth)
summary(mosqMod)
```
```{r, include = T, eval = T}
mosqMonth$month <- as.factor(mosqMonth$month)
mosqMod <- lm(totalMos ~ time + totalMos_lag1 + month ,
data = mosqMonth)
summary(mosqMod)
```
**In a true report, we might want to write some text here about the kind of model we fitted to accompany our code. Try that out here to practice communicating about models.**
### Residual Diagnostics
The residual plots show that having 0 abundance during certain months consistently causes a problem for our model. Think of some other ways we could approach modeling these data that would alleviate this problem.
```{r, echo = F}
hist(mosqMod$residuals)
plot(predict(mosqMod), mosqMod$residuals)
acf(mosqMod$residuals)
```
### Model Performance
Here is a plot of the model predictions overlaid on the actual observations. The model $R^2$ was `{r} round(summary(mosqMod)$r.squared, 2)`, which means that `{r} round(summary(mosqMod)$r.squared*100, 0)`% of the variation in the data was explained by the model.
```{r, echo = F}
mosqMonth$pred <- predict(mosqMod)
colors2 <- c("actual" = "black", "predicted" = "purple")
ggplot(data = mosqMonth, aes(x = date, y = totalMos))+
geom_line(aes(color = "actual"))+
geom_point(aes(color = "actual"))+
geom_line(aes(y = pred, color = "predicted"), linewidth = 1.5,
alpha = 0.3)+
scale_color_manual(
name = "Color",
values = colors2)+
theme_bw()+
labs(x = "Time", y = "Total Abundance")
```
## Conclusions and Limitations
It is always good to think about how our models do well and where they fall short to help make appropriate conclusions from the model. Depending on the model you chose to use, the strengths and limitations will be different.
**Take a minute and write about how the model did well and where we could improve or should at least use caution in trusting its conclusions. Try using some inline code to allow the report to be flexible. For example, `{r} length(mosqMonth$pred[mosqMonth$pred < 0])` of the predictions were below zero, which is not possible in reality.**
## Challenge
Using the skills you learned in the time-dependent covariate module, gather mean monthly temperature data for Suffolk, VA for the appropriate time frame and include temperature as a covariate in your model. Consider transforming the response variable (e.g., taking a square-root) to address non-homoskedastic elements of the data.