В R, как я могу сгруппировать по одному столбцу и условно суммировать другой?

Это дополнение к моему предыдущему вопросу: Как я могу подсчитать количество условных строк в r dplyr mutate?

Допустим, у меня есть фрейм данных ниже. В моем предыдущем вопросе я спросил, как я могу вычислить в каждой строке, сколько раз клиент этой строки в дальнейшем заказывал Продукт X (буквально X, а не Продукт, связанный со строкой), который теперь указан в nSubsqX. Теперь я хочу узнать сумму затрат, связанных с этими последующими заказами X. Я вручную ввел ответ в nCostSubsqX ниже, но я не понимаю, как это сделать программно.

   Date       Customer Product  cost nSubsqX nCostSubsqX
 1 2020-05-18 A        X           9       0           0
 2 2020-02-10 B        X           2       5          42
 3 2020-02-12 B        Y           3       5          42
 4 2020-03-04 B        Z           4       5          42
 5 2020-03-29 B        X           5       4          37
 6 2020-04-08 B        X           6       3          31
 7 2020-04-30 B        X           7       2          24
 8 2020-05-13 B        X           8       1           5
 9 2020-05-23 B        Y          10       1           5
10 2020-07-02 B        Y          11       1           5
11 2020-08-26 B        Y          12       1           5
12 2020-12-06 B        X          16       0           0
13 2020-01-31 C        X           1       3          42
14 2020-09-19 C        X          13       2          60
15 2020-10-13 C        X          14       1          15
16 2020-11-11 C        X          15       0           0
17 2020-12-26 C        Y          17       0           0

В целях предоставления Reprex ниже приведен код для создания фрейма данных.

df = data.frame("Date" = as.Date(c("2020-01-31", "2020-02-10", "2020-02-12", 
"2020-03-04", "2020-03-29", "2020-04-08", "2020-04-30", "2020-05-13", "2020-05-18", 
"2020-05-23", "2020-07-02", "2020-08-26", "2020-09-19", "2020-10-13", "2020-11-11", 
"2020-12-06", "2020-12-26")), "Customer" = c("C","B","B","B","B","B","B","B","A",
"B","B","B","C","C","C","B","C"), "Product" = c("X","X","Y","Z","X","X","X","X","X",
"Y","Y","Y","X","X","X","X","Y"))

df$cost = seq(nrow(df))

Ниже приведен код, который дает мне nSubsqX:

df %>%
  arrange(Customer, Date) %>%
  group_by(Customer) %>%
  mutate(
    nSubsqX = sum(Product= = "X") - cumsum(Product= = "X"))

Теперь мне нужно понять, как сделать массив строками, где Product равен X, но из столбца стоимости, а не из самого столбца Product. есть идеи?

Попытка 1, выдает ошибку.

df %>%
  arrange(Customer, Date) %>%
  group_by(Customer) %>%
  mutate(
    nSubsqX = sum(Product= = "X") - cumsum(Product= = "X"),
    nCostSubsqX = sum(cost[which(Product == "X")]) - cumsum(cost[which(Product == "X")]))
...
Error in `mutate_cols()`:
  Problem with `mutate()` column `nCostSubsqX`.
  `nCostSubsqX = sum(cost[which(Product == "X")]) - ...`.
  `nCostSubsqX` must be size 11 or 1, not 6.
  The error occurred in group 2: Customer = "B".

Попытка 2, где математика неверна. В столбце nCostSubsqX необходимо удалить совокупную стоимость к этому моменту.

df %>%
  arrange(Customer, Date) %>%
  group_by(Customer) %>%
  mutate(
    nSubsqX = sum(Product= = "X") - cumsum(Product= = "X"),
    nCostSubsqX = zoo::na.locf0(replace(rep(NA_real_, n()), 
                                        Product == "X", rev(seq_len(sum(cost[which(Product == "X")]))))))
...
   Date       Customer Product  cost nSubsqX nCostSubsqX
 1 2020-05-18 A        X           9       0           9
 2 2020-02-10 B        X           2       5          44
 3 2020-02-12 B        Y           3       5          44
 4 2020-03-04 B        Z           4       5          44
 5 2020-03-29 B        X           5       4          43
 6 2020-04-08 B        X           6       3          42
 7 2020-04-30 B        X           7       2          41
 8 2020-05-13 B        X           8       1          40
 9 2020-05-23 B        Y          10       1          40
10 2020-07-02 B        Y          11       1          40
11 2020-08-26 B        Y          12       1          40
12 2020-12-06 B        X          16       0          39
13 2020-01-31 C        X           1       3          43
14 2020-09-19 C        X          13       2          42
15 2020-10-13 C        X          14       1          41
16 2020-11-11 C        X          15       0          40
17 2020-12-26 C        Y          17       0          40

Попытка 3, я не знаю, что здесь делает математика, но это неправильно!

df %>%
  arrange(Customer, Date) %>%
  group_by(Customer) %>%
  mutate(
    nSubsqX = sum(Product= = "X") - cumsum(Product= = "X"),
    nCostSubsqX = zoo::na.locf0(replace(rep(NA_real_, n()), 
                       Product == "X", rev(seq_len(sum(cost[which(Product == "X")])))))-
                  zoo::na.locf0(ifelse(Product == "X",cumsum(cost[which(Product == "X")]),NA)))

Где находится ваш столбец cost в вашем фрейме данных?

Quinten 05.05.2022 18:06

Становится трудно следить. Но я думаю, что проблема с попыткой 1 в том, что cost[which(Product == "X")] слишком короткая. Попробуйте использовать cost * (Product == "X"), который имеет правильную длину.

bdecaf 05.05.2022 18:21

@Quinten - извините за это .... обновил репрекс-код!

SIE_Vict0ria 05.05.2022 18:25

@bdecaf омг! это сработало! спасибо! Вы хотите поместить это как ответ, чтобы я мог отметить его принятым?

SIE_Vict0ria 05.05.2022 18:28
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
4
42
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Первая попытка почти закончилась. Важно, чтобы количество строк сохранялось. Замените cost[which(Product == "X")] на cost*(Product= = "X") (подвох). Кстати. which не нужен.

Фрагмент будет:

df %>%
  arrange(Customer, Date) %>%
  group_by(Customer) %>%
  mutate(
    nSubsqX = sum(Product= = "X") - cumsum(Product= = "X"),
    nCostSubsqX = sum(cost[Product == "X"]) - cumsum(cost*(Product == "X")))

Вот немного другой подход, если вам интересно.

library(data.table)

f <- function(p,co=rep(1,length(p))) {
  sapply(seq_along(p), \(i) sum(co[-i:0][p[-i:0]= = "X"]))
}

setDT(df)[
  order(Date,Customer),
  `:=`(nSubsqX = f(Product),nCostSubsqx=f(Product, cost)),
  by=Customer
]

В этом подходе я фактически использую одну и ту же функцию f() как для nSubsqX, так и для nCostSubsqx; разница только в том, передается ли cost дополнительно в f() в качестве параметра co, или используется параметр co по умолчанию.

Выход:

          Date Customer Product  cost nSubsqX nCostSubsqx
        <Date>   <char>  <char> <int>   <num>       <int>
 1: 2020-01-31        C       X     1       3          42
 2: 2020-02-10        B       X     2       5          42
 3: 2020-02-12        B       Y     3       5          42
 4: 2020-03-04        B       Z     4       5          42
 5: 2020-03-29        B       X     5       4          37
 6: 2020-04-08        B       X     6       3          31
 7: 2020-04-30        B       X     7       2          24
 8: 2020-05-13        B       X     8       1          16
 9: 2020-05-18        A       X     9       0           0
10: 2020-05-23        B       Y    10       1          16
11: 2020-07-02        B       Y    11       1          16
12: 2020-08-26        B       Y    12       1          16
13: 2020-09-19        C       X    13       2          29
14: 2020-10-13        C       X    14       1          15
15: 2020-11-11        C       X    15       0           0
16: 2020-12-06        B       X    16       0           0
17: 2020-12-26        C       Y    17       0           0

Другие вопросы по теме