最近有个小伙伴问了这么一个会计实操方面的问题,问题大致是这样的,她有一列费用数据,需要根据费用来开发票,但是每笔费用开一张发票太浪费了,所以公司要求合计超过 30000 的多笔费用合开一张发票,那么该如何找到所有合计金额超过 30000 的费用组合呢?
首先我们用 Stata 生成一个示例数据:
cd "~/Desktop" clear allset obs 500gen 序号 = _nset seed 1234gen 费用 = uniform () * 10000list in 1/10
例如前 5 笔费用的总和是 31051.7,刚好大于 30000,可以合开一张发票。那么如何按顺序找到所有这种刚好超过 30000 的组合呢?当然不能重复对某比费用开票。
下面我们就通过 Stata 编程来解决这个问题:
gen group = .local j = 1forval i = 1/`=_N' { local tempsum = 0 forval z = `j' /`=_N' { local tempsum = `tempsum' + 费用[`z' ] if `tempsum' > 30000 { qui replace group = `z' if _n == `z' local j = `z' + 1 continue , break } } di "`j'" }
这里我进行了两层的循环,外层循环 i 循环的是所有的观测值,内层循环 j 找到每个超过 30000 的费用组合,group 变量用来标记每个组合结果:
list in 1/10 *> +-------------------------+ *> | 序号 费用 group | *> |-------------------------| *> 1. | 1 9472.316 . | *> 2. | 2 522.2338 . | *> 3. | 3 9743.183 . | *> 4. | 4 9457.483 . | *> 5. | 5 1856.478 5 | *> |-------------------------| *> 6. | 6 9487.334 . | *> 7. | 7 8825.376 . | *> 8. | 8 9440.776 . | *> 9. | 9 894.2585 . | *> 10. | 10 7505.445 10 | *> +-------------------------+
group = 5 就表示前 5 组是一个合适的开票组合,group = 10 表示 6~10 是一个合适的开票组合,以此类推。
可以看到最后有 5 笔费用凑不齐 3w,所以填充 group 的时候最后三个没法填充:
forval i = 1/10000{ qui replace group = group[_n + 1] if missing(group) qui count if missing(group) if r(N) <= 5 { continue, break } }
最后剩余的 5 笔费用合开一张发票:
replace group = _N if missing (group)
然后计算每组的和:
bysort group: egen sum = sum (费用)bysort group: replace sum = . if _n > 1save temp, replace list in 1/10
由于这位小伙伴最后还想得到一个 Excel 文件,然后 sum 一列需要使用合并单元格。所以我们需要再把这个数据输出成 Excel 文件。
如果直接输出的话就没法设置合并单元格,所以我们可以使用 putexcel 按照我们想要的格式写入 Excel 文件。
由于 sum 列需要使用合并单元格的格式写入,所以我们需要先生成每个合并单元格的范围:
gen z = _nbysort group: replace z = . if _n != 1 & _n != _Nkeep group zdrop if missing (z)replace z = z + 1tostring z, replace bysort group: gen z1 = "C" + z[1] + ":" + "C" + z[_N]drop zduplicates drop group, forcesave temp2, replace list in 1/10
例如第一组是需要把 sum 的值填充到 C2:C6 合并的单元格中。
然后就可以 temp1.dta 和 temp2.dta 了:
use temp, clear merge m :1 group using temp2drop _mbysort group: replace z1 = "" if _n > 1list in 1/10
然后就可以写入 Excel 文件了:
* 保存到 excel 文件 putexcel set "temp.xlsx", replace qui { putexcel A1 = "序号" putexcel B1 = "费用" putexcel C1 = "开票" } forval i = 1/`=_N' { di "`i'" qui { putexcel A`=`i' + 1' = `=序号[`i']' putexcel B`=`i' + 1' = `=费用[`i']' if !missing(`=sum[`i']') { putexcel `=z1[`i']' = `=sum[`i']', merge hcenter vcenter } } } putexcel save
这样我们就完整了这个工作!
点击这里跳转到 RStata 短书平台获取附件:使用 Stata 编程寻找一串数字中总和超过某个值的数字组合
评论