#r #dplyr
Вопрос:
Альтернативным названием может быть «Использовать задержку в мутации для ссылки на мутацию предыдущих строк».
Я хотел бы включить значения, сгенерированные для предыдущих строк, в качестве входных данных для вычисления мутации. Некоторые данные:
mydiamonds <- diamonds %>%
mutate(Ideal = ifelse(cut == 'Ideal', 1, 0)) %>%
group_by(Ideal) %>%
mutate(rn = row_number()) %>%
arrange(Ideal, rn) %>%
mutate(CumPrice = cumsum(price)) %>%
mutate(InitialPrice = min(price)) %>%
select(Ideal, rn, CumPrice, InitialPrice)
Выглядит так:
mydiamonds %>% head
# A tibble: 6 x 4
# Groups: Ideal [1]
Ideal rn CumPrice InitialPrice
<dbl> <int> <int> <int>
1 0 1 326 326
2 0 2 653 326
3 0 3 987 326
4 0 4 1322 326
5 0 5 1658 326
6 0 6 1994 326
Модель:
mod.diamonds = glm(CumPrice ~ log(lag(CumPrice)) log(rn) Ideal , family = "poisson", data = mydiamonds)
Протестируйте модель:
# new data, pretend we don't know CumPrice but want to use predictions to predict subsequent predictions
mydiamonds.testdata <- mydiamonds %>% select(-CumPrice)
# manual prediction based on lag(prediction), for the first row in each group use InitialPrice
## add coefficients as fields
coeffs <- mod.diamonds$coefficients
mydiamonds.testdata <- mydiamonds.testdata %>%
mutate(CoefIntercept = coeffs['(Intercept)'],
CoefLogLagCumPrice = coeffs['log(lag(CumPrice))'],
CoefLogRn = coeffs['log(rn)'],
CoefIdeal = coeffs['Ideal']
)
Вот как выглядят мои тестовые данные:
mydiamonds.testdata %>% head
# A tibble: 6 x 7
# Groups: Ideal [1]
Ideal rn InitialPrice CoefIntercept CoefLogLagCumPrice CoefLogRn CoefIdeal
<dbl> <int> <int> <dbl> <dbl> <dbl> <dbl>
1 0 1 326 0.0931 0.987 0.0154 -0.000715
2 0 2 326 0.0931 0.987 0.0154 -0.000715
3 0 3 326 0.0931 0.987 0.0154 -0.000715
4 0 4 326 0.0931 0.987 0.0154 -0.000715
5 0 5 326 0.0931 0.987 0.0154 -0.000715
6 0 6 326 0.0931 0.987 0.0154 -0.000715
Не могу использовать функцию predict(), так как мне нужно рекурсивно предсказывать, где прогнозы для предыдущего дня/строки вводятся в текущий день. Вместо этого попробуйте спрогнозировать вручную, используя коэффициенты:
# prediction
mydiamonds.testdata <- mydiamonds.testdata %>%
mutate(
Prediction = CoefIntercept
# here's the hard bit. If it's the first row in the group, use InitialPrice, else use the value of the previous prediction
(CoefLogLagCumPrice * ifelse(rn == 1, InitialPrice, lag(Prediction)))
(CoefLogRn * log(rn))
(CoefIdeal * Ideal)
)
Ошибка: Проблема с
mutate()
вводомPrediction
. x объект
«Прогноз» не найден ℹ ВводPrediction
есть...
. ℹ Ошибка
произошла в группе 1: Идеал = 0.
Как я могу мутировать таким образом, где я хотел бы сослаться на мутацию предыдущих строк? (Если только это не самая первая строка, в этом случае используйте InitialPrice)
[РЕДАКТИРОВАТЬ] следуя за комментатором, я попробовал использовать функцию накопления, с которой я не так хорошо знаком:
mydiamonds.testdata <- mydiamonds.testdata %>%
mutate(
Prediction = accumulate(.f = function(.) {
.$CoefIntercept
# here's the hard bit. If it's the first row in the group, use InitialPrice, else use the value of the previous prediction
(.$CoefLogLagCumPrice * ifelse(.$rn == 1, .$InitialPrice, lag(.$Prediction)))
(.$CoefLogRn * log(.$rn))
(.$CoefIdeal * .$Ideal)
}))
Error: Problem with `mutate()` input `Prediction`.
x argument ".x" is missing, with no default
ℹ Input `Prediction` is `accumulate(...)`.
ℹ The error occurred in group 1: Ideal = 0.
Комментарии:
1. возможно, вам придется использовать некоторую адаптацию
purrr
sreduce()
илиaccumulate()
2. @GuedesBF Я попробовал, смотрите мою обновленную попытку под редакцией
3. @user14328853 вам следовало отредактировать свой другой вопрос, а не создавать новый. Этот, кстати, намного приятнее, хорошая работа по его улучшению!
Ответ №1:
Как вы сказали, вы не привыкли к этой довольно сложной функции, вот небольшое объяснение.
purrr::accumulate()
используется для вычисления рекурсивных операций по строкам. Его первым аргументом .x
является переменная, на которой вы хотите накапливать. Его вторым аргументом .f
является функция , которая должна иметь 2 аргумента: текущий результат cur
и следующее вычисленное значение val
. При первом .f
вызове cur
значение равно .x[1]
(по умолчанию), затем оно равно предыдущему результату, возвращенному .f
.
purrr::accumulate2()
позволяет нам использовать вторую переменную .y
для итерации. Первое значение .y
всегда игнорируется, так как .f
уже известно, что возвращать в это время. Следовательно, .y
должно быть на один пункт меньше, чем .x
.
К сожалению, есть только accumulate()
и accumulate2()
там, где вам нужно accumulate3()
было бы или paccumulate()
накопить на rn, Идеал и цена.
Однако, используя row_number()
и cur_data()
, вы можете обмануть accumulate2()
, чтобы вести себя так, как вы хотите:
CoefIntercept = coeffs['(Intercept)']
CoefLogLagCumPrice = coeffs['log(lag(CumPrice))']
CoefLogRn = coeffs['log(rn)']
CoefIdeal = coeffs['Ideal']
mydiamonds.testdata <- mydiamonds %>%
ungroup() %>%
select(-CumPrice) %>%
mutate(
Prediction = accumulate2(.x=InitialPrice, .y=row_number()[-1],
.f=function(acc, nxt, row) {
db=cur_data_all()
rn = db$rn[row]
Ideal = db$Ideal[row]
CoefIntercept
(CoefLogLagCumPrice * acc)
(CoefLogRn * log(rn))
(CoefIdeal * Ideal)
}) %>% unlist()
)
mydiamonds.testdata
# A tibble: 53,940 x 4
# Ideal rn InitialPrice Prediction
# <dbl> <int> <int> <dbl>
# 1 0 1 326 326
# 2 0 2 326 322.
# 3 0 3 326 318.
# 4 0 4 326 313.
# 5 0 5 326 309.
# 6 0 6 326 305.
# 7 0 7 326 301.
# 8 0 8 326 297.
# 9 0 9 326 294.
# 10 0 10 326 290.
ИЗМЕНИТЬ: Существует другой, более чистый способ использования .init
аргумента, так как InitialPrice
столбец никогда не используется по-настоящему, за исключением его первого значения. Это позволяет напрямую использовать аргументы, но это не будет работать для более сложных моделей с большим количеством ковариат.
mydiamonds.testdata <- mydiamonds %>%
ungroup() %>%
select(-CumPrice) %>%
mutate(
Prediction = accumulate2(.x=Ideal[-1], .y=rn[-1],
.init=InitialPrice[1],
.f=function(rslt, Ideal, rn) {
CoefIntercept
(CoefLogLagCumPrice * rslt)
(CoefLogRn * log(rn))
(CoefIdeal * Ideal)
}) %>% unlist()
)
Комментарии:
1. ПОТРЯСАЮЩЕ, @Dan Chaltiel!
2. Это фантастика, спасибо! Я только что открыл свой рабочий ноутбук и увидел это, с нетерпением ожидая, чтобы попробовать это сегодня с таким подходом, расскажу, как у меня дела.
3. Это действительно сработало! Спасибо. В первом методе, который я использую, поскольку реальные данные действительно имеют больше коэффициентов, почему вы разгруппировали() тестовые данные? Номер строки указан для каждой группы, так как идея заключается в том, что совокупная сумма находится в пределах совокупной суммы группы. Я просто собирался удалить строку ungroup (), но хотел убедиться, что я здесь чего-то не пропустил?
4. @user14328853 Я разогруппировался по привычкам, потому что не был уверен, что моя функция будет хорошо работать с группами. С другой стороны, это должно сработать.
5. @user14328853
accumulate2()
всегда производит такое впечатление 🙂 Рад, что смог помочь!