基于R语言计算促销产品与最近4个非促销周平均销售额比值
用R语言计算促销周销售额与非促销周均值的比值
嘿,我来帮你搞定这个计算需求!首先得明确你的数据集结构,我先假设你的数据框叫sales_data,包含以下核心字段:
product_id: 产品唯一IDweek: 周标识(可以是日期、周数字符串,比如"2024-W01",得是能排序的类型)is_promotion: 促销标记(1代表促销周,0代表非促销周,就是你说的flag)sales: 当期的销售额
接下来一步步实现你的需求:
1. 先给每个产品的周数据按时间排序
要取最近4个非促销周,必须先把每个产品的周数据按时间排好序,不然取到的就不是“最近”的了:
library(dplyr) library(purrr) # 用来处理逐行的列表计算 # 按产品ID和周排序(如果week是字符串格式,建议先转成日期类型,比如用lubridate::parse_date_time(week, "%Y-W%U")) sales_data_sorted <- sales_data %>% arrange(product_id, week)
2. 计算每个促销周对应的最近4个非促销周平均销售额
这里用dplyr的分组+窗口函数,结合purrr来逐行处理每个周的历史非促销数据:
sales_with_ratio <- sales_data_sorted %>% group_by(product_id) %>% # 先计算该产品所有非促销周的整体均值,作为没有历史数据时的兜底值 mutate(overall_non_promo_avg = mean(sales[is_promotion == 0], na.rm = TRUE)) %>% mutate( # 对每个行,获取当前周之前的所有非促销周销售额 past_non_promo_sales = map(week, ~ sales[is_promotion == 0 & week < .x]), # 计算最近4个非促销周的均值:够4个就取最后4个,不够就用现有全部,没有的话用兜底均值 avg_past_non_promo = map_dbl(past_non_promo_sales, ~ { if (length(.x) >= 4) { mean(tail(.x, 4)) } else if (length(.x) > 0) { mean(.x) } else { overall_non_promo_avg[1] } }), # 生成最终结果:促销周用销售额/均值,非促销周直接用当期销售额 result_value = case_when( is_promotion == 1 ~ sales / avg_past_non_promo, TRUE ~ sales ), # 处理极端情况:如果连兜底均值都没有(比如产品从来没非促销过),标记为NA result_value = ifelse(is.nan(result_value), NA_real_, result_value) ) %>% ungroup() %>% # 保留需要的字段,去掉中间临时列 select(product_id, week, is_promotion, sales, avg_past_non_promo, result_value)
3. 输出符合指定格式的结果
如果需要输出成CSV文件(最常用的格式),直接用:
# 可以先把数值格式化为两位小数,让结果更整洁 sales_with_ratio_formatted <- sales_with_ratio %>% mutate(across(c(sales, avg_past_non_promo, result_value), ~ round(.x, 2))) write.csv(sales_with_ratio_formatted, "promotion_sales_ratio.csv", row.names = FALSE)
如果需要其他格式(比如Excel),可以用writexl::write_xlsx()函数,先安装包就行:install.packages("writexl")
小提醒
- 要是你的
week字段是类似"2024-W01"的字符串,记得先转成可排序的日期类型,不然排序会出错:library(lubridate) sales_data$week <- parse_date_time(sales_data$week, "%Y-W%U") - 如果不需要兜底均值,想直接把没有历史非促销数据的促销周标记为NA,把
overall_non_promo_avg[1]改成NA_real_就行。
内容的提问来源于stack exchange,提问作者av abhishiek
相关产品推荐
相关产品推荐

