Функция накопления Purrr может обрабатывать изменяющиеся во времени индексы, если вы передадите их вашей функции моделирования в виде списка со всеми параметрами в нем. Тем не менее, для правильной работы требуется немного споров. Трюк здесь в том, что accumulate() может работать как в списке, так и в векторных столбцах. Вы можете использовать функциональное гнездо() для группировки столбцов в вектор списка, содержащий текущее состояние и параметры популяции, а затем использовать accumulate() в результирующем столбце списка. Это немного сложно объяснить, поэтому я включил демонстрацию, имитирующую логистический рост с постоянным темпом роста или изменяющимся во времени стохастическим темпом роста. Я также включил пример того, как использовать это, чтобы имитировать множественные репликации для данной модели, используя dpylr + purrr + tidyr.
library(dplyr)
library(purrr)
library(ggplot2)
library(tidyr)
# Declare the population growth function. Note: the first two arguments
# have to be .x (the prior vector of populations and parameters) and .y,
# the current parameter value and population vector.
# This example function is a Ricker population growth model.
logistic_growth = function(.x, .y, growth, comp) {
pop = .x$pop[1]
growth = .y$growth[1]
comp = .y$comp[1]
# Note: this uses the state from .x, and the parameter values from .y.
# The first observation will use the first entry in the vector for .x and .y
new_pop = pop*exp(growth - pop*comp)
.y$pop[1] = new_pop
return(.y)
}
# Starting parameters the number of time steps to simulate, initial population size,
# and ecological parameters (growth rate and intraspecific competition rate)
n_steps = 100
pop_init = 1
growth = 0.5
comp = 0.05
#First test: fixed growth rates
test1 = data_frame(time = 1:n_steps,pop = pop_init,
growth=growth,comp =comp)
# here, the combination of nest() and group_by() split the data into individual
# time points and then groups all parameters into a new vector called state.
# ungroup() removes the grouping structure, then accumulate runs the function
#on the vector of states. Finally unnest transforms it all back to a
#data frame
out1 = test1 %>%
group_by(time)%>%
nest(pop, growth, comp,.key = state)%>%
ungroup()%>%
mutate(
state = accumulate(state,logistic_growth))%>%
unnest()
# This is the same example, except I drew the growth rates from a normal distribution
# with a mean equal to the mean growth rate and a std. dev. of 0.1
test2 = data_frame(time = 1:n_steps,pop = pop_init,
growth=rnorm(n_steps, growth,0.1),comp=comp)
out2 = test2 %>%
group_by(time)%>%
nest(pop, growth, comp,.key = state)%>%
ungroup()%>%
mutate(
state = accumulate(state,logistic_growth))%>%
unnest()
# This demostrates how to use this approach to simulate replicates using dplyr
# Note the crossing function creates all combinations of its input values
test3 = crossing(rep = 1:10, time = 1:n_steps,pop = pop_init, comp=comp) %>%
mutate(growth=rnorm(n_steps*10, growth,0.1))
out3 = test3 %>%
group_by(rep)%>%
group_by(rep,time)%>%
nest(pop, growth, comp,.key = state)%>%
group_by(rep)%>%
mutate(
state = accumulate(state,logistic_growth))%>%
unnest()
print(qplot(time, pop, data=out1)+
geom_line() +
geom_point(data= out2, col="red")+
geom_line(data=out2, col="red")+
geom_point(data=out3, col="red", alpha=0.1)+
geom_line(data=out3, col="red", alpha=0.1,aes(group=rep)))
Я думаю, что философия dplyr довольно укоренена в обработке данных, а не в создании данных. Вероятно, есть способ dplyr сделать это как-то, но я бы не рекомендовал его. –
Я делаю довольно много динамического моделирования и сложных систем, где скорость изменения зависит от других параметров, которые также со временем меняются с другими параметрами, которые также меняются со временем ... Звук, похожий на ваш случай. В то время как простая динамика может быть векторизована в R, когда вещи становятся сложными циклами, становится единственным реалистичным решением. Но тогда скорость может стать очень медленной, если вы попытаетесь сделать эти петли в R. Мое решение, как правило, придерживается циклов, но делает интенсивный цикл в RCpp. R отлично, но это не всегда лучшее для всего. К счастью, Rcpp снимает боль с привязки C++ к R – dww
. В этом случае, в частности, проблема заключается в том, что 'lag()' и 'lead()' не работают по строкам, а просто меняют индекс столбец на единицу. Новый 'pop' - это просто' 1.1 * c (NA, tdf $ pop [-length (pop)] '. –