基于时间元素的函数应用:按组计算合约月度成本
我来帮你解决这个批量计算并汇总的问题!你的单条逻辑已经没问题了,现在只需要把这个逻辑扩展到所有行,再按Group汇总就行。这里给你两种常用的实现方式,分别基于tidyverse和data.table,你可以根据自己的习惯选择:
方法一:用tidyverse(直观易读)
首先我们先定义一个处理单行数据的函数,和你原来的逻辑完全一致,然后批量处理所有行,再汇总转成宽表:
library(tidyverse) # 定义单行处理函数,返回包含Group、月份、对应成本的 tibble calculate_monthly_cost <- function(row) { # 生成小时序列并统计各月份小时数 hours_per_month <- table(format(seq.POSIXt(row$Fromdate, row$Todate, by = "hour"), "%Y-%m")) # 转成 tibble 格式,计算成本 tibble( Group = row$Group, month = names(hours_per_month), total_cost = as.numeric(hours_per_month) * row$Cost * row$Quantity ) } # 批量处理所有行,合并结果 final_result <- df %>% # 对每一行应用函数并合并成一个大表 map_dfr(calculate_monthly_cost) %>% # 按Group和月份分组求和 group_by(Group, month) %>% summarise(total_cost = sum(total_cost), .groups = "drop") %>% # 转成宽表,得到你想要的格式 pivot_wider(names_from = month, values_from = total_cost, values_fill = 0) # 查看结果 print(final_result)
代码解释:
map_dfr:把每行数据传入函数,自动把所有结果合并成一个纵向的tibble,比apply系列更友好。group_by + summarise:把同一Group同一月份的成本加总,得到每个组的月度总成本。pivot_wider:把长格式的数据转成你期望的宽格式,values_fill=0确保没有数据的月份显示0(如果不需要可以去掉,显示NA)。
方法二:用data.table(高效适合大数据)
如果你的数据量很大,data.table的链式操作会比tidyverse更快:
library(data.table) # 转成data.table格式 setDT(df) final_result <- df[, { # 生成小时序列并提取月份 hours_seq <- seq.POSIXt(Fromdate, Todate, by = "hour") month_vec <- format(hours_seq, "%Y-%m") # 统计各月份小时数并计算成本 hours_table <- table(month_vec) .(month = names(hours_table), total_cost = as.numeric(hours_table) * Cost * Quantity) }, by = .(Fromdate, Todate, Cost, Quantity, Group)][ # 按Group和月份汇总 , .(total_cost = sum(total_cost)), by = .(Group, month) ][ # 转成宽表 , dcast(.SD, Group ~ month, value.var = "total_cost", fill = 0) ] # 查看结果 print(final_result)
代码解释:
- 用data.table的分组操作
by,对每行数据生成月度成本数据。 - 第二次分组汇总得到每个Group的月度总成本。
dcast实现宽表转换,和tidyverse的pivot_wider功能类似。
两种方法都能得到你想要的输出格式,示例输出如下(数值为计算后的结果):
# A tibble: 3 × 13 Group `2014-01` `2014-02` `2014-03` `2014-04` `2014-05` `2014-06` `2014-07` `2014-08` `2014-09` `2014-10` `2014-11` `2014-12` <fct> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> 1 A 2.44 2.27 2.44 2.36 2.44 2.36 2.44 2.44 2.36 2.44 2.36 2.44 2 B 12.2 11.4 12.2 11.8 12.2 11.8 12.2 12.2 11.8 12.2 11.8 12.2 3 C 9.21 8.57 9.21 8.93 9.21 8.93 9.21 9.21 8.93 9.21 8.93 9.21
内容的提问来源于stack exchange,提问作者Thorst
相关产品推荐
相关产品推荐

