【问题标题】:R data.table finding min and max within groupsR data.table 查找组内的最小值和最大值
【发布时间】:2021-07-12 16:37:48
【问题描述】:

您好,我有一个问题,我有一个人在不同公司工作的数据集。现在我想找出他工作的每家公司的持续时间。有些人回到他以前的公司工作。这是我的数据集和我的实现,但是当他稍后回到他以前的公司时它就不起作用了。

library(data.table)
data <- data.table(person = c(1,1,1,1,1,1,1,1), company = c(1,1,1,2,2,2,1,1),
               year = c(1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997))

你看到人 == 1 从 1990 年到 1992 年在公司 1 工作,然后从 1993 年到 1995 年转到公司 2。然后他从 1996 年到 1997 年回到公司 1。

我考虑过使用

min <- data[data[, .I[year == min(year)], by=.(person, company)]$V1]
setnames(min, "year", "start")

max <- data[data[, .I[year == max(year)], by=.(person, company)]$V1]
setnames(max, "year", "end")

duration <- merge(min, max, all = T)

你得到的:

person company start  end
     1       1  1990 1997
     1       2  1993 1995

但我想要的是:

person company start  end
     1       1  1990 1992
     1       2  1993 1995
     1       1  1996 1997

知道如何获得吗?

谢谢。

【问题讨论】:

    标签: r data.table


    【解决方案1】:

    我们可以使用rleid作为分组变量

    library(data.table)
    data[, .(start =  min(year), end = max(year)),
        .(person, grp = rleid(company), company)][, grp := NULL][]
    

    -输出

       person company start  end
    1:      1       1  1990 1992
    2:      1       2  1993 1995
    3:      1       1  1996 1997
    

    或者也可以使用collapse

    library(collapse)
    data[, grp := rleid(company)]
    collap(data,  ~ person + company + grp, list(fmin, fmax))
       person company fmin.year fmax.year grp
    1:      1       1      1990      1992   1
    2:      1       1      1996      1997   3
    3:      1       2      1993      1995   2
    

    【讨论】:

    • 由于某种原因,如果数据较大,我需要这样做:data[, grp := rleid(company), by=.(person)] 然后 data[, .(start = min(year), end = max(year)), .(person, grp), company)][grp := NULL] 谢谢
    • @Gabriel 如果数据很大,:= 会更快
    • 是的,我需要 1 分钟才能完成 4gb 数据集的操作,认为如果我们使用 .I 查找索引而不是在内存中执行它会更快。谢谢
    • @Gabriel 你可以试试`更新的折叠。我认为它会更快
    【解决方案2】:

    可能有更好的方法来做到这一点,但它就是这样:

    library(data.table)
    data = data.table(person = c(1,1,1,1,1,1,1,1), company = c(1,1,1,2,2,2,1,1),
                       year = c(1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997))
    
    data[, c('start', 'end', 'group') := 0]
    group_count = 0
    
    for (i in seq_len(nrow(data))) {
      if (i == 1) {
        next
        } else if (data[i, company] != data[i-1, company]) {
        group_count = group_count + 1
        data[i, group := group_count]
        } else {
        data[i, group := group_count]
        }
    }
    
    data[, c('start', 'end') := .(min(year), max(year)), by = group]
    
    data = unique(data[, .(person, company, start, end)])
    
    > data
       person company start  end
    1:      1       1  1990 1992
    2:      1       2  1993 1995
    3:      1       1  1996 1997
    

    【讨论】:

      【解决方案3】:

      采纳@akrun 的回答

      如果你的数据集很大

      data[, grp := rleid(company), by=.(person)]
      
      min <- data[data[, .I[year == min(year)], by=.(person, company, grp)]$V1]
      setnames(min, "year", "start")
      
      max <- data[data[, .I[year == max(year)], by=.(person, company, grp)]$V1]
      setnames(max, "year", "end")
      
      duration <- merge(min, max, all = T)
      

      【讨论】:

        猜你喜欢
        • 2021-09-15
        • 2012-09-16
        • 2016-06-06
        • 1970-01-01
        • 2018-05-03
        • 2017-04-20
        • 2014-06-11
        • 2015-09-29
        相关资源
        最近更新 更多