我的组似乎没有在磁盘框架中工作

My group by doesn't appear to be working in disk frames

我 运行 在一个大型数据集 (>20GB) 上分组,但它似乎工作不正常

这是我的代码

mydf[, .(value = n_distinct(list_of_id, na.rm = T)),
                      by = .(week),
                      keep = c("list_of_id", "week")
                      ] 

它返回了这个错误

Warning messages: 1: In serialize(data, node$con) :
'package:MLmetrics' may not be available when loading 2: In serialize(data, node$con) : 'package:MLmetrics' may not be available when loading 3: In serialize(data, node$con) : 'package:MLmetrics' may not be available when loading 4: In serialize(data, node$con) :
'package:MLmetrics' may not be available when loading 5: In serialize(data, node$con) : 'package:MLmetrics' may not be available when loading 6: In serialize(data, node$con) : 'package:MLmetrics' may not be available when loading 7: In serialize(data, node$con) :
'package:MLmetrics' may not be available when loading 8: In serialize(data, node$con) : 'package:MLmetrics' may not be available when loading

我最初加载了库,但后来我 运行 remove.packages(MLmetrics) 在 运行 执行此代码之前。此外,我检查了 conflicted::conflict_scout,没有发现与 MLmetrics 包有任何冲突。

当我运行这段代码

> mydf %>% 
+   filter(week == "2012-01-02")

它给了我这个输出

         week    value 
1: 2012-01-02      483     
2: 2012-01-02     61233  

我担心在对数据进行分组时出现问题,因为它没有创建不同的价值周组。两列都存储为字符数据类型。

disk.frame 看起来很有趣,可以填补 RAM 处理和大数据之间的空白。

为了测试它,我创建了一个 200 * 200 Mb CSV 文件的集合,总计 40Gb,超过了我计算机上安装的 32Gb RAM:

library(furrr)
library(magrittr)
library(data.table)
library(dplyr)
library(disk.frame)
plan(multisession,workers = 11)
nbrOfWorkers()
#[1] 11

filelength <- 1e7

# Create 200 files * 200Mb
sizelist <- 1:200 %>% future_map(~{
  mydf <- data.table(week = sample(1:52,filelength,replace=T),
                     list_of_id=sample(1:filelength,filelength,replace=T))
  filename <- paste0('data/test',.x,'.csv')
  data.table::fwrite(mydf, filename)
  ##write.csv(mydf,file=filename)
  file.size(filename)
})

sum(unlist(sizelist))
# [1] 43209467799

由于distinct_n是一个dplyr动词,我先停留在dplyr句法:

setup_disk.frame()
#The number of workers available for disk.frame is 6
options(future.globals.maxSize = Inf)

mydf = csv_to_disk.frame(file.path('data',list.files('data')))
"
csv_to_disk.frame: Reading multiple input files.
Please use `colClasses = `  to set column types to minimize the chance of a failed read
=================================================

 ----------------------------------------------------- 
-- Converting CSVs to disk.frame -- Stage 1 of 2:

Converting 200 CSVs to 60 disk.frames each consisting of 60 chunks

 Progress: ──────────────────────────────────────────────────────────────── 100%

-- Converting CSVs to disk.frame -- Stage 1 or 2 took: 00:01:44 elapsed (0.130s cpu)
 ----------------------------------------------------- 
 
 ----------------------------------------------------- 
-- Converting CSVs to disk.frame -- Stage 2 of 2:

Row-binding the 60 disk.frames together to form one large disk.frame:
Creating the disk.frame at c:\TempWin\RtmpkNkY9H\file398469c42f1b.df

Appending disk.frames: 
 Progress: ──────────────────────────────────────────────────────────────── 100%

Stage 2 of 2 took: 59.9s elapsed (0.370s cpu)
 ----------------------------------------------------- 
Stage 1 & 2 in total took: 00:02:44 elapsed (0.500s cpu)"


result <- mydf %>% 
  group_by(week) %>% 
  summarize(value = n_distinct(list_of_id)) %>% 
  collect  

result
# A tibble: 52 x 2
    week   value
   <int>   <int>
 1     1 9786175
 2     2 9786479
 3     3 9786222
 4     4 9785997
 5     5 9785833
 6     6 9786013
 7     7 9786586
 8     8 9786029
 9     9 9785674
10    10 9786314
# ... with 42 more rows

原来如此! 用于此特定任务的总 RAM 内存在 1 到 5Gb 之间波动,在 6 个处理器上处理 20 亿行花费了不到 10 分钟的时间,限制因素似乎是磁盘访问速度而不是处理器性能。

我还用 data.table 语法进行了测试,因为 disk.frame 两者都接受,但我返回的速度太快了 60 倍多的行(好像 60 disk.frames 创建了200 个 CSV 未合并 and/or 完全处理),还有很多 Warning messages: 1: In serialize(data, node$con).

我在 GitHub 上提交了一个问题。
在弄清楚这一点之前,我建议继续使用有效的 dplyr 语法。

这个例子让我相信 disk.frame 允许处理比 RAM 更大的数据 supported verbs

此处为{disk.frame}的作者。

问题是目前,{disk.frame} 没有按 within 每个块分组。它不像 dplyr 语法那样在全局范围内执行 group-by。

所以你得再总结一遍,才能达到你想要的效果。所以我建议现在坚持使用 dplyr 语法。

正如@Waldi 指出的那样,{disk.frame} 的 dplyr 语法工作正常,目前缺少对 data.table 的支持,因此您现在只能使用 dplyr 语法实现您想要的。

{disk.frame} 需要实施 https://github.com/xiaodaigh/disk.frame/issues/239 才能适用于 data.table.

如果 anyone/organization 愿意资助此功能的开发,请私信我。