在R数据框中计算增长率:新增Val1、Val2的增长百分比列
解决R数据框的增长率计算问题
我来帮你搞定这个需求!首先咱们得先处理这个有点“不规则”的原始数据——它是按月度块排列的,每个月度汇总行下面跟着A-E的明细行,而且Feb和Jan里的A-E顺序还不一样,直接计算肯定会出错。咱们分步骤来:
步骤1:构造原始数据
先把你给的数据转换成R能识别的数据框:
df <- data.frame( Month = c("Feb-17", "A", "B", "C", "D", "E", "Jan-17", "A", "B", "C", "D", "E"), Val1 = c(250, 25, 25, 100, 10, 40, 200, 20, 40, 100, 20, 20), Val2 = c(10000, 2000, 2000, 2000, 2000, 2000, 8000, 1000, 1600, 1600, 1600, 2200), Part1 = c(25, 5, 5, 5, 5, 5, 50, 10, 10, 10, 10, 10), Part2 = c(100, 20, 20, 20, 20, 20, 100, 20, 20, 20, 20, 20), stringsAsFactors = FALSE )
步骤2:给数据打分组标签
咱们需要识别出每个月度块(Feb-17和Jan-17),给每一行打上所属月份的标签,这样后续才能准确匹配A-E的对应数据:
# 识别月度汇总行(格式是"XXX-XX"),生成分组ID df$group <- cumsum(grepl("^[A-Za-z]{3}-\\d{2}$", df$Month)) # 提取每个分组对应的月份名称 month_labels <- df$Month[grepl("^[A-Za-z]{3}-\\d{2}$", df$Month)] # 给每一行分配所属月份 df$month <- rep(month_labels, each = 6) # 每个月度块有6行:1行汇总+5行明细
步骤3:拆分明细并计算增长率
因为A-E的顺序在两个月份里不一样,所以咱们要按**类别(A-E)**来匹配数据,而不是按行顺序。这里用dplyr和tidyr来处理:
library(dplyr) library(tidyr) # 提取明细行(排除汇总行) detail_df <- df[!grepl("^[A-Za-z]{3}-\\d{2}$", df$Month), ] # 把数据转成宽格式,让同一个类别的Feb和Jan数据在同一行 wide_detail <- detail_df %>% pivot_wider( id_cols = Month, # Month列这里是A-E类别 names_from = month, values_from = c(Val1, Val2) ) # 计算增长率,公式:(Feb值 - Jan值)/Jan值 * 100,保留2位小数 wide_detail <- wide_detail %>% mutate( Per_1 = round(((Val1_Feb-17 - Val1_Jan-17)/Val1_Jan-17)*100, 2), Per_2 = round(((Val2_Feb-17 - Val2_Jan-17)/Val2_Jan-17)*100, 2) )
步骤4:把增长率合并回原始数据
现在把计算好的明细增长率匹配回原始数据,同时计算汇总行的整体增长率:
# 匹配明细行的增长率 result_df <- df %>% left_join(wide_detail %>% select(Month, Per_1, Per_2), by = "Month") # 计算汇总行的整体增长率 summary_rows <- result_df[grepl("^[A-Za-z]{3}-\\d{2}$", result_df$Month), ] summary_rows <- summary_rows %>% mutate( Per_1 = round(((Val1 - Val1[month == "Jan-17"])/Val1[month == "Jan-17"])*100, 2), Per_2 = round(((Val2 - Val2[month == "Jan-17"])/Val2[month == "Jan-17"])*100, 2) ) # 替换原始数据中的汇总行增长率 result_df[grepl("^[A-Za-z]{3}-\\d{2}$", result_df$Month), c("Per_1", "Per_2")] <- summary_rows[, c("Per_1", "Per_2")]
最终结果
运行完上面的代码后,result_df就是你要的最终数据框,它在Val1后新增了Per_1列,Val2后新增了Per_2列,包含了Feb-17相对Jan-17的增长率(正数是增长,负数是下降)。你可以用print(result_df)查看完整结果:
print(result_df)
内容的提问来源于stack exchange,提问作者Roy1245
相关产品推荐
相关产品推荐

