我正在为一家零售商处理成本数据,我正在使用 gam 进行一些预测,如下所示(示例数据,自行生成)。GAM 适合中间的值,但在极端处有一些 NA。弹性计算为成本变化百分比与项目变化百分比之比。
df <- tibble(
factor = seq(0.7,1.3, 0.1),
items = c(7, 8, 9, 10, 11, 12, 13),
cost = c(NA, NA, 70, 80, 90, NA, NA),
elasticity = c(NA, NA, 0.5, 0.6, 0.7, NA, NA)
)
Run Code Online (Sandbox Code Playgroud)
对弹性的一个简单估计是向上和向下扩展最后一个已知值。
df %>%
fill(elasticity, .direction = 'updown') ->
df
Run Code Online (Sandbox Code Playgroud)
| 因素 | 项目 | 成本 | 弹性 |
|---|---|---|---|
| 0.7 | 7 | 不适用 | 0.5 |
| 0.8 | 8 | 不适用 | 0.5 |
| 0.9 | 9 | 70 | 0.5 |
| 1.0 | 10 | 80 | 0.6 |
| 1.1 | 11 | 90 | 0.7 |
| 1.2 | 12 | 不适用 | 0.7 |
| 1.3 | 13 | 不适用 | 0.7 |
我想计算成本,估计成本弹性。例如,对于系数 1.2,项目为 12,弹性为 0.7。项目变化百分比为 (12-11)/11 = 9.09%,因此成本变化百分比应为 0.7 * 9.09% = 6.36%。由于因子 1.1 的成本为 90,因此因子 1.2 的成本为 95.72。同样的情况也向下和向上传播。
我想不出办法做到这一点。有人可以建议如何在 R 中(最好是在 dplyr 中)完成此操作吗?
一种可能的解决方案使用dplyr和purrr:
library(dplyr)\nlibrary(tidyr)\nlibrary(purrr) # used for pmap() in dbl_fill()\nRun Code Online (Sandbox Code Playgroud)\n<-注意,在命名列表元素、tibble 列等时应避免使用。
df <- tibble(\n factor = seq(0.7,1.3, 0.1),\n items = c(7, 8, 9, 10, 11, 12, 13),\n cost = c(NA, NA, 70, 80, 90, NA, NA),\n elasticity = c(NA, NA, 0.5, 0.6, 0.7, NA, NA)\n)\n\ndf <- fill(df, elasticity, .direction = \'updown\')\nRun Code Online (Sandbox Code Playgroud)\ndbl_fill()我意识到在变异时df我需要根据缺失值的“深度”递归lag()或列。lead()我假设您的数据是示例数据,因此认为最好创建一个通用函数,将数值向量滞后/领先到最大可接受的深度(对于本例来说 2 就足够了)。
dbl_fill <- function(x, lag_or_lead = c("lag", "lead"), max_fill = 2){\n\n lag_or_lead <- match.arg(lag_or_lead)\n if(lag_or_lead == "lag") fill_function <- lag\n else fill_function <- lead\n \n n_list <- as.list(1:max_fill)\n \n fill_list <- lapply(n_list, function(y) fill_function(x, y))\n \n vector_out <- pmap_dbl(fill_list, coalesce)\n \n return(vector_out)\n}\nRun Code Online (Sandbox Code Playgroud)\n我们可以对 执行大量突变df,然后删除select()我们不想保留的列。
我df$items在这里落后/领先,因为我不想假设该列中的值在行之间递增 1。items - 1但如果是的话,那么做与 相对的事情就足够了lag(items)。例如,这些是等效的。
df <- mutate(df,\n ## calculate new costs from lagged values\n pc_change_items = (items - lag(items)) / lag(items),\n lagged_cost = dbl_fill(cost, "lag", 2),\n pc_change_cost = pc_change_items * elasticity,\n lag_cost = lagged_cost * (1 + pc_change_cost),\n \n ## calculate new costs from lead\'ed values\n pc_change_items = (lead(items) - items) / items,\n leaded_cost = dbl_fill(cost, "lead", 2),\n pc_change_cost = pc_change_items * elasticity,\n lead_cost = leaded_cost * (1 - pc_change_cost)\n )\nRun Code Online (Sandbox Code Playgroud)\ndf <- select(df, factor, items, cost, elasticity, lag_cost, lead_cost)\ndf\n#> # A tibble: 7 \xc3\x97 6\n#> factor items cost elasticity lag_cost lead_cost\n#> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>\n#> 1 0.7 7 NA 0.5 NA 65 \n#> 2 0.8 8 NA 0.5 NA 65.6\n#> 3 0.9 9 70 0.5 NA 75.6\n#> 4 1 10 80 0.6 74.7 84.6\n#> 5 1.1 11 90 0.7 85.6 NA \n#> 6 1.2 12 NA 0.7 95.7 NA \n#> 7 1.3 13 NA 0.7 95.2 NA\nRun Code Online (Sandbox Code Playgroud)\n请注意,这里我优先考虑lag_costover lead_cost,但这完全是任意的,您可能想证明它的合理性。在两者都可用的情况下获取两者的平均值可能会更平衡,但这超出了这个答案的范围。
mutate(df, cost = coalesce(cost, lag_cost, lead_cost)) |> \n select(-lag_cost, -lead_cost)\n#> # A tibble: 7 \xc3\x97 4\n#> factor items cost elasticity\n#> <dbl> <dbl> <dbl> <dbl>\n#> 1 0.7 7 65 0.5\n#> 2 0.8 8 65.6 0.5\n#> 3 0.9 9 70 0.5\n#> 4 1 10 80 0.6\n#> 5 1.1 11 90 0.7\n#> 6 1.2 12 95.7 0.7\n#> 7 1.3 13 95.2 0.7\nRun Code Online (Sandbox Code Playgroud)\n创建于 2022 年 10 月 25 日,使用reprex v2.0.2
\n