Как вычислить значения в R-фрейме данных, когда столбцы зависят друг от друга

#r #dataframe

#r #фрейм данных

Вопрос:

Плакат в первый раз — так что прошу прощения, если этот вопрос простой / плохо объясненный. Благодарен любому, кто может помочь или указать мне правильное направление!

Я хотел бы сделать следующее в R-фрейме данных, если это возможно:

Существующие данные

Столбец A представляет собой вектор значений, скажем, от 10 до 20.

Новые данные / столбцы

Столбец B будет представлять собой столбец A, умноженный на столбец C

Столбец C будет представлять собой столбец C минус столбец B из предыдущей строки данных, т.е. Данные $ C [-1] — данные $ B [-1], за исключением, конечно, первой строки столбца C, которой я дам фиксированное значение.

Я пробовал это как отдельные шаги, но я продолжаю перезаписывать столбцы B и C, и у меня такое чувство, что я шел по этому пути неправильно! Я мог бы поделиться своим кодом, но я думаю, что это запутало бы дело!

Заранее спасибо!

ОТРЕДАКТИРУЙТЕ, ЧТОБЫ ДОБАВИТЬ КОД:

 A <- c(0.1,0.2,0.3,0.4,0.5)
df1 <- data.frame(A)

df1$B <- 0 
df1$C <- 0 

df1$C[1] <- 100

df2 <- df1 %>%
  mutate(B = C * A,
         C = lag(C-B))
 

РЕЗУЛЬТАТ ИЗ ВЫШЕИЗЛОЖЕННОГО

A B C
1 0.1 10 NA
2 0.2 0 90
3 0.3 0 0
4 0.4 0 0
5 0.5 0 0

ОЖИДАЕМЫЙ РЕЗУЛЬТАТ

A B C
1 0.1 10 100
2 0.2 18 90
3 0.3 21.6 72
4 0.4 20.16 50.4
5 0.5 15.12 30.24

C2 = C1 — B1 B2 = C2 * A2

Ответ №1:

Мы можем использовать accumulate from purrr для выполнения рекурсивного обновления

 library(dplyr)
library(purrr)
tmp <-  with(df1, accumulate(A,  ~ .x - (.x * .y), .init = first(C)))
df2 <- df1 %>% 
    mutate(C = head(tmp, -1), B = -diff(tmp))
df2
#    A     B      C
#1 0.1 10.00 100.00
#2 0.2 18.00  90.00
#3 0.3 21.60  72.00
#4 0.4 20.16  50.40
#5 0.5 15.12  30.24
 

Или использовать base R

 tmp <- with(df1, Reduce(function(x, y) x - (x * y), A, 
     accumulate = TRUE, init = C[1]))
df2 <- transform(df1, C = head(tmp, -1), B = -diff(tmp))
 

Комментарии:

1. Спасибо! Я думаю, что я почти на месте. Я немного изменил ваш приведенный выше код на lag (C-B), см. Ниже. Однако C1 изменяется на NA (но я бы хотел, чтобы это оставалось равным 100), и я все еще получаю 0 для других значений. В идеале я хотел бы получить 18 (0,2 * 90) в B2 и 72 (90-18) в C3. И так далее. Извините, если я что-то пропустил! A <- c(0.1,0.2,0.3,0.4,0.5) df1 <- data.frame(A) df1$B <- 0 df1$C <- 0 df1$C[1] <- 100 df2 <- df1 %>% мутировать(B = C * A,C = задержка (C-B))

2. @Tyingtocode без воспроизводимого примера сложно протестировать

3. Я добавил приведенный выше код в свой первоначальный пост выше вместе с результирующей таблицей. Помогает ли это в качестве воспроизводимого примера? Единственные значения, которые я подключаю к этому тесту, — это вектор A. Еще раз спасибо!

4. @Tyingtocode можете ли вы обновить свой пост с ожидаемым результатом

5. Работает идеально! Большое спасибо!

Ответ №2:

Если вы не возражаете против использования математического подхода, вы можете сначала вывести общее выражение для рекурсии, а затем получить R-код впоследствии.

Ниже приведена одна реализация с базовым R

 transform(
  transform(
    df1,
    C = C[1] * c(1, cumprod(1 - A)[-nrow(df1)])
  ),
  B = A * C
)
 

что дает

     A     B      C
1 0.1 10.00 100.00
2 0.2 18.00  90.00
3 0.3 21.60  72.00
4 0.4 20.16  50.40
5 0.5 15.12  30.24
 

Аналогичным data.table образом можно

 > setDT(df1)[, C := first(C) * c(1, cumprod(1 - A)[-.N])][, B := A * C][]
     A     B      C
1: 0.1 10.00 100.00
2: 0.2 18.00  90.00
3: 0.3 21.60  72.00
4: 0.4 20.16  50.40
5: 0.5 15.12  30.24
 

Комментарии:

1. Потрясающе! Спасибо за эти другие варианты!