Как использовать mutate () для генерации переменных, которые зависят от предыдущих значений строк других новых переменных? - PullRequest
2 голосов
/ 03 мая 2019

Я пытаюсь использовать функцию dplyr mutate() для создания новых переменных, которые зависят от предыдущих значений строк последующих новых переменных.

Я искал SO с другими терминами, чтобы увидеть, что что-то щелкает, и самое близкое, что я пришел, это этот ответ. Это грубая структура tibble tib У меня есть:

library(dplyr)
library(magrittr)

tib <- tribble(
  ~ID,
  "A1",
  "A2",
  "A3",
  "A4",
  "A5",
  "A1", 
  "B1",
  "B2",
  "B3"
)

Я хочу использовать mutate(), чтобы иметь возможность генерировать столбцы x, y и z:

tib %<>%
  mutate(
    x = if_else(ID == "A1", 2, lag(y) + lag(z)),
    y = if_else(ID == "A1", 3, x + lag(z)),
    z = if_else(ID == "A1", 7, lag(z))
  )

Например, для значений, показанных выше, я бы хотел, чтобы результат был:

|  ID  |   x   |   y   |   z   |
--------------------------------
|  A1  |   2   |   3   |   7   |
|  A2  |   10  |   17  |   7   |
|  A3  |   24  |   31  |   7   |
|  A4  |   38  |   45  |   7   |
|  A5  |   52  |   59  |   7   |
|  A1  |   2   |   3   |   7   |
|  B1  |   10  |   17  |   7   |
|  B2  |   24  |   31  |   7   |
|  B3  |   38  |   45  |   7   |
--------------------------------

Проблема этого метода в том, что mutate() возвращает ошибку:

Error in lag(y) : object 'y' not found

Я понимаю, что имею в виду y и z, прежде чем я их инициирую. Если бы x было чем-то, что зависело только от него самого, как в связанном выше вопросе, я мог бы сделать это в несколько проходов, как это предлагалось там, но я не думаю, что это возможно здесь.

Как предлагается в комментариях к моему вопросу, если я попытаюсь инициализировать эти значения (чтобы были известны y и z), как показано ниже,

tib %<>%
  mutate(
    x = if_else(ID == "A1", 2, 0),
    y = if_else(ID == "A1", 3, 0),
    z = if_else(ID == "A1", 7, 0)
  )

tib %<>%
  mutate(
    x = if_else(ID == "A1", 2, lag(y) + lag(z)),
    y = if_else(ID == "A1", 3, x + lag(z)),
    z = if_else(ID == "A1", 7, lag(z))
  )

Вот что я понимаю:

# A tibble: 9 x 4
  ID        x     y     z
  <chr> <dbl> <dbl> <dbl>
1 A1        2     3     7
2 A2       10    17     7
3 A3        0     0     0
4 A4        0     0     0
5 A5        0     0     0
6 A1        2     3     7
7 B1       10    17     7
8 B2        0     0     0
9 B3        0     0     0

что отличается от того, что я ожидаю получить (возможно, потому что mutate() оценивает все переменные по столбцам, поэтому y и z равны 0)?

Надеюсь, чтобы выразить это более четко, я хочу иметь возможность вычислять значения для каждого из новых столбцов на основе значений, присутствующих в предыдущих строках указанных столбцов - у них всегда будет какая-то строка, в которой они получают начальные значения , но как заставить его перетекать в нижние ряды?

Если это поможет, вот как я бы хотел, чтобы это работало в Excel (я только начинаю изучать R).

Я хотел бы продолжить использовать dplyr для обеспечения согласованности с моим кодом.

1 Ответ

2 голосов
/ 04 мая 2019

mutate() на самом деле не работает с итеративными формулами, такими как Excel. Он работает по столбцам, поэтому иметь связь между каждой итерацией строки нелегко. В этом конкретном случае ваша функция имеет простые нерекурсивные определения. Вот функция-обертка, которая инкапсулирует неитеративные версии

my_mutate <- function(data, x0, y0, z0) {
  mutate(data, 
    n = 1:n(),
    x = if_else(n==1, x0, y0 + z0*(n-1)),
    y = if_else(n==1, y0, y0 + z0*2*(n-1)),
    z = z0,
    n = NULL
  )
}

Тогда мы можем выполнить внутригрупповые преобразования с помощью

tib %>% group_by(grp=cumsum(ID=="A1")) %>% 
  my_mutate(x0=2, y0=3, z0=7) %>% 
  ungroup %>% select(-grp)
#   ID        x     y     z
#   <chr> <dbl> <dbl> <dbl>
# 1 A1        2     3     7
# 2 A2       10    17     7
# 3 A3       17    31     7
# 4 A4       24    45     7
# 5 A5       31    59     7
# 6 A1        2     3     7
# 7 B1       10    17     7
# 8 B2       17    31     7
# 9 B3       24    45     7

С неитеративными определениями гораздо легче справиться, когда они существуют.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...