Это дополнение к моему предыдущему вопросу: Как я могу подсчитать количество условных строк в 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)))
Становится трудно следить. Но я думаю, что проблема с попыткой 1 в том, что cost[which(Product == "X")]
слишком короткая. Попробуйте использовать cost * (Product == "X")
, который имеет правильную длину.
@Quinten - извините за это .... обновил репрекс-код!
@bdecaf омг! это сработало! спасибо! Вы хотите поместить это как ответ, чтобы я мог отметить его принятым?
Первая попытка почти закончилась. Важно, чтобы количество строк сохранялось. Замените 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
Где находится ваш столбец
cost
в вашем фрейме данных?