-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdiet_sim_script.R
More file actions
171 lines (131 loc) · 7.4 KB
/
Copy pathdiet_sim_script.R
File metadata and controls
171 lines (131 loc) · 7.4 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
library(ggplot2)
library(lemon)
library(dplyr)
theme_set(theme_classic())
set.seed(888)
# logit functions
logit <- function(p) {log(p / (1 - p))}
inverse_logit <- function(l) {1 / (1 + exp(-l))}
# ---- Initial Parameters ----
# simulation dimensions
pop_size = 10000 # population size # n
time_points = 5 # time points # k
# population consumption parameters
food_items = c("berries", "preyA", "preyB") # p = 3
n_food = length(food_items)
consume_probs = c(0.75, 0.25, 0.10) # probability that each food is consumed by a random individual
consume_means = c(0.5, 0.0, -1.0) # given that an item is consumed, how much was consumed?
names(consume_means) = names(consume_probs) = food_items # add names to the probs and means
# Variance-covariance of food consumption
# Note, if all food items have variance=1, then the varriance-covariance matrix is equivalent to the correlation matrix.
# Otherwise, additional steps are needed to calculate covariance from correlations.
food_varcov = matrix(data = c(1.0, 0.5, 0.2,
0.5, 1.0, -0.7,
0.2, -0.7, 1.0), # variance-covariance of food consumption
ncol = 3, dimnames = list(food_items, food_items))
# ---- Baseline Population Consumption ----
# Generate random population baseline consumption (Multivariate-normal) from the covariance matrix
pop_consumption = mvtnorm::rmvnorm(n=pop_size, mean=consume_means, sigma=food_varcov)
# Estimates of population statistics (these are highly accurate with large pop size, e.g., 2000)
(diet_mean = apply(X = pop_consumption, MARGIN = 2, FUN = function(x){round(mean(x), 1)})) # mean item consumption
(diet_cor = round(cov(pop_consumption), 1)) # covariance of item consumption
(diet_sd = round(sqrt(diag(diet_cor)), 1)) # sd of item consumption
# Visualize the diet distribution
pop_consumption %>%
reshape2::melt() %>%
transmute(ID = Var1, food = Var2, value = value) %>%
ggplot() +
geom_density(aes(x = value, fill = food, col = food), alpha = .2)
# ---- Baseline Individual Consumption ----
individual_id = seq_len(pop_size) # numeric ID for each individual
# Individual preferences
# For simplicity, 3 preference groups
strategy_table = data.frame(opportunist = c(1, 1, 1), # equally likely to eat all items
avoider = c(0, 1, 1), # complete avoidance of first item
specialist = c(.2, .2, 1.2) # reduced consumption of items 1 and 2, increased consumption of item 3
)
strat_n = nrow(strategy_table) # number of distinct strategies
strategy_probs = c(.7, .05, .25) # proportion of the population that belongs to each preference group
stopifnot(sum(strategy_probs) == 1) # ensure rates add up to 1
# randomly sample from the strategy index, based on the specified rates
strat_indx = sample(x = seq_len(strat_n), size = pop_size, replace = TRUE, prob = strategy_probs)
# Create preference table, using corresponding strategies
individual_strategies = as.matrix(strategy_table[strat_indx, ])
dimnames(individual_strategies) <- list(individual_id, food_items) # set names
# create baseline preference matrix for each individual, from consumption probabilities
consumption_base = matrix(replicate(n = pop_size, consume_probs), nrow = pop_size, byrow = TRUE)
# full individual preferences
individual_consumption_probs = individual_strategies * consumption_base
# ---- Calculate binary consumption over time ----
binary_array = array(NA, dim = c(pop_size, time_points, n_food), dimnames = list(NULL, NULL, food_items))
for(j in seq_len(pop_size)) for (i in seq_len(n_food)) {
multinom_timeseries = rmultinom(n = time_points, size = 1, prob = individual_consumption_probs[j, ])
binary_array[j, ,i] = multinom_timeseries[i, ]
}
# ---- Autoregression ----
AR_array = array(NA, dim = c(pop_size, time_points, n_food), dimnames = list(NULL, NULL, food_items))
# burn in for AR generation
burn_in = 2000
# AR coefficients for each food item, in the population.
food_ARcoefs = list("berries" = c(0.1, 0.05), "preyA" = 0.1, "preyB" = 0.1)
stopifnot(length(food_ARcoefs) == n_food)
# Generate an AR time series for each food type within each individual
for (i in seq_len(n_food)) for (j in seq_len(pop_size)) {
AR_timeseries = arima.sim(n = time_points, model = list(ar = food_ARcoefs[[i]]), n.start = burn_in)
AR_array[j, ,i] = AR_timeseries
}
# ---- Individual Quantitative Effects ----
randef_sd = 1
# generate random effect of each individual for each food that will remain consistent over time.
individual_randef = matrix(rnorm(n = pop_size*n_food, sd = randef_sd), nrow = pop_size,
dimnames = list(individual_id, food_items))
# ---- Calculate Quantitative consumption over time ----
consumption_array = array(NA, dim = c(pop_size, time_points, n_food), dimnames = list(NULL, NULL, food_items))
for (i in seq_len(n_food)) {
base_mat = replicate(time_points, pop_consumption[, i]) # population consumption, repeated for each time point
randef_mat = replicate(time_points, individual_randef[, i]) # individual effect, repeated for each time point
food_consumed = base_mat + AR_array[, , i] + randef_mat # regression
consumption_array[, , i] = food_consumed # add value into array
}
# Remove value, if item not consumed by individual
consumption_array[binary_array == 0] = NA
print(round(consumption_array, 2))
## --- Calculate raw statistics ----
# Average population binary consumption across time
cons_prop_avg = apply(consumption_array, 3, function(x)1 - mean(is.na(x)))
(prop_avg_table = data.frame(true = consume_probs, expected = round(apply(individual_consumption_probs, 2, mean), 2),
observed = round(cons_prop_avg, 2)))
# Average population quantitative consumption across time
item_pop_avg = apply(consumption_array, 3, function(x)mean(x, na.rm=TRUE))
(pop_avg_table = data.frame(true = consume_means, observed = round(item_pop_avg, 2)) %>% mutate(diff = observed - true))
# Population varcovariance across time (if possible)
consumption_permute = aperm(consumption_array, c(1, 3, 2)) # rearrange the array
cov_list = list(true = food_varcov) # create a list of covariances
for (t in seq_len(time_points)){
name = paste0("time", t)
cov_list[[name]] = round(cor(consumption_permute[, , t], use = "na.or.complete"), 2) # add to covariance list
}
cov_list
## ---- Visualize population ----
diet_df = reshape2::melt(consumption_permute, varnames = c("individual", "item", "time"), value.name = "consumption")
diet_df %>% ggplot() +
geom_line(aes(x = time, y = consumption, group = individual), show.legend = FALSE) +
facet_grid(item~.)
diet_df %>% ggplot() +
stat_summary(aes(x = item, y = consumption))
# and a subset of individuals
ind_subset <- sample(individual_id, 20)
diet_subset = diet_df %>% filter(individual %in% ind_subset)
# cunsumption through time
diet_subset %>% ggplot() +
geom_line(aes(x = time, y = consumption, group = individual, col = individual), show.legend = FALSE) +
facet_grid(item~.) +
scale_color_viridis_c(option = "plasma", end = .7)
# consumption over full time period
diet_subset %>% ggplot() +
geom_hline(yintercept = 0, linetype = "dashed", col = "black") +
stat_summary(fun.data = mean_se, aes(x = item, y = consumption, fill = item), geom = "bar") +
stat_summary(fun.data = mean_se, aes(x = item, y = consumption)) +
facet_rep_wrap(~individual) +
theme(strip.background = element_blank(), strip.placement = "inside") +
labs(y = "Consumption", x = "Diet Item", col = "Diet Item")