R语言跨年月度share差值计算问题及代码修正求助
问题描述
需要计算月度share的差值,规则如下:
- 非1月、非12月:当月
share减去同年上月的share - 1月:当月
share减去上一年12月的share - 12月:当月
share减去下一年1月的share
尝试的代码及问题
代码1:产生大量NA值
这段代码运行后得到大量NA,原因是分组后无法跨年份访问数据,且索引逻辑错误:
data %>% arrange(month) %>% mutate(unique = ave(month, month, FUN = seq_along)) %>% group_by(year) %>% mutate( lags = ifelse( month == 1, share - share[month == 12 & year == unique(year) - 1], share - share[month == month - 1 & year == unique(year)] ) )
代码2:无法处理12月逻辑
嵌套ifelse的代码可正常计算部分月份,但完全没有处理12月调用下一年1月的需求,且代码冗余:
mutate(lag = ifelse(month == 1, share[month == 2] - share[month == 1], ifelse(month == 2, share[month == 3] - share[month == 2], ifelse(month == 3, share[month == 4] - share[month == 3], ifelse(month == 4, share[month == 5] - share[month == 4], ifelse(month == 5, share[month == 6] - share[month == 5], ifelse(month == 6, share[month == 7] - share[month == 6], ifelse(month == 7, share[month == 8] - share[month == 7], ifelse(month == 8, share[month == 9] - share[month == 8], ifelse(month == 9, share[month == 10] - share[month == 9], ifelse(month == 10, share[month == 11] - share[month == 10], ifelse(month == 11, share[month == 12] - share[month == 11], NA)
示例数据
data <- data.frame( month = c(1, 1, 1, 2, 2, 2, 3, 3, 4, 4, 5, 6, 6, 7, 7, 8, 9, 9, 10, 10, 11, 11, 11, 12, 12, 12), year = c(2000, 2000, 2015, 2000, 2000, 2015, 2000, 2000, 2000, 2000, 2000, 2001, 2001, 2014, 2014, 2014, 2014, 2014, 2000, 2000, 2000, 2001, 2001, 2001, 2001, 2014), share = c(0.2, 0.4, 0.1, 0.6, 0.7, 0.3, 0.2, 0.8, 0.5, 0.1, 0.2, 0.4, 0.1, 0.6, 0.7, 0.3, 0.2, 0.8, 0.5, 0.1, 0.2, 0.4, 0.1, 0.6, 0.7, 0.3) )
期望输出
# A tibble: 26 × 5 # Groups: year [4] month year share unique lag1 <dbl> <dbl> <dbl> <dbl> <dbl> 1 1 2000 0.2 1 0.4 2 1 2000 0.4 2 0.3 3 1 2015 0.1 3 0.2 4 2 2000 0.6 1 -0.4 5 2 2000 0.7 2 0.1 6 2 2015 0.3 3 NA 7 3 2000 0.2 1 0.3 8 3 2000 0.8 2 -0.7 9 4 2000 0.5 1 -0.3 10 4 2000 0.1 2 NA 11 5 2000 0.2 1 NA 12 6 2001 0.4 1 NA 13 6 2001 0.1 2 NA 14 7 2014 0.6 1 -0.3 15 7 2014 0.7 2 NA 16 8 2014 0.3 1 -0.1 17 9 2014 0.2 1 NA 18 9 2014 0.8 2 NA 19 10 2000 0.5 1 -0.3 20 10 2000 0.1 2 NA 21 11 2000 0.2 1 NA 22 11 2001 0.4 2 0.2 23 11 2001 0.1 3 0.6 24 12 2001 0.6 1 NA 25 12 2001 0.7 2 NA 26 12 2014 0.3 3 -0.2
解决方案
使用lubridate创建连续的年月标识,通过自连接匹配对应月份的share,实现跨年月的差值计算:
library(dplyr) library(lubridate) # 处理数据 result <- data %>% # 生成标准年月格式,方便跨年月计算 mutate(ym = make_date(year, month)) %>% # 生成和原数据一致的unique列 mutate(unique = ave(month, month, FUN = seq_along)) %>% # 根据月份规则生成需要对比的年月 mutate(compare_ym = case_when( month == 1 ~ ym - years(1) + months(11), # 上一年12月 month == 12 ~ ym + years(1) - months(11), # 下一年1月 TRUE ~ ym - months(1) # 同年上月 )) %>% # 自连接,匹配对比年月和unique,获取对应的share值 left_join( data %>% mutate(ym = make_date(year, month)) %>% mutate(unique = ave(month, month, FUN = seq_along)) %>% rename(compare_share = share), by = c("compare_ym" = "ym", "unique" = "unique") ) %>% # 计算差值 mutate(lag1 = share - compare_share) %>% # 调整列顺序,和期望输出一致 select(month, year, share, unique, lag1) %>% # 保持原数据的行顺序 arrange(match(row_number(), seq(nrow(data)))) print(result)
代码说明
- 年月标识:用
make_date将year和month转为标准日期格式,方便跨年月的加减计算。 - 对比年月生成:通过
case_when分别处理1月、12月和其他月份的对比年月逻辑。 - 自连接匹配:通过
left_join匹配对应的对比年月和unique标识,确保每条记录能找到对应的对比share(没有对应数据则返回NA,符合期望输出)。 - 差值计算:直接用当前
share减去匹配到的compare_share得到结果。
内容的提问来源于stack exchange,提问作者Victoria
相关产品推荐
相关产品推荐

