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

如何在R语言中基于已有列创建发育阶段时长新列?

问题:统计动物发育阶段时长与总发育天数

现有记录动物随时间发育的R数据框,包含物种(Species)、处理方式(Treatment)及多列日期观测数据,示例代码如下:

df <- data.frame (Species  = c("sp1", "sp1", "sp2"),
                  Treatment = c("hot", "cold", "hot"),
                  Apr1 = c("egg", "egg", "egg"),
                  Apr2 = c("1", "egg", "1"),
                  Apr3 = c("2", "egg", "1"),
                  Apr4 = c("adult", "1", "2"))

需要生成新列统计每个发育阶段的天数,以及总发育时长(到成虫阶段的天数),期望输出结构如下:

Species Treatment Apr1 Apr2 Apr3  Apr4 Egg Instar1 Instar2 DaysToAdult
1     sp1       hot  egg    1    2 adult   1       1       1           4
2     sp1      cold  egg  egg  egg     1   3       1       0          NA
3     sp2       hot  egg    1    1     2   1       2       1          NA

询问是否有简便函数实现该需求,若必要也可逐个创建新列(注:实际有大约15个发育阶段)。


解决方案

方法1:批量处理(适配多发育阶段)

用tidyverse工具包可以实现批量处理,不用逐个手动创建列,适合15个阶段的场景:

  1. 先加载依赖包
library(tidyverse)
  1. 定义发育阶段的顺序(确保统计逻辑按阶段递进)
stage_order <- c("egg", "1", "2", "adult")
  1. 完整处理代码
result <- df %>%
  # 将日期列转为长格式,方便按阶段分组统计
  pivot_longer(cols = starts_with("Apr"), names_to = "Day", values_to = "Stage") %>%
  # 从日期名中提取天数数字(比如Apr1提取为1)
  mutate(Day = as.numeric(str_extract(Day, "\\d+"))) %>%
  # 按物种和处理方式分组
  group_by(Species, Treatment) %>%
  # 按天数排序,保证时间顺序正确
  arrange(Day, .by_group = TRUE) %>%
  # 计算每个阶段的持续天数
  mutate(
    Stage = factor(Stage, levels = stage_order),
    prev_day = lag(Day, default = 0),
    # 当阶段变化或到最后一天时,计算当前阶段的时长
    stage_duration = ifelse(Stage != lead(Stage, default = Stage), Day - prev_day, 0)
  ) %>%
  # 按阶段汇总总天数
  group_by(Species, Treatment, Stage) %>%
  summarise(Duration = sum(stage_duration), .groups = "drop") %>%
  # 转回宽格式,对应每个阶段的列
  pivot_wider(names_from = Stage, values_from = Duration, names_prefix = "") %>%
  # 未经历的阶段天数设为0
  mutate(across(all_of(stage_order), ~replace_na(., 0))) %>%
  # 计算到成虫的天数:找到出现adult的最大天数,未出现则为NA
  left_join(
    df %>%
      pivot_longer(cols = starts_with("Apr"), names_to = "Day", values_to = "Stage") %>%
      mutate(Day = as.numeric(str_extract(Day, "\\d+"))) %>%
      group_by(Species, Treatment) %>%
      filter(Stage == "adult") %>%
      summarise(DaysToAdult = max(Day), .groups = "drop"),
    by = c("Species", "Treatment")
  ) %>%
  # 和原数据框合并,保留原始日期列
  left_join(df, by = c("Species", "Treatment")) %>%
  # 调整列顺序,匹配期望输出
  select(Species, Treatment, starts_with("Apr"), all_of(stage_order), DaysToAdult) %>%
  # 重命名阶段列,让名称更直观
  rename(
    Egg = egg,
    Instar1 = `1`,
    Instar2 = `2`
  ) %>%
  # 未发育到成虫的个体,DaysToAdult设为NA
  mutate(DaysToAdult = ifelse(adult == 0, NA, DaysToAdult)) %>%
  # 移除不需要的adult列
  select(-adult)

运行后得到的result就是符合要求的输出:

> result
# A tibble: 3 × 11
  Species Treatment Apr1  Apr2  Apr3  Apr4  Egg Instar1 Instar2 DaysToAdult
  <chr>   <chr>     <chr> <chr> <chr> <chr> <dbl>   <dbl>   <dbl>       <dbl>
1 sp1     cold      egg   egg   egg   1         3       1       0          NA
2 sp1     hot       egg   1     2     adult     1       1       1           4
3 sp2     hot       egg   1     1     2         1       2       1          NA

方法2:逐个创建列(适合阶段数少的场景)

如果不想用批量处理,也可以针对每个阶段单独写逻辑,示例如下:

# 统计Egg阶段天数:数出连续为"egg"的日期列数量
df$Egg <- apply(df[, starts_with("Apr")], 1, function(x) sum(x == "egg"))

# 统计Instar1阶段天数:在Egg阶段结束后,数出连续为"1"的数量
df$Instar1 <- apply(df[, starts_with("Apr")], 1, function(x) {
  egg_last_pos <- max(which(x == "egg"))
  sum(x[(egg_last_pos + 1):length(x)] == "1")
})

# 统计Instar2阶段天数:在Instar1阶段结束后,数出连续为"2"的数量
df$Instar2 <- apply(df[, starts_with("Apr")], 1, function(x) {
  instar1_last_pos <- max(c(which(x == "egg"), which(x == "1")))
  sum(x[(instar1_last_pos + 1):length(x)] == "2")
})

# 计算DaysToAdult:找到第一个出现"adult"的日期对应的天数,无则为NA
df$DaysToAdult <- apply(df[, starts_with("Apr")], 1, function(x) {
  adult_pos <- which(x == "adult")
  if (length(adult_pos) > 0) as.numeric(str_extract(names(x)[adult_pos], "\\d+")) else NA
})

这种方法需要为每个阶段单独编写逻辑,阶段越多越繁琐,15个阶段的话更推荐用方法1的批量处理。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 14:34:57