【问题标题】:slow function by groups in data.table rdata.table r 中按组的慢速函数
【发布时间】:2019-03-20 14:34:14
【问题描述】:

我的实验设计在不同的森林中测量了树木,并在多年内重复测量。

DT <- data.table(forest=rep(c("a","b"),each=6),
                    year=rep(c("2000","2010"),each=3),
                    id=c("1","2","3"),
                    size=(1:12))

DT[,id:=paste0(forest,id)]

> DT
    forest year id size
 1:     a 2000 a1     1
 2:     a 2000 a2     2
 3:     a 2000 a3     3
 4:     a 2010 a1     4
 5:     a 2010 a2     5
 6:     a 2010 a3     6
 7:     b 2000 b1     7
 8:     b 2000 b2     8
 9:     b 2000 b3     9
10:     b 2010 b1    10
11:     b 2010 b2    11
12:     b 2010 b3    12

对于每棵树 i,我想计算一个新变量,等于同一组/年中比树 i 大的所有其他个体的大小的总和。

我创建了以下函数:

f.new <- function(i,n){ 
 DT[forest==DT[id==i, unique(forest)] & year==n # select the same forest & year of the tree i
 & size>DT[id==i & year==n, size], # select the trees larger than the tree i
 sum(size, na.rm=T)] # sum the sizes of all such selected trees
}

在数据表中应用时,我得到了正确的结果。

       DT[,new:=f.new(id,year), by=.(id,year)]

> DT
    forest year id size new
 1:     a 2000 a1     1   5
 2:     a 2000 a2     2   3
 3:     a 2000 a3     3   0
 4:     a 2010 a1     4  11
 5:     a 2010 a2     5   6
 6:     a 2010 a3     6   0
 7:     b 2000 b1     7  17
 8:     b 2000 b2     8   9
 9:     b 2000 b3     9   0
10:     b 2010 b1    10  23
11:     b 2010 b2    11  12
12:     b 2010 b3    12   0

请注意,我有一个包含多个森林 (40)、重复年份 (6) 和单个个体 (20,000) 的大型数据集,总共进行了近 50,000 次测量。当我执行上述功能时,需要 8-10 分钟(Windows 7,i5-6300U CPU @ 2.40 GHz 2.40 GHz,RAM 8 GB)。我需要经常重复它并进行一些小的修改,这需要很多时间。

  1. 有更快的方法吗?我检查了 *apply 函数,但无法根据它们找出解决方案。
  2. 我能否创建一个不依赖于数据集特定结构的通用函数(即我可以用作“大小”不同的列)?

【问题讨论】:

  • 您基本上已经以低效的方式实现了联接操作。可能有一种方法可以使用 data.table 非 equi 连接,但它仍然比我的答案慢得多。

标签: r function data.table


【解决方案1】:

只需对数据进行排序,这会非常快:

setorder(DT, forest, year, -size)
DT[, new := cumsum(size) - size, by = .(forest, year)]
setorder(DT, forest, year, id)
DT
#    forest year id size new
# 1:      a 2000 a1    1   5
# 2:      a 2000 a2    2   3
# 3:      a 2000 a3    3   0
# 4:      a 2010 a1    4  11
# 5:      a 2010 a2    5   6
# 6:      a 2010 a3    6   0
# 7:      b 2000 b1    7  17
# 8:      b 2000 b2    8   9
# 9:      b 2000 b3    9   0
#10:      b 2010 b1   10  23
#11:      b 2010 b2   11  12
#12:      b 2010 b3   12   0

【讨论】:

  • 或者暂时重新排序DT[order(forest, year, -size), v := cumsum(c(0, size[-.N])), by=.(forest, year)] 我想可能需要稍微不同的东西来处理领带。
  • @Frank 对,我没有考虑过关系。可能需要在by = .(forest, year, size) 中减去(多个)size
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-08-23
  • 1970-01-01
  • 2016-11-23
  • 1970-01-01
  • 2018-12-18
  • 1970-01-01
  • 2015-04-04
相关资源
最近更新 更多