我的 data.table 加入超过了 64 位 Windows 机器上 32GB RAM 的内存限制
My data.table join exceeds memory limit on 64bit Windows machine with 32gb RAM
背景
我需要对非常大的 data.table
进行一些数据操作,我们将调用 d1
(约 1.25 亿行 x 10 列)我从 .csv 读入 R
表格使用 fread
。数据是关于汽车保险运行ce -- t运行与变速箱相关和与发动机相关的索赔。这是读物:
d1 <- fread("c:/analysis.csv",
header = TRUE,
na.strings = c("", "NA"),
data.table = TRUE,
stringsAsFactors = TRUE)
我需要在 d1
上做的工作相当简单 dplyr
东西 -- 一些连接(在小得多的 tables 上),一对 mutate
的等。让我们将那些更小的 tables 称为 d2
和 d3
以供参考;假设这些也以与上述 d1
相同的方式 data.tables
读入 R
。我已经在 d1
的更小的“测试”子集上计划了这些操作(连接和变异),所以我知道它们会起作用。
我 运行 正在 R
使用的机器有 32gb 内存、最新的 Comet Lake Intel Core i5 和 1TB NVMe SSD。我的 Windows 和 R
版本是 64 位。
作为参考,这里是 space 每个数据集占用的数量:
> format(object.size(d1), "Gb")
[1] "4 Gb"
> format(object.size(d2), "Mb")
[1] "3.2 Mb"
这里是str(d1)
所以你可以看到数据类型:
Classes ‘data.table’ and 'data.frame': 125640181 obs. of 10 variables:
$ id : int 1551444 ...
$ service_dt : IDate, format: "2020-11-22" ...
$ service_code : Factor w/ 41817 levels "316",..
$ problem_code : Factor w/ 39531 levels "0",
$ problem_flag : int 0 0 0 0 0 0 0 1 1 0 ...
$ problem_type : Factor w/ 2 levels "transmission","engine": 1 1 ...
$ customer_dob : IDate, format: "1976-04-14" "1980-04-25" ...
$ customer_gender_cd : Factor w/ 3 levels "F","M","U": 1 2 ...
$ customer_zip_cd : Factor w/ 8354 levels "00000","00003"
$ old_id : int 13449983 ...
还有str(d2)
:
'data.frame': 37323 obs. of 4 variables:
$ service_code : Factor w/ 36281 levels "00002081702",..: 1 2 3 ...
$ parts_used : Factor w/ 215 levels "Disc Brake Rotor (Front)",..: 136 ...
$ category : Factor w/ 5 levels "Brakes",..: 1 1 ...
$ subcategory_1 : Factor w/ 24 levels "Rotors",..: 22 20 ...
问题
我去运行这个加入...
d1 <- left_join(d1, d2, by = c("service_code" = "service_code"))
... 我收到此错误:Error: cannot allocate vector of size 277.7 Gb
。请注意,这里的 d2
看起来像这样:
> dim(d2)
[1] 37323 4
我试过的
所以我在 Whosebug 上阅读了几篇“R 内存不足”的帖子,试图弄清楚我能做些什么。使用 data.table
s 是一个建议。在 运行 加入之前,我尝试使用 gc()
到 运行 垃圾收集;那也不管用。如果我查看内存限制,我会得到:
> memory.limit()
[1] 32502
我认为这意味着 R
可能已经分配了我系统的所有 RAM,我不确定这是否可以更高。
在其他帖子中,我阅读了有关大型数据集的包 ff
,但我 运行 在尝试使用它时遇到了其他麻烦。我已经成功地将我的 data.tables
变成了 ffdf
格式,如下所示:
d1 <- as.ffdf(d1)
d2 <- as.ffdf(d2)
然后尝试运行加入,但是得到这个错误:Error in UseMethod("left_join") : no applicable method for 'left_join' applied to an object of class "ffdf"
.
我担心的是,即使我能以某种方式将这个特定的 ff
代码转换为 运行,我必须做的其余工作非常依赖于 dplyr
。我担心 ff
宇宙中不存在我需要做的等效函数,如果这有意义的话。有没有办法继续使用 ff
,但将 d1
和 d2
(和 d3
,此处未显示)保留为 data.table
s?
编辑
在与@serkan 进行一些互动后——请参阅下面他们非常有用的答案——我发现 d2
具有我的连接键 d2$service_code
的重复值。事实上,其中大约有 1100 个。事后看来,这可能是 R
在简单的左连接上被 vector of size 277.7 Gb
绊倒的主要原因。所以,我今天学到了一些东西:左连接时,确保你的RHS table的关键变量是唯一的!
我建议 dtplyr
以这种方式,
large_data <- tibble(
id = 1:125640181,
value1 = 1:125640181,
value2 = 1:125640181,
value3 = 1:125640181,
value4 = 1:125640181,
value5 = 1:125640181,
value6 = 1:125640181,
value7 = 1:125640181,
value8 = 1:125640181,
value9 = 1:125640181
) %>% lazy_dt()
small_data <- tibble(
id = 1:37323,
value1 = 1:37323,
value2 = 1:37323,
value3 = 1:37323
) %>% lazy_dt()
然后 join
通过,
joined_data <- left_join(
large_data,
small_data, by = "id"
) %>% as_tibble()
这给出了,
# A tibble: 6 x 13
id value1.x value2.x value3.x value4 value5 value6 value7 value8 value9 value1.y value2.y value3.y
<int> <int> <int> <int> <int> <int> <int> <int> <int> <int> <int> <int> <int>
1 1 1 1 1 1 1 1 1 1 1 1 1 1
2 2 2 2 2 2 2 2 2 2 2 2 2 2
3 3 3 3 3 3 3 3 3 3 3 3 3 3
4 4 4 4 4 4 4 4 4 4 4 4 4 4
5 5 5 5 5 5 5 5 5 5 5 5 5 5
6 6 6 6 6 6 6 6 6 6 6 6 6 6
在我的机器上也有 32 Gb
内存。您可以保留所有 dplyr
函数和 syntax
,同时滥用 data.table
!
的内存效率
阅读更多相关信息
背景
我需要对非常大的 data.table
进行一些数据操作,我们将调用 d1
(约 1.25 亿行 x 10 列)我从 .csv 读入 R
表格使用 fread
。数据是关于汽车保险运行ce -- t运行与变速箱相关和与发动机相关的索赔。这是读物:
d1 <- fread("c:/analysis.csv",
header = TRUE,
na.strings = c("", "NA"),
data.table = TRUE,
stringsAsFactors = TRUE)
我需要在 d1
上做的工作相当简单 dplyr
东西 -- 一些连接(在小得多的 tables 上),一对 mutate
的等。让我们将那些更小的 tables 称为 d2
和 d3
以供参考;假设这些也以与上述 d1
相同的方式 data.tables
读入 R
。我已经在 d1
的更小的“测试”子集上计划了这些操作(连接和变异),所以我知道它们会起作用。
我 运行 正在 R
使用的机器有 32gb 内存、最新的 Comet Lake Intel Core i5 和 1TB NVMe SSD。我的 Windows 和 R
版本是 64 位。
作为参考,这里是 space 每个数据集占用的数量:
> format(object.size(d1), "Gb")
[1] "4 Gb"
> format(object.size(d2), "Mb")
[1] "3.2 Mb"
这里是str(d1)
所以你可以看到数据类型:
Classes ‘data.table’ and 'data.frame': 125640181 obs. of 10 variables:
$ id : int 1551444 ...
$ service_dt : IDate, format: "2020-11-22" ...
$ service_code : Factor w/ 41817 levels "316",..
$ problem_code : Factor w/ 39531 levels "0",
$ problem_flag : int 0 0 0 0 0 0 0 1 1 0 ...
$ problem_type : Factor w/ 2 levels "transmission","engine": 1 1 ...
$ customer_dob : IDate, format: "1976-04-14" "1980-04-25" ...
$ customer_gender_cd : Factor w/ 3 levels "F","M","U": 1 2 ...
$ customer_zip_cd : Factor w/ 8354 levels "00000","00003"
$ old_id : int 13449983 ...
还有str(d2)
:
'data.frame': 37323 obs. of 4 variables:
$ service_code : Factor w/ 36281 levels "00002081702",..: 1 2 3 ...
$ parts_used : Factor w/ 215 levels "Disc Brake Rotor (Front)",..: 136 ...
$ category : Factor w/ 5 levels "Brakes",..: 1 1 ...
$ subcategory_1 : Factor w/ 24 levels "Rotors",..: 22 20 ...
问题
我去运行这个加入...
d1 <- left_join(d1, d2, by = c("service_code" = "service_code"))
... 我收到此错误:Error: cannot allocate vector of size 277.7 Gb
。请注意,这里的 d2
看起来像这样:
> dim(d2)
[1] 37323 4
我试过的
所以我在 Whosebug 上阅读了几篇“R 内存不足”的帖子,试图弄清楚我能做些什么。使用 data.table
s 是一个建议。在 运行 加入之前,我尝试使用 gc()
到 运行 垃圾收集;那也不管用。如果我查看内存限制,我会得到:
> memory.limit()
[1] 32502
我认为这意味着 R
可能已经分配了我系统的所有 RAM,我不确定这是否可以更高。
在其他帖子中,我阅读了有关大型数据集的包 ff
,但我 运行 在尝试使用它时遇到了其他麻烦。我已经成功地将我的 data.tables
变成了 ffdf
格式,如下所示:
d1 <- as.ffdf(d1)
d2 <- as.ffdf(d2)
然后尝试运行加入,但是得到这个错误:Error in UseMethod("left_join") : no applicable method for 'left_join' applied to an object of class "ffdf"
.
我担心的是,即使我能以某种方式将这个特定的 ff
代码转换为 运行,我必须做的其余工作非常依赖于 dplyr
。我担心 ff
宇宙中不存在我需要做的等效函数,如果这有意义的话。有没有办法继续使用 ff
,但将 d1
和 d2
(和 d3
,此处未显示)保留为 data.table
s?
编辑
在与@serkan 进行一些互动后——请参阅下面他们非常有用的答案——我发现 d2
具有我的连接键 d2$service_code
的重复值。事实上,其中大约有 1100 个。事后看来,这可能是 R
在简单的左连接上被 vector of size 277.7 Gb
绊倒的主要原因。所以,我今天学到了一些东西:左连接时,确保你的RHS table的关键变量是唯一的!
我建议 dtplyr
以这种方式,
large_data <- tibble(
id = 1:125640181,
value1 = 1:125640181,
value2 = 1:125640181,
value3 = 1:125640181,
value4 = 1:125640181,
value5 = 1:125640181,
value6 = 1:125640181,
value7 = 1:125640181,
value8 = 1:125640181,
value9 = 1:125640181
) %>% lazy_dt()
small_data <- tibble(
id = 1:37323,
value1 = 1:37323,
value2 = 1:37323,
value3 = 1:37323
) %>% lazy_dt()
然后 join
通过,
joined_data <- left_join(
large_data,
small_data, by = "id"
) %>% as_tibble()
这给出了,
# A tibble: 6 x 13
id value1.x value2.x value3.x value4 value5 value6 value7 value8 value9 value1.y value2.y value3.y
<int> <int> <int> <int> <int> <int> <int> <int> <int> <int> <int> <int> <int>
1 1 1 1 1 1 1 1 1 1 1 1 1 1
2 2 2 2 2 2 2 2 2 2 2 2 2 2
3 3 3 3 3 3 3 3 3 3 3 3 3 3
4 4 4 4 4 4 4 4 4 4 4 4 4 4
5 5 5 5 5 5 5 5 5 5 5 5 5 5
6 6 6 6 6 6 6 6 6 6 6 6 6 6
在我的机器上也有 32 Gb
内存。您可以保留所有 dplyr
函数和 syntax
,同时滥用 data.table
!
阅读更多相关信息