R中变量windows滚动最大值/最小值的内存效率

Memory efficiency of rolling max / mins with variable windows in R

我一直在做一个练习,我需要在一些大型数据集(~100 - 2.5 亿行)上使用变量 window 长度来计算最大/最小值。

简而言之,我有一个 table 显示开始和结束索引(在下面用“Lookup_table”表示),它反映了第二个 table 的行位置(参考如下面的“Price_table”)。使用这些行位置,然后我需要提取“Price_table”中特定列的最大值和最小值。我需要对“查找”的所有行重复此操作 table。

例如,如果“Lookup_table”的第一行有 Start = 1 和 End = 5,我需要从行中找到 Price_table 中目标列的最大值/最小值1 到 5(含)。然后,如果第二列的 Start = 6,End = 12,那么我会在第 6 行到第 12 行的 Price_table 内找到最大值/最小值,依此类推。

我在下面创建了一组包含 10,000 行的虚拟数据(对所有包要求表示歉意)。

require(data.table)
require(dplyr)
require(purrr)
   
# Number of rows
nn <- 10000
# Create a random table of Price data with 1,000,000 rows
Price_table <- data.table(Price = runif(nn,300,1000)) %>% mutate(.,Index = seq_len(nrow(.)))

# Create a lookup table with start / end indexes
Lookup_table <- data.table(Start = floor(sort(runif(nn,1,nn)))) %>% mutate(.,End = shift(Start,fill = nn,type = "lead"))

我最初使用以下代码行计算了最大值/最小值。不幸的是,我发现它在非常大的数据集上失败了,因为它 运行 内存不足(我有 64 Gig 内存)。

# Option 1: Determine the max / min between the Start / End prices in the "Price_table" table's "Price" column
Lookup_table[,(c("High_2","Low_2")) := rbindlist(pmap(.l = list(x = Start,y = End),
                       function(x,y) data.table(Max = max(Price_table$Price[x:y],na.rm = T),
                                                Min = min(Price_table$Price[x:y],na.rm = T))))]

我还没有在完整的数据集上重新测试以下替代选项,但基于一些较小的数据集,它似乎更节省内存(好吧,至少使用 memory.size(),它可能会或可能不会提供准确的反映...)。

# Option 2: Use mapply separately to determine the max / min between the Start / End prices in the "Price_table" table's "Price" column
Lookup_table[,High := mapply(function(x,y) max(Price_table$Price[x:y],na.rm = T),Start,End)]
Lookup_table[,Low := mapply(function(x,y) min(Price_table$Price[x:y],na.rm = T),Start,End)]

我有两个问题:

  1. 如果我说 mapply 方法的内存效率更高(不是一般情况下,但至少相对于我的第一次尝试而言)是正确的,有人可以解释为什么会这样吗?例如,是因为在第一次尝试中使用了 rbindlist() + data.table() 调用吗?
  2. 在处理更大的数据集时,是否还有其他内存高效(且速度更快?)的方法可供我考虑?

提前致谢。 菲尔

你可以使用 non-equijoins :

Price_table[Lookup_table,.(Price,Start,End),on=.(Index>=Start,Index<=End)][
            ,.(Low = min(Price), High = max(Price)),by=.(Start,End)]

      Start   End      Low     High
   1:     3     5 668.3308 908.1017
   2:     5     5 908.1017 908.1017
   3:     5     6 333.3477 908.1017
   4:     6     7 333.3477 827.1258
   5:     7     8 785.8887 827.1258
  ---                              
8947:  9993  9995 395.8449 827.7860
8948:  9995  9995 827.7860 827.7860
8949:  9995  9997 418.7436 827.7860
8950:  9997  9999 418.7436 947.1398
8951:  9999 10000 489.3145 634.6268