如何在R中用循环创建哑变量统计各城镇年度门店数量
问题描述
我是R语言初学者,问题比较基础还请见谅。我现在有个包含各城镇门店开业、闭店日期的数据集,需要统计各城镇每年的门店数量。之前我问过这个问题,得到了热心帮助但没实现别人的方案,不过理解过程中学到了很多,自己想了一套方法:
- 为每一年创建哑变量,标记门店当年是否营业;
- 用
pivot_longer()转换数据格式; - 通过
group_by()和summarise()统计数量。
我手动写了示例代码,但数据年份跨度是1900-2023,手动创建哑变量效率太低,想请教怎么用循环批量创建这些哑变量。
手动实现代码
数据初始化
library(tidyverse) library(stringr) library(lubridate) id <- c("001", "002", "003", "004") town <- c("A", "A", "A", "B") opening <- as.Date(c("1900-01-01", "1902-02-05", "1903-01-01", "1903-01-01")) closing <- as.Date(c(NA, NA, NA, "1905-03-03")) df <- data.frame(id, town, opening, closing)
手动创建哑变量及后续处理
df_intermediate_1 <- df %>% mutate(Year_1900 = if_else(opening <= 1900 & closing > 1900, TRUE, FALSE), Year_1901 = if_else(opening <= 1901 & closing > 1901, TRUE, FALSE), Year_1902 = if_else(opening <= 1902 & closing > 1902, TRUE, FALSE), Year_1903 = if_else(opening <= 1903 & closing > 1903, TRUE, FALSE), Year_1904 = if_else(opening <= 1904 & closing > 1904, TRUE, FALSE), Year_1905 = if_else(opening <= 1905 & closing > 1905, TRUE, FALSE)) df_intermediate_2 <- df_intermediate_1 %>% pivot_longer( cols = c("Year_1900","Year_1901","Year_1902","Year_1903","Year_1904","Year_1905"), names_to = 'year', values_to = 'is_open') df_output <- df_intermediate_2 %>% group_by(town, year) %>% summarise(stores = sum(is_open)) df_output$year <- as.numeric(substr(df_output$year, start = 6, stop = nchar(df_output$year)))
解决方案
方法一:循环批量创建哑变量
首先定义年份范围,然后通过for循环批量生成每个年份的哑变量,同时修正原代码中未处理closing为NA(门店持续营业)的问题:
# 定义年份范围 years <- 1900:2023 # 初始化中间数据框 df_intermediate_1 <- df # 循环创建哑变量 for (y in years) { # 生成列名 col_name <- paste0("Year_", y) # 添加哑变量:开业年份<=当前年,且(未闭店或闭店年份>当前年)则标记为营业 df_intermediate_1 <- df_intermediate_1 %>% mutate(!!col_name := if_else(opening <= y & (is.na(closing) | closing > y), TRUE, FALSE)) } # 转换数据格式(无需手动列所有年份列,用starts_with匹配) df_intermediate_2 <- df_intermediate_1 %>% pivot_longer( cols = starts_with("Year_"), names_to = 'year', values_to = 'is_open') # 统计各城镇每年门店数量,并简化年份格式 df_output <- df_intermediate_2 %>% group_by(town, year) %>% summarise(stores = sum(is_open), .groups = "drop") %>% mutate(year = as.numeric(str_remove(year, "Year_")))
方法二:更高效的无哑变量方案(推荐)
对于年份跨度大的场景,创建大量哑变量会占用过多内存,推荐直接生成每个门店的营业年份序列再统计,效率更高:
df %>% rowwise() %>% # 生成该门店所有营业年份的序列:从开业年份到闭店年份(未闭店则到当前年) mutate(year = list(seq(year(opening), year(coalesce(closing, today())), by = 1))) %>% # 展开年份序列 unnest(year) %>% # 按城镇和年份分组统计门店数 group_by(town, year) %>% summarise(stores = n(), .groups = "drop")
内容的提问来源于stack exchange,提问作者L.P. Hayek
相关产品推荐
相关产品推荐

