【问题标题】:R aggregate based on multiple columns and then merge into dataframe?R 基于多列聚合然后合并到数据框?
【发布时间】:2017-05-24 10:40:27
【问题描述】:

我有一个看起来像这样的数据框:

id<-c(1,1,1,3,3)
date1<-c("23-01-08","01-11-07","30-11-07","17-12-07","12-12-08")
type<-c("A","B","A","B","B")
df<-data.frame(id,date,type)
df$date<-as.Date(as.character(df$date), format = "%d-%m-%y")

我想要的是添加一个新列,其中包含每种类型的每个 ID 的最早日期。第一次尝试工作正常,并且仅基于 ID 进行聚合和合并。

d = aggregate(df$date, by=list(df$id), min)
df2 = merge(df, d, by.x="id", by.y="Group.1")

我想要的也是按类型过滤并得到这个结果:

data.frame(df2, desired=c("2007-11-30","2007-11-01", "2007-11-30","2007-12-17","2007-12-17"))

我尝试了很多可能性。我真的认为它可以用列表来完成,但我不知道如何......

d = aggregate(df$date, by=list(df$id, df$type), min)

# And merge the result of aggregate with the original data frame
df2 = merge(df,d,by.x=list("id","type"),by.y=list("Group.1","Group.2"))

对于这个简单的示例,我可以将类型分离到它们自己的 df 中,构建新列,然后组合生成的 2 个 df,但实际上有许多类型和第 3 列也必须进行类似过滤,这不会实用...

谢谢!

【问题讨论】:

  • 在制作df 时,date1date 之间存在拼写错误
  • @thelatemail 你是对的。我绕了一圈来制作那个日期栏...

标签: r merge aggregate


【解决方案1】:

我们可以使用data.table。将'data.frame'转换为'data.table'(setDT(df)),按'id'、'type'(或'id')、order'date'分组并分配(:=) 'date' 的第一个元素作为 'earliestdate' 列。

library(data.table)
setDT(df)[order(date), earliestdateid := date[1], by = id
    ][order(date), earliestdateidtype := date[1], by = .(id, type)]
df
#    id       date type earliestdateid earliestdateidtype
#1:  1 2008-01-23    A     2007-11-01         2007-11-30
#2:  1 2007-11-01    B     2007-11-01         2007-11-01
#3:  1 2007-11-30    A     2007-11-01         2007-11-30
#4:  3 2007-12-17    B     2007-12-17         2007-12-17
#5:  3 2008-12-12    B     2007-12-17         2007-12-17

dplyr 类似的方法是

library(dplyr)
df %>%
   group_by(id) %>%
   arrange(date) %>%
   mutate(earliestdateid = first(date)) %>%
   group_by(type, add = TRUE) %>%
   mutate(earliestdateidtype = first(date))

注意:这避免了分两步执行此操作,即获取汇总输出然后加入

【讨论】:

  • 哇,这就是我喜欢 R 的原因。在 1 行中处理了一堆复杂的操作。而且我认为2行很棒哈哈。如果我遇到类似但在数字列而不是日期上的情况,我是否只需将 order(date) 更改为 mean(numbers) 或 data.table 方式的类似效果?
  • @Soran 如果只需要mean(numbers),则不需要order,即setDT(df)[, Mean := mean(numbers), .(id, type)]
【解决方案2】:

您可以改为使用ave 来获得不同组的两个最小值:

df$minid <- with(df, ave(date, id, FUN=min, drop=TRUE) )
df$minidtype <- with(df, ave(date, list(id,type), FUN=min, drop=TRUE) )
df

#  id       date type      minid  minidtype
#1  1 2008-01-23    A 2007-11-01 2007-11-30
#2  1 2007-11-01    B 2007-11-01 2007-11-01
#3  1 2007-11-30    A 2007-11-01 2007-11-30
#4  3 2007-12-17    B 2007-12-17 2007-12-17
#5  3 2008-12-12    B 2007-12-17 2007-12-17

如果你很狡猾,你也可以在一个电话中完成所有事情:

df[c("minid", "minidtype")] <- lapply(list("id", c("id","type")),
                                  FUN=function(x) ave(df$date, df[x], FUN=min, drop=TRUE) )

【讨论】:

    猜你喜欢
    • 2015-05-17
    • 2015-01-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多