【问题标题】:How to get a minimum value by group [duplicate]如何按组获得最小值[重复]
【发布时间】:2026-02-16 10:05:01
【问题描述】:

我有一个这样的数据框

library(dplyr)
test.df <- data.frame(id=c(1,1,1,3,3,3,3),
                      date=c("2016-02-13","2016-06-01",
                             "2016-09-01","2015-08-02",
                             "2015-09-21","2016-12-01",
                             "2017-02-11"))

test.df$date <- as.Date(test.df$date,format='%Y-%m-%d')

id    date
1   2016-02-13          
1   2016-06-01          
1   2016-09-01          
3   2015-08-02          
3   2015-09-21          
3   2016-12-01          
3   2017-02-11  

我想创建一个新变量first.login 来获取每个id 的第一个日期。输出将如下所示

id    date      first.login
1   2016-02-13  2016-02-13
1   2016-06-01  2016-02-13      
1   2016-09-01  2016-02-13      
3   2015-08-02  2015-08-02      
3   2015-09-21  2015-08-02      
3   2016-12-01  2015-08-02      
3   2017-02-11  2015-08-02

我尝试使用这样的代码

new.df <- test.df %>% 
  group_by(id) %>% 
  mutate(first.log = min(date))

但这给出的结果是为整个数据框提取最早日期,而不是在每个 ID 组内。

id    date      first.login
1   2016-02-13  2015-08-02
1   2016-06-01  2015-08-02      
1   2016-09-01  2015-08-02      
3   2015-08-02  2015-08-02      
3   2015-09-21  2015-08-02      
3   2016-12-01  2015-08-02      
3   2017-02-11  2015-08-02

这应该不是一个棘手的任务,但我想知道我犯了什么错误?如何在每个id 组中获得最早的?

更新: 我之前尝试过使用summarize

new.df <- test.df %>% 
  group_by(id) %>% 
  summarize(first.login = min(date))

但它返回单行和单列。

first.log
2015-08-02

事实证明这些代码没有问题;我只需要在其中指定dplyr::mutate

【问题讨论】:

  • 我认为你需要使用summarize。
  • 我认为该代码应该可以工作。请注意,您的示例有一个列标题 first.login 而您的代码有 first.log =
  • 我是这么想的,但它只返回单列单行first.log 2015-08-02

标签: r dplyr


【解决方案1】:

你想使用 summarise 而不是 mutate

new.df <- test.df %>% 
  group_by(id) %>% 
  summarize(first.log = min(date))

【讨论】:

  • 感谢您回答我的问题,我试过了,但它只返回单列单行first.log 2015-08-02
  • 同意。如果您想保留所有数据,那就不好了
【解决方案2】:

这是一个循序渐进的 R 基础解决方案:

# renaming for easy handle
x <- test.df$date
g <- test.df$id
# getting min
split(x, g) <- lapply(split(x, g), min)
# merging
test.df$first.login <- do.call("c", split(x, g))
#printting result
test.df
  id       date first.login
1  1 2016-02-13  2016-02-13
2  1 2016-06-01  2016-02-13
3  1 2016-09-01  2016-02-13
4  3 2015-08-02  2015-08-02
5  3 2015-09-21  2015-08-02
6  3 2016-12-01  2015-08-02
7  3 2017-02-11  2015-08-02

实际上这就是ave 在内部的工作方式

【讨论】:

    【解决方案3】:

    当您需要每行一个结果而不是每组一个值时,您应该使用基本 R 函数 ave

    test.df$first.login <- ave(test.df$date, test.df$id, FUN = min)
    test.df
    #  id       date first.login
    #1  1 2016-02-13  2016-02-13
    #2  1 2016-06-01  2016-02-13
    #3  1 2016-09-01  2016-02-13
    #4  3 2015-08-02  2015-08-02
    #5  3 2015-09-21  2015-08-02
    #6  3 2016-12-01  2015-08-02
    #7  3 2017-02-11  2015-08-02
    

    【讨论】: