You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在R中利用起止日期计算活跃暴发疫情数的技术求助

统计每日活跃呼吸道疾病暴发数的解决方案

问题背景

我有一份机构呼吸道疾病暴发数据集,每条记录包含暴发通知日期、结束日期,以及COVID-19、流感、RSV的存在状态(多病原体共存为混合暴发)。暴发从通知日到结束日视为活跃状态,目标是绘制从最早通知日到当日,按病原体分类的每日活跃暴发数图表,但统计每日总活跃暴发数时遇到问题。

现有代码问题

第一版代码问题

第一版代码尝试为每条暴发生成活跃日期序列,但统计病原体分类时逻辑错误——用is.na判断其他病原体不存在,而实际数据中不存在是用0表示,导致仅计数一次而非每日计数:

ari_test <- ari_data %>%
  select(record_id, notification_date, declaration_date, c_cov_present, c_flu_present, c_rsv_present) |> 
  mutate(notification_date = as.Date(notification_date),
         declaration_date = as.Date(declaration_date)) %>%
  filter(!is.na(notification_date) & !is.na(declaration_date)) %>%
  # Generate a sequence of dates from notification_date to declaration_date for each facility
  rowwise() %>%
  mutate(date = list(seq(notification_date, declaration_date, by = "day"))) %>%
  unnest(date) %>%
  select(-notification_date, -declaration_date) %>%
  # Count the number of active outbreaks per day for each pathogen
  group_by(date) %>%
  summarise(active_covid = sum(c_cov_present == 1 & is.na(c_flu_present) & is.na(c_rsv_present)),
            active_influenza = sum(is.na(c_cov_present) & c_flu_present == 1 & is.na(c_rsv_present)),
            active_rsv = sum(is.na(c_cov_present) & is.na(c_flu_present) & c_rsv_present == 1),
            active_mixed = sum(rowSums(cbind(c_cov_present, c_flu_present, c_rsv_present), na.rm = TRUE) >= 2))

第二版代码问题

第二版代码用complete扩展日期时,因分组后min(notification_date)和max(declaration_date)是每组的范围,而非全局范围,导致record_id找不到的错误:

ari_test <- ari_data %>%
  mutate(notification_date = as.Date(notification_date),
         declaration_date = as.Date(declaration_date)) %>%
  filter(!is.na(notification_date) & !is.na(declaration_date)) %>%
  mutate(across(starts_with("c_"), ~if_else(is.na(.), 0, 1))) %>%  # Convert NA to 0 for presence/absence
  group_by(record_id) %>%
  mutate(active_covid = +(any(c_cov_present == 1 & is.na(c_flu_present) & is.na(c_rsv_present))),
         active_influenza = +(any(is.na(c_cov_present) & c_flu_present == 1 & is.na(c_rsv_present))),
         active_rsv = +(any(is.na(c_cov_present) & is.na(c_flu_present) & c_rsv_present == 1)),
         active_mixed = +(any(rowSums(select(., starts_with("c_"))) >= 2))) %>%
  complete(record_id, date = seq.Date(min(notification_date), max(declaration_date), by = "day"), fill = list(active_covid = 0, active_influenza = 0, active_rsv = 0, active_mixed = 0)) %>%
  ungroup()

修正后的解决方案

核心思路:

  • 先统一将病原体状态的NA转为0,明确0表示不存在,1表示存在
  • 为每条暴发生成完整的活跃日期序列
  • 对每条暴发先判定其属于哪类(单一COVID、单一流感、单一RSV、混合)
  • 按日期分组统计各类活跃暴发数
# 加载所需包
library(tidyverse)

# 处理数据
ari_test <- ari_data %>%
  # 转换日期格式并过滤有效记录
  mutate(notification_date = as.Date(notification_date),
         declaration_date = as.Date(declaration_date)) %>%
  filter(!is.na(notification_date) & !is.na(declaration_date)) %>%
  # 将NA转为0,统一状态标识
  mutate(across(starts_with("c_"), ~replace_na(., 0))) %>%
  # 为每条暴发生成活跃日期序列
  rowwise() %>%
  mutate(date = list(seq(notification_date, declaration_date, by = "day"))) %>%
  unnest(date) %>%
  # 判定每条暴发的类型
  mutate(
    total_pathogens = c_cov_present + c_flu_present + c_rsv_present,
    outbreak_type = case_when(
      total_pathogens >= 2 ~ "mixed",
      c_cov_present == 1 ~ "covid",
      c_flu_present == 1 ~ "influenza",
      c_rsv_present == 1 ~ "rsv",
      TRUE ~ "none" # 无病原体的情况,可根据实际需求处理
    )
  ) %>%
  # 过滤无病原体的记录(如果有的话)
  filter(outbreak_type != "none") %>%
  # 按日期和暴发类型分组计数,再转为宽格式
  group_by(date, outbreak_type) %>%
  summarise(count = n(), .groups = "drop") %>%
  pivot_wider(names_from = outbreak_type, values_from = count, values_fill = 0) %>%
  # 重命名列以匹配需求
  rename(
    active_covid = covid,
    active_influenza = influenza,
    active_rsv = rsv,
    active_mixed = mixed
  )

验证示例数据

使用提供的示例数据测试:

# 示例数据
ari_data <- structure(list(record_id = c(1, 2, 5, 6, 7, 8, 10, 11, 12, 13
), notification_date = structure(c(19523, 19524, 19535, 19535, 
19535, 19535, 19536, 19536, 19542, 19542), class = "Date"), declaration_date = structure(c(19544, 
19537, 19548, 19559, 19542, 19555, 19548, 19549, 19550, 19569
), class = "Date"), c_cov_present = c(1, 1, 1, 1, 0, 1, 1, 1, 
1, 0), c_flu_present = c(1, 0, 0, 0, 
0, 0, 0, 0, 0, 1), 
    c_rsv_present = c(0, 0, 0, 0, 1, 0, 0, 1, 0, 0)), row.names = c(NA, 
-10L), class = c("tbl_df", "tbl", "data.frame"))

# 运行修正后的代码
ari_test <- ari_data %>%
  mutate(notification_date = as.Date(notification_date),
         declaration_date = as.Date(declaration_date)) %>%
  filter(!is.na(notification_date) & !is.na(declaration_date)) %>%
  mutate(across(starts_with("c_"), ~replace_na(., 0))) %>%
  rowwise() %>%
  mutate(date = list(seq(notification_date, declaration_date, by = "day"))) %>%
  unnest(date) %>%
  mutate(
    total_pathogens = c_cov_present + c_flu_present + c_rsv_present,
    outbreak_type = case_when(
      total_pathogens >= 2 ~ "mixed",
      c_cov_present == 1 ~ "covid",
      c_flu_present == 1 ~ "influenza",
      c_rsv_present == 1 ~ "rsv",
      TRUE ~ "none"
    )
  ) %>%
  filter(outbreak_type != "none") %>%
  group_by(date, outbreak_type) %>%
  summarise(count = n(), .groups = "drop") %>%
  pivot_wider(names_from = outbreak_type, values_from = count, values_fill = 0) %>%
  rename(
    active_covid = covid,
    active_influenza = influenza,
    active_rsv = rsv,
    active_mixed = mixed
  )

# 查看结果
head(ari_test)

运行后会得到每日各类型活跃暴发数,可直接用于绘图。

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 15:10:02