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

基于时间变量提取各分组首个非NA值的实现方法

按分组提取各变量首个非NA值(基于时间排序)

问题背景

处理时间序列数据时,需按id分组,提取每个变量按时间排序后首个出现的非NA值。使用tidyverse的across函数尝试实现,但原代码返回了不必要的NA,未达预期效果。

可运行示例数据

library(tidyverse)

df <- tibble(
  id = c("a","a","b","b","c","c"), 
  time = c(2,3,1,3,3,5), 
  val1 = c(NA,"x","y",NA,NA,"w"), 
  val2 = c("x",NA,"y","w",NA,"q")
)

原代码问题

原代码取每个组内time最小的行对应的变量值,但该行的变量可能为NA,导致结果不符合需求:

df %>% 
  group_by(id)%>%  
  summarise(across(starts_with('val'), ~ .x[which.min(time)]))

原代码返回结果(含NA)

# A tibble: 3 x 3
  id    val1  val2 
  <chr> <chr> <chr>
1 a     NA    x    
2 b     y     y    
3 c     NA    NA   

期望结果

# A tibble: 3 x 3
  id    val1  val2 
  <chr> <chr> <chr>
1 a     x     x    
2 b     y     y    
3 c     w     q    

解决方案

核心思路是先按组内时间升序排列,再对每个变量提取第一个非NA值,用across批量处理所有val开头的变量:

方法一:过滤NA后取首个值

df %>% 
  group_by(id) %>%
  arrange(time, .by_group = TRUE) %>% # 按组内时间从小到大排序
  summarise(across(starts_with("val"), ~ .x[!is.na(.x)][1]))

方法二:用first(na.omit(.x))简化代码

df %>% 
  group_by(id) %>%
  arrange(time, .by_group = TRUE) %>%
  summarise(across(starts_with("val"), ~ first(na.omit(.x))))

关键说明

  • arrange(time, .by_group = TRUE)确保每个组内的行按时间顺序排列,time为Date或POSIXct(datetime)类型时同样适用,无需额外转换。
  • 两种方法都会过滤当前变量的NA值,取排序后的第一个非NA值;如果该组变量全为NA,会返回NA(符合逻辑)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 18:27:27