在dplyr中应用比例法则计算ttl_amt_adjusted字段问题
问题描述
需要基于比例法则(Rule of Three)计算新增字段ttl_amt_adjusted,规则如下:
- 对每个
group,若同时存在control和target子组:target子组的ttl_amt_adjusted直接等于自身ttl_amtcontrol子组的ttl_amt_adjusted计算公式为:target的n值 * control的ttl_amt值 / control的n值
- 若
group仅包含target子组,所有行的ttl_amt_adjusted等于自身ttl_amt
原始数据表格:
| group | sub_group | n | ttl_amt |
|---|---|---|---|
| A | control | 1702 | 4791 |
| A | target | 32637 | 102143 |
| B | target | 12355 | 53640 |
| C | control | 1012 | 2943 |
| C | target | 19514 | 56017 |
期望输出结果:
| group | sub_group | n | ttl_amt | ttl_amt_adjusted |
|---|---|---|---|---|
| A | control | 1702 | 4791 | 91870.66 |
| A | target | 32637 | 102143 | 102143 |
| B | target | 12355 | 53640 | 53640 |
| C | control | 1012 | 2943 | 56748.72 |
| C | target | 19514 | 56017 | 56017 |
原尝试代码(未得到正确结果):
df%>% group_by(group)%>% arrange(group,sub_group)%>% mutate(ttl_amt_adjusted=lag(n,default=last(n))*lead(ttl_amt,default=first(ttl_amt))/lead(n,default=first(n)))
问题分析
原代码依赖lag()和lead()函数,这种方式高度依赖行的排列顺序,且无法灵活处理仅含target的分组场景,逻辑上不够严谨,容易出现计算错误。
正确实现代码
使用dplyr分组后直接提取各组内的关键值,通过条件判断完成计算,逻辑更清晰可靠:
library(dplyr) df %>% group_by(group) %>% mutate( # 提取当前组control的n和ttl_amt,无则为NA control_n = if(any(sub_group == "control")) n[sub_group == "control"] else NA, control_amt = if(any(sub_group == "control")) ttl_amt[sub_group == "control"] else NA, # 提取当前组target的n,无则为NA target_n = if(any(sub_group == "target")) n[sub_group == "target"] else NA, # 根据规则计算ttl_amt_adjusted ttl_amt_adjusted = case_when( sub_group == "target" ~ ttl_amt, sub_group == "control" ~ (target_n * control_amt) / control_n, TRUE ~ ttl_amt # 兜底情况,理论上不会触发 ) ) %>% # 移除临时计算的辅助列 select(-control_n, -control_amt, -target_n) %>% ungroup()
代码说明
- 分组提取关键值:在每个
group内,分别获取control的n和ttl_amt、target的n,没有对应子组时标记为NA - 条件计算:
- 当
sub_group为target时,直接赋值自身ttl_amt - 当
sub_group为control时,用提前提取的各组关键值代入比例公式计算 - 兜底逻辑确保所有情况都有值
- 当
- 清理辅助列:移除临时创建的
control_n、control_amt、target_n,保持表格简洁
运行上述代码后即可得到符合要求的输出结果。
内容的提问来源于stack exchange,提问作者GitZine
相关产品推荐
相关产品推荐

