简体   繁体   中英

How to avoid redundant calculation within data.table?

I need to find the unique two minima in data column at a data table by two ids id1 and id2 :

n <- 12
set.seed(1234)
id1 <- rep(1:2, each = 6)
id2 <- rep(1:6, each = 2)
data <- 100+100*rnorm(n)
dt <- data.table(id1=id1, id2=id2, data=data)

Find below the function that, given the second id id2 , calculates the two unique minima at the same time and export them as a vector:

detect_two_lower <- function(ids, values){
  dt <- data.table(ids, values)
  dt <- dt[, .(V1=min(values, na.rm = T))
           , by = ids
  ][order(V1)]
  min_1 <- dt$V1[1]
  min_2 <- dt$V1[2]
  nn <- c(min_1 = min_1, min_2 = min_2)
}
detect_two_lower <- memoise(detect_two_lower)

Then apply the function on the data.table, grouping by = id1 :

dt[, `:=` ( min_1 = detect_two_lower(id2, data)[1]
           ,min_2 = detect_two_lower(id2, data)[2])
   , by = id1
]

The calculation runs as expected (see below). Note, however, that the code calls detect_two_lower twice with the same parameters. As a workaround I tried to minimize the reworking with memoise , but I would like to avoid this patch. Is there a better way to accomplish the same result?

dt
    id1 id2         data        min_1     min_2
 1:   1   1  -20.7065749 -134.5697703 -20.70657
 2:   1   1  127.7429242 -134.5697703 -20.70657
 3:   1   2  208.4441177 -134.5697703 -20.70657
 4:   1   2 -134.5697703 -134.5697703 -20.70657
 5:   1   3  142.9124689 -134.5697703 -20.70657
 6:   1   3  150.6055892 -134.5697703 -20.70657
 7:   2   4   42.5260040    0.1613555  10.99622
 8:   2   4   45.3368144    0.1613555  10.99622
 9:   2   5   43.5548001    0.1613555  10.99622
10:   2   5   10.9962171    0.1613555  10.99622
11:   2   6   52.2807300    0.1613555  10.99622
12:   2   6    0.1613555    0.1613555  10.99622 

Return a list from the function

library(data.table)

detect_two_lower <- function(ids, values){
  dt <- data.table(ids, values)
  dt <- dt[, .(V1=min(values, na.rm = T)), by = ids][order(V1)]
  as.list(dt$V1)
}

So you can assign them directly:

dt[, c('min_1', 'min_2') := detect_two_lower(id2, data), id1]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM