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

如何用dplyr更优雅地按组条件修改item_1的time_1值?

优化dplyr分组替换逻辑的优雅实现

原始数据与需求

首先是创建数据框的代码:

df1 <- data.frame(id = rep( c('id_1', 'id_2') , c(3,3)),
                  item = c('item_1', 'item_2', 'item_3') ,
                  time_1 = c( 1:3 , 2:3 , 1) , time_2 = c( 1:3 , 1, 3 , 1)) 

数据展示(time_2是time_1的期望替换结果):

id   item time_1 time_2
1 id_1 item_1      1      1
2 id_1 item_2      2      2
3 id_1 item_3      3      3
4 id_2 item_1      2      1
5 id_2 item_2      3      3
6 id_2 item_3      1      1

需求:按id分组,检查每组中item_1的time_1是否为组内最小值,若不是则替换为组内最小值(比如id_2组的item_1原time_1为2,需替换为1)。

原实现方式:

df1 %>%
  group_by( id ) %>%
  mutate( min_ = min( time_1 ) ) %>%
  mutate( time_1 = ifelse( ( item == 'item_1' ) & ( time_1 != min_ )  , min_ , time_1 ) )

优化后的dplyr实现

方案1:用case_when简化逻辑(推荐)

df1 %>%
  group_by(id) %>%
  mutate(
    time_1 = case_when(
      item == "item_1" ~ pmin(time_1, min(time_1)),
      TRUE ~ time_1
    )
  ) %>%
  ungroup()

这里用case_when让条件分支更直观,pmin直接取当前值和组内最小值的较小值,不管当前值是不是最小,最终结果都符合需求。同时分组后建议用ungroup()取消分组,避免后续操作受分组状态影响。

方案2:合并mutate的简洁写法

如果偏好if_else,可以把逻辑合并到单个mutate中,省去中间变量:

df1 %>%
  group_by(id) %>%
  mutate(
    time_1 = if_else(item == "item_1" & time_1 != min(time_1), min(time_1), time_1)
  ) %>%
  ungroup()

优化点说明

  • 去掉了冗余的中间列min_,直接在替换逻辑中计算组内最小值,避免数据框冗余
  • 用单个mutate完成所有逻辑,更贴合dplyr管道式操作的风格
  • case_when的写法比嵌套ifelse更易读,后续如果要加其他替换规则也更容易扩展

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 02:20:38