You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

R语言技术需求:编写时间周期哑变量生成函数

解决R语言中按日期区间填充0/1的问题

嘿,这个需求我之前处理类似项目时也碰到过,用R实现起来其实挺顺畅的,我给你一步步拆解解决方案,保证你能快速用上~

核心思路梳理

我们要做的就是这两件事:

  • 把所有日期(起始、结束、列名)统一转成可直接比较的日期类型
  • 对每一行,逐个判断列名对应的年月是否落在该行的起止区间内,是则填1,否则填0

具体代码实现

1. 先构造示例数据(方便你对照测试)

假设你的数据框长这样,我先模拟一个和你需求匹配的样本:

df <- data.frame(
  start_date = c("2020-01", "2021-03", "2019-10"),
  end_date = c("2020-05", "2021-06", "2020-02"),
  `2020-01` = NA,
  `2020-02` = NA,
  `2020-03` = NA,
  `2021-03` = NA,
  `2021-04` = NA,
  stringsAsFactors = FALSE
)

2. 加载必要的工具包

推荐用lubridate处理日期(超级省心,专门对付各种日期格式),dplyr做数据转换:

library(lubridate)
library(dplyr)

3. 统一日期格式

把起始、结束日期转成yearmon类型(专门处理年月的类型,比普通Date更贴合我们的需求),同时把要填充的列名也转成同样的类型:

# 转换起止日期为yearmon类型
df <- df %>%
  mutate(
    start_date = ym(start_date),  # ym()自动识别"YYYY-MM"格式的年月
    end_date = ym(end_date)
  )

# 提取需要填充的列名,转成yearmon类型
target_months <- ym(colnames(df)[-c(1, 2)])

4. 定义单行处理函数

写一个小函数,输入一行数据,返回该行所有列的0/1判断结果:

fill_row <- function(row) {
  # 取出当前行的起止日期
  start <- row[["start_date"]]
  end <- row[["end_date"]]
  
  # 逐个判断目标月份是否在区间内,转成整数1/0
  sapply(target_months, function(month) as.integer(month >= start & month <= end))
}

5. 应用函数到所有行并合并结果

apply把函数跑遍每一行,再把结果和原数据的前两列合并起来:

# 对每一行应用函数,得到填充后的矩阵
filled_matrix <- t(apply(df[, c(1, 2)], 1, fill_row))

# 转成数据框并设置对应列名
filled_df <- as.data.frame(filled_matrix, col.names = colnames(df)[-c(1, 2)])

# 合并得到最终结果
final_df <- cbind(df[, c(1, 2)], filled_df)

6. 查看最终结果

运行完后打印final_df,就能看到符合要求的0/1填充结果了:

print(final_df)
# 输出示例:
#   start_date   end_date 2020-01 2020-02 2020-03 2021-03 2021-04
# 1 2020-01-01 2020-05-01       1       1       1       0       0
# 2 2021-03-01 2021-06-01       0       0       0       1       1
# 3 2019-10-01 2020-02-01       1       1       0       0       0

额外实用提示

  • 如果你的日期格式不是YYYY-MM(比如YYYY/MM或者MM-YYYY),只需要调整ym()的参数,比如用my()处理MM-YYYY格式就行
  • 要是不想用第三方包,也可以用base R把年月转成每月第一天的Date类型(比如as.Date(paste0(start_date, "-01"))),原理完全一样,只是代码会稍微繁琐一点
  • 如果数据量特别大,apply的效率可能不够,可以尝试用向量化的方法(比如outer函数),但一般中小规模的数据用apply完全没问题

内容的提问来源于stack exchange,提问作者Jojo

火山引擎 最新活动