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

使用dplyr::filter结合dplyr::lag过滤时如何保留分组首行?

如何在使用lag()过滤分组数据时保留每组首行?

这个问题我之前也碰到过!当用lag()做分组过滤时,每组第一行因为没有前一个值,lag()会返回NA,而大多数比较运算里NA会被判定为FALSE,所以这些首行就被过滤掉了。别担心,有几个简单的办法能解决这个问题,咱们一步步来:

首先先看你提供的示例数据集:

ds <- structure(list(mpg = c(21, 21, 21.4, 18.7, 14.3, 16.4), 
                     cyl = c(6, 6, 6, 8, 8, 8), 
                     hp = c(110, 110, 110, 175, 245, 180)), 
                class = c("tbl_df", "tbl", "data.frame"), 
                row.names = c(NA, -6L), 
                .Names = c("mpg", "cyl", "hp"))

假设你想过滤出每组中hp和前一行不同的行,你可能会写出这样的代码,但结果会丢失每组首行:

library(dplyr)

# 这种写法会丢失每组首行
ds %>%
  group_by(cyl) %>%
  filter(hp != lag(hp)) %>%
  ungroup()

运行后得到的结果里,cyl=6和cyl=8的组首行都没了:

# A tibble: 2 × 3
    mpg   cyl    hp
  <dbl> <dbl> <dbl>
1  14.3     8   245
2  16.4     8   180

下面是两种可行的解决方案:

方法1:把NA的情况纳入过滤条件

每组首行的lag(hp)是NA,我们可以用is.na(lag(hp))匹配这些行,再用|(逻辑或)连接你的过滤条件,这样首行和满足条件的行都会被保留:

ds %>%
  group_by(cyl) %>%
  filter(is.na(lag(hp)) | hp != lag(hp)) %>%
  ungroup()

运行后就能得到保留了每组首行的结果:

# A tibble: 4 × 3
    mpg   cyl    hp
  <dbl> <dbl> <dbl>
1  21       6   110
2  18.7     8   175
3  14.3     8   245
4  16.4     8   180

方法2:用行号直接指定保留首行

另一种更直观的方式是通过row_number() == 1判断当前行是否是分组内的第一行,再结合你的过滤条件:

ds %>%
  group_by(cyl) %>%
  filter(row_number() == 1 | hp != lag(hp)) %>%
  ungroup()

这个方法的逻辑非常直白——明确告诉R:“保留每组的第一行,或者满足hp和前一行不同的行”,最终结果和方法1完全一致。

补充提示

如果你的过滤条件更复杂(比如要比较多个变量),只需要把hp != lag(hp)替换成你的实际判断条件即可。要是你用的是base R而非dplyr,思路也是一样的:先按分组计算lag值,再用is.na(lag_val) | 你的条件来筛选行。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 08:33:10