#r #purrr
#r #purrr
Вопрос:
Допустим, у меня есть приведенный ниже набор данных. Он содержит параметр нецентральности (NCP), степени свободы (DF) и количество симуляций (10 000) для кандидата от каждой партии в трех штатах. Как вы можете видеть, у некоторых рас нет кандидатов для данной партии:
dat <- tibble(state = c("Iowa", "Wisconsin", "Minnesota"),
ncp_D = c(0, 11000, 5700),
ncp_R = c(10000, 12000, 5000),
ncp_Ind = c(1800, 0, 600),
df_D = c(10),
df_R = c(10),
df_Ind = c(10),
sims_D = c(10000),
sims_R = c(10000),
sims_Ind = c(10000))
Я хотел бы, чтобы код произвел 10000 симуляций для каждого кандидата в трех состояниях с использованием purrr
пакета. Ниже приведен код, который я использую для запуска этого процесса на основе t-дистрибутива ( rt()
):
dat_results <- dat %>%
mutate(DVotes = pmap(list(sims_D, df_D, ncp_D), rt),
RVotes = pmap(list(sims_R, df_R, ncp_R), rt),
IndVotes = pmap(list(sims_Ind, df_Ind, ncp_Ind), rt))
Это создает три списка возможностей голосования в dat_results
фрейме данных, но в конечном итоге я хочу, чтобы списки, созданные для кандидата, были полны нулей, если их значение ncp равно нулю. Например, у кандидата D в Айове должны быть предсказанные значения, основанные на rt()
функции, равными 10000 нулям вместо значений, которые используют 0 в качестве своего NCP, что приводит к некоторым отрицательным значениям. То же самое с кандидатом Ind в Висконсине. По сути, я пытаюсь условно перезаписать список во фрейме данных.
Есть ли простой способ сделать это в R, предпочтительно используя purrr
пакет? Заранее спасибо.
Ответ №1:
В вашем случае, я думаю, проще всего изменить rt()
функцию:
cond_rt <- function(n, df, ncp, ...){
if(ncp == 0) return(rep(0, n))
rt(n, df, ncp, ...)
}
Затем просто используйте эту измененную версию:
dat_results <- dat %>%
mutate(DVotes = pmap(list(sims_D, df_D, ncp_D), cond_rt),
RVotes = pmap(list(sims_R, df_R, ncp_R), cond_rt),
IndVotes = pmap(list(sims_Ind, df_Ind, ncp_Ind), cond_rt))
map_dbl(dat_results$DVotes, length)
#> [1] 10000 10000 10000
map_dbl(dat_results$DVotes, sum)
#> [1] 0 119262980 61756273
Но если вы действительно хотите условно изменить столбец апостериорно, это можно было бы сделать с помощью mutate()
и if_else()
. Мы просто сталкиваемся с проблемой, поскольку нам нужно читать и записывать элементы списка, это можно решить с помощью rowwise()
(для чтения одного элемента строки за раз) и вызова list()
на выходе, так что мы получаем список длиной 1, который можно вставить как элемент.
dat_results2 <- dat %>%
mutate(DVotes = pmap(list(sims_D, df_D, ncp_D), rt),
RVotes = pmap(list(sims_R, df_R, ncp_R), rt),
IndVotes = pmap(list(sims_Ind, df_Ind, ncp_Ind), rt)) %>%
rowwise() %>%
mutate(DVotes = if_else(ncp_D == 0, list(rep(0, length(DVotes))), list(DVotes)),
RVotes = if_else(ncp_R == 0, list(rep(0, length(RVotes))), list(RVotes)),
IndVotes = if_else(ncp_Ind == 0, list(rep(0, length(IndVotes))), list(IndVotes)))
map_dbl(dat_results2$DVotes, length)
#> [1] 10000 10000 10000
map_dbl(dat_results2$DVotes, sum)
#> [1] 0 119172966 61629269
Вероятно, это можно было бы упростить с помощью across()
.
Комментарии:
1. Спасибо за это, @Alexlok. Краткий вопрос: допустим, я хочу, чтобы функция cond_rt возвращала только неотрицательные значения. (То есть любые отрицательные значения, возвращаемые функцией, преобразуются в ноль.) Прямо сейчас, если NCP чуть выше нуля, функция вернет отрицательные значения, поскольку она следует правилам t-распределения. У вас есть предложения о том, как реализовать это в логике функции? Еще раз спасибо.
2. Простое установление порога должно работать:
x <- rt(...); x[x<0] <- 0
. Но результирующее распределение больше не является надлежащим нецентральным распределением t, поэтому я не знаю, будет ли анализ по-прежнему правильным.