如何用R语言dplyr包计算连续假期及HL_UP、HL_DOWN列
问题解析:连续假期天数计算与代码解释
一、需求背景
我们需要基于仅含IS_HOLIDAY变量的数据集,用dplyr计算两个列:
HL_UP:包含补假后的连续假期总天数(连续假期定义:两个假期之间的非假期日视为假期)HL_DOWN:原始假期天数
用户已编写生成补假列HL的代码,并尝试通过分组计算目标列,但对分组逻辑中的关键代码存疑,同时需要验证整体实现是否正确。
二、关键代码解释:with(rle(HL), rep(seq_along(lengths), lengths))
这段代码的核心作用是为每一行分配所属的连续值组号,方便后续按连续的假期/非假期段分组计算总和,拆解如下:
rle(HL):对HL列执行游程编码(Run Length Encoding),返回一个包含两个元素的列表:values:HL列中连续出现的唯一值(比如连续的1或0)lengths:每个唯一值连续出现的次数
seq_along(lengths):为每个连续段生成序号(比如第1个连续段是1,第2个是2,以此类推)rep(seq_along(lengths), lengths):将每个序号重复对应段的长度次数,最终得到与原数据行数一致的组号向量,每个连续相同值的行都会被分到同一个组with(...):简化代码,直接在rle(HL)返回的列表环境中操作,无需反复写rle(HL)$
举个例子:若HL为[1,1,0,0,1],rle(HL)的lengths是[2,2,1],seq_along(lengths)生成[1,2,3],rep后得到[1,1,2,2,3],这样连续的行就被分到了同一组。
三、整体实现逻辑验证
1. 补假列HL生成的问题
用户当前生成HL的代码:
data_temp2<-data_temp %>% mutate( HL=if_else( IS_HOLIDAY == 0 & lag(IS_HOLIDAY,1)==1 & lead(IS_HOLIDAY,1)==1,1,IS_HOLIDAY))
这段代码仅能将单个非假期日(前后都是假期)标记为补假,若两个假期之间存在连续多个非假期日,则无法正确标记(比如IS_HOLIDAY为1,0,0,1时,中间的两个0都不会被转为1),不符合连续假期的定义。
2. 分组计算部分的正确性
用户后续分组计算HL_UP和HL_DOWN的逻辑是正确的:
- 按
HL的连续段分组后,sum(HL)得到该连续假期段的总天数(含补假),即HL_UP sum(IS_HOLIDAY)得到该段内的原始假期天数,即HL_DOWN
3. 修正后的HL列生成代码
要正确标记所有两个假期之间的非假期日,可通过游程编码实现:
# 对原始假期列执行游程编码 rle_holiday <- rle(data_temp$IS_HOLIDAY) # 定位前后均为假期的非假期连续段 middle_non_holiday <- which( rle_holiday$values == 0 & dplyr::lag(rle_holiday$values, default = 0) == 1 & dplyr::lead(rle_holiday$values, default = 0) == 1 ) # 将这些段标记为假期 rle_holiday$values[middle_non_holiday] <- 1 # 生成修正后的HL列 data_temp2 <- data_temp %>% mutate(HL = inverse.rle(rle_holiday))
修正后再执行用户的分组计算代码,就能得到正确的HL_UP和HL_DOWN列。
内容的提问来源于stack exchange,提问作者Masoud
相关产品推荐
相关产品推荐

