使用 mutate ifelse 和 rollappy 根据连续变量的变化创建条件因子
Using mutate ifelse and rollappy to create a conditional factor based on changes in continuous variable
tl;dr 我需要根据价格随时间的下降(或不下降)来确定是否进行促销。我对其他方法持开放态度。
我有一个价格数据框,其中价格随着时间的推移分为几个分组因素。我的目标是让 'EACH' 商店中的每个 'ITEM' 检查过去 7 个日期(如果存在)的 'PRICE' 的模式。如果观察值小于价格模式的 10%,则在 'Promotion' 列中填充 1,如果不是 0。
示例数据
dat <- data.frame(Date = sample(seq(as.Date('1999/01/01'), as.Date('2000/01/01'), by="day"), 10),
Item = rep(LETTERS[1:4], times = 10),
Store = as.factor(sample(rep(c("NY","SYD","LON","PAR"), each = 10))),
Price = rnorm(n = 40, mean = 2.5, sd = 1))
到目前为止,我已经使用 dplyr 的 group_split
来分解项目并将分组存储到单独的数据帧中以捕获所有条件。我认为我现在需要做的是 mutate
使用带有 rollapply
的 ifelse
语句的新专栏。到目前为止,我已经尝试使用以下代码行...
data %>% mutate(Promotion = ifelse(rollapply(Price, 7, Mode <= Price*0.91,1,0)))
这个returns一个错误陈述...
Error: Problem with `mutate()` input `PRMT_IND2`.
x comparison (5) is possible only for atomic and list types
i Input `PRMT_IND2` is `ifelse(...)`.
我不太确定从这里到哪里去。如果您有时间,请告诉我如何将此应用到 group_split 创建的所有组,以及如何将其重新组合在一起,我将不胜感激。
note. 观察结果 (dates/rows) 在商店之间是不均匀的,有些填充时间少于 7 天。如果滚动应用没有它就无法工作,我可以删除它们。但这会丢失大量数据。
我正在为模式使用此功能...
Mode <- function(x) {
ux <- unique(x)
ux[which.max(tabulate(match(x, ux)))]
}
正如 Ronah Shak 所指出的,函数似乎不是最合适的选择。
另外请注意,使用 tabulate 会将值转换为整数,这对于您拥有的值可能会有问题。
关于错误,正如您猜对的那样,问题是您的拆分数据并不总是有 7 个日期,因此带有 width=7
的 rollapply
函数返回了一个错误。
允许您的函数使用 Date 向量的长度或 7(如果可用)可以解决问题。
此外,您可以使用 group_by
应用函数,不需要拆分数据。
dat %>%
group_by(Store,Item)%>%
mutate(price_check = Price*0.91,
Promotion = ifelse(rollapply(Price, width = min(length(Date),7), Mode)>=price_check,1,0))
或许你可以使用滚动均值代替众数。
library(dplyr)
library(zoo)
dat %>%
group_by(Item, Store) %>%
mutate(Promotion = as.integer(abs((Price -
rollmeanr(Price, 7, fill = NA))/Price) > 0.1))
这将为前 6 个值提供 NA
,如果 Price
比前 7 天的值变化超过 10%,则为 1,否则为 0。另请注意,我们在这里采用绝对值,因此如果价格上涨 10% 或下跌,它将给出 1。
tl;dr 我需要根据价格随时间的下降(或不下降)来确定是否进行促销。我对其他方法持开放态度。
我有一个价格数据框,其中价格随着时间的推移分为几个分组因素。我的目标是让 'EACH' 商店中的每个 'ITEM' 检查过去 7 个日期(如果存在)的 'PRICE' 的模式。如果观察值小于价格模式的 10%,则在 'Promotion' 列中填充 1,如果不是 0。
示例数据
dat <- data.frame(Date = sample(seq(as.Date('1999/01/01'), as.Date('2000/01/01'), by="day"), 10),
Item = rep(LETTERS[1:4], times = 10),
Store = as.factor(sample(rep(c("NY","SYD","LON","PAR"), each = 10))),
Price = rnorm(n = 40, mean = 2.5, sd = 1))
到目前为止,我已经使用 dplyr 的 group_split
来分解项目并将分组存储到单独的数据帧中以捕获所有条件。我认为我现在需要做的是 mutate
使用带有 rollapply
的 ifelse
语句的新专栏。到目前为止,我已经尝试使用以下代码行...
data %>% mutate(Promotion = ifelse(rollapply(Price, 7, Mode <= Price*0.91,1,0)))
这个returns一个错误陈述...
Error: Problem with `mutate()` input `PRMT_IND2`.
x comparison (5) is possible only for atomic and list types
i Input `PRMT_IND2` is `ifelse(...)`.
我不太确定从这里到哪里去。如果您有时间,请告诉我如何将此应用到 group_split 创建的所有组,以及如何将其重新组合在一起,我将不胜感激。
note. 观察结果 (dates/rows) 在商店之间是不均匀的,有些填充时间少于 7 天。如果滚动应用没有它就无法工作,我可以删除它们。但这会丢失大量数据。
我正在为模式使用此功能...
Mode <- function(x) {
ux <- unique(x)
ux[which.max(tabulate(match(x, ux)))]
}
正如 Ronah Shak 所指出的,函数似乎不是最合适的选择。 另外请注意,使用 tabulate 会将值转换为整数,这对于您拥有的值可能会有问题。
关于错误,正如您猜对的那样,问题是您的拆分数据并不总是有 7 个日期,因此带有 width=7
的 rollapply
函数返回了一个错误。
允许您的函数使用 Date 向量的长度或 7(如果可用)可以解决问题。
此外,您可以使用 group_by
应用函数,不需要拆分数据。
dat %>%
group_by(Store,Item)%>%
mutate(price_check = Price*0.91,
Promotion = ifelse(rollapply(Price, width = min(length(Date),7), Mode)>=price_check,1,0))
或许你可以使用滚动均值代替众数。
library(dplyr)
library(zoo)
dat %>%
group_by(Item, Store) %>%
mutate(Promotion = as.integer(abs((Price -
rollmeanr(Price, 7, fill = NA))/Price) > 0.1))
这将为前 6 个值提供 NA
,如果 Price
比前 7 天的值变化超过 10%,则为 1,否则为 0。另请注意,我们在这里采用绝对值,因此如果价格上涨 10% 或下跌,它将给出 1。