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

使用dplyr按组删除某列首次出现指定值后的行及后续行

解决方案

需求

按id分组、组内按name排序后,删除char列首次出现1的行及其后续所有行。

示例数据

df <- data.frame(
  id = c(1001, 1001, 1002, 1002, 1002, 1005, 1005, 1005, 1005, 1005),
  name = c("monkey", "gorilla", "chimp", "monkey", "giraffe", "tarzan", "whale", "princess", "phone", "kindle"),
  char = c(0, 1, 0, 1, 0, 0, 0, 1, 0, 0)
)

# 目标结果
df_desired <- data.frame(
  id = c(1001, 1002, 1005, 1005),
  name = c("monkey", "chimp", "tarzan", "whale"),
  char = c(0, 0, 0, 0)
)

方法1:使用tidyverse(dplyr)

library(dplyr)

df_result <- df %>%
  group_by(id) %>%
  arrange(name, .by_group = TRUE) %>%
  # 处理边界情况:组内无1时保留全部行
  filter(ifelse(is.na(which(char == 1)[1]), TRUE, row_number() < which(char == 1)[1])) %>%
  ungroup()

# 查看结果
df_result

关键步骤说明

  1. 分组排序:group_by(id)按id分组后,arrange(name, .by_group = TRUE)确保组内按name字母顺序排序
  2. 过滤行:
    • which(char == 1)[1]定位组内char首次为1的行号
    • 用ifelse处理无1的分组:这类分组直接保留所有行;有1的分组只保留首次出现1之前的行

方法2:使用base R(无需额外包)

# 先按id和name全局排序
df_sorted <- df[order(df$id, df$name), ]

# 分组处理并合并
df_result <- do.call(rbind, lapply(split(df_sorted, df_sorted$id), function(group) {
  first_one_pos <- which(group$char == 1)[1]
  if (!is.na(first_one_pos)) {
    group[1:(first_one_pos - 1), ]
  } else {
    group
  }
}))

# 重置行名
rownames(df_result) <- NULL

# 查看结果
df_result

关键步骤说明

  1. 排序拆分:order(df$id, df$name)完成全局排序,split将数据按id拆分为分组列表
  2. 分组过滤:对每个分组判断是否存在char=1,存在则保留首次出现前的行,否则保留全部分组
  3. 合并结果:do.call(rbind, ...)将处理后的分组重新合并为数据框

验证结果

两种方法输出均与目标结果一致:

all.equal(df_result, df_desired)
#> [1] TRUE

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 22:18:09