pivot_longer 运行 在小对象上的内存使用
Memory usage of pivot_longer run on small object
我正在处理一个包含 528 列和 2,643,246 行的数据框。其中八个是字符变量,其余是整数。总共有 11.35 GiB 的数据,我的可用 RAM 为 164 GiB。
我现在想 运行 在所述数据框上 pivot_longer
,每列一行 + 两个 ID 变量(年份和机构)。 76年以上机构总数671370所。
所以 atm 数据的结构如下:
Institution
Year
X
Y
Z
A
1
2
1
3
A
2
3
4
4
B
1
3
4
2
B
2
5
3
2
我想更改它的地方,使结构变为:
Institution
Year
G
N
A
1
X
2
A
1
Y
1
A
1
Z
3
A
2
X
3
A
2
Y
1
A
2
Z
4
B
1
X
3
B
1
Y
4
B
1
Z
2
B
2
X
5
B
2
Y
3
B
2
Z
2
为此,我尝试了以下代码:
library(tidyverse)
Df <- Df %>% pivot_longer(17:527,
names_to = "G",
values_to = "N"
)
当 运行 对小样本数据进行此操作时,我设法达到了预期的结果,但是当尝试对整个数据集执行相同操作时,我很快 运行 内存不足。从使用 11 GiB 内存的对象开始,它在返回“无法分配大小为 x Gb 的向量”错误之前迅速增加到 150 GiB 以上。
因为我没有添加任何数据,所以我不太明白额外的内存使用量是从哪里来的。因此,我想知道是什么造成了这种增加,以及是否有更有效的方法通过其他一些代码来解决这个问题。
在此先感谢您的帮助!
我无法在您的数据上测试代码,但这是一个想法。
我们的想法是一次对一大块行进行从宽到长的转换,将结果存储在列表中。最后,将列表组合成最终的数据框。希望这可以减少内存使用量。
如果不行,试试data.table
中的melt
是否可以更有效地转换数据。
另一个可能有用的想法。也许通过在从宽到长的转换之前删除第 1 列到第 16 列来对 Df
进行子集化,只保留一个 ID
列。您可以稍后将第 1 列到第 16 列连接回转换后的数据框。
library(tidyverse)
Df_list <- list()
Institution <- unique(DF$Institution)
for (i in Institution){
Df_temp <- Df %>%
filter(Institution %in% i) %>%
pivot_longer(17:527, names_to = "G", values_to = "N")
Df_list[[i]] <- Df_temp
}
Df <- bind_rows(Df_list)
对于这种大小的数据,reshape2
或 data.table
的旋转可能比 tidyr
的更节省内存。在较小的 800MB 样本中,reshape2::melt
需要的内存大约是原始数据的 2.6 倍,data.table::melt
需要大约 3.6 倍,而本例中的 tidyr::pivot_longer
方法需要大约 12 倍内存很大,速度慢了大约 20 倍。
编辑:在查看警告后,我意识到当我调用 data.table::melt
时,我的早期草稿实际上是在幕后使用 reshape2
,因为我正在给它喂食。添加了明确的 data.table::melt
解决方案,其中包括将数据转换为 data.table。对于此数据,reshape2::melt
似乎更快且内存效率更高。
示例数据
n1 = as.integer(2E8/26)
set.seed(42)
data_long <- data.frame(Institution = 1:n1,
G = rep(letters, each = n1),
Z = rpois(26*n1, 10))
data_wide <- data_long %>% pivot_wider(names_from = G, values_from = Z)
基准
bench::mark(
tidyr::pivot_longer(data_wide, -1),
reshape2::melt(data_wide, id.vars = 1),
data.table::melt(data.table::as.data.table(data_wide), id.vars = 1),
check = FALSE,
iterations = 10
)
# A tibble: 3 x 13
expression min median `itr/sec` mem_alloc `gc/sec` n_itr n_gc total_time
<bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl> <int> <dbl> <bch:tm>
1 tidyr::pivot_longer(data_wide, -1) 26.77s 37.38s 0.0269 10.52GB 0.0538 10 20 6.2m
2 reshape2::melt(data_wide, id.vars = 1) 1.25s 1.73s 0.519 2.23GB 0.156 10 3 19.3s
3 data.table::melt(data.table::as.data.table(data_wide), id.vars = 1) 1.82s 2.41s 0.332 3.01GB 0.232 10 7 30.1s
# … with 4 more variables: result <list>, memory <list>, time <list>, gc <list>
我正在处理一个包含 528 列和 2,643,246 行的数据框。其中八个是字符变量,其余是整数。总共有 11.35 GiB 的数据,我的可用 RAM 为 164 GiB。
我现在想 运行 在所述数据框上 pivot_longer
,每列一行 + 两个 ID 变量(年份和机构)。 76年以上机构总数671370所。
所以 atm 数据的结构如下:
Institution | Year | X | Y | Z |
---|---|---|---|---|
A | 1 | 2 | 1 | 3 |
A | 2 | 3 | 4 | 4 |
B | 1 | 3 | 4 | 2 |
B | 2 | 5 | 3 | 2 |
我想更改它的地方,使结构变为:
Institution | Year | G | N |
---|---|---|---|
A | 1 | X | 2 |
A | 1 | Y | 1 |
A | 1 | Z | 3 |
A | 2 | X | 3 |
A | 2 | Y | 1 |
A | 2 | Z | 4 |
B | 1 | X | 3 |
B | 1 | Y | 4 |
B | 1 | Z | 2 |
B | 2 | X | 5 |
B | 2 | Y | 3 |
B | 2 | Z | 2 |
为此,我尝试了以下代码:
library(tidyverse)
Df <- Df %>% pivot_longer(17:527,
names_to = "G",
values_to = "N"
)
当 运行 对小样本数据进行此操作时,我设法达到了预期的结果,但是当尝试对整个数据集执行相同操作时,我很快 运行 内存不足。从使用 11 GiB 内存的对象开始,它在返回“无法分配大小为 x Gb 的向量”错误之前迅速增加到 150 GiB 以上。
因为我没有添加任何数据,所以我不太明白额外的内存使用量是从哪里来的。因此,我想知道是什么造成了这种增加,以及是否有更有效的方法通过其他一些代码来解决这个问题。 在此先感谢您的帮助!
我无法在您的数据上测试代码,但这是一个想法。
我们的想法是一次对一大块行进行从宽到长的转换,将结果存储在列表中。最后,将列表组合成最终的数据框。希望这可以减少内存使用量。
如果不行,试试data.table
中的melt
是否可以更有效地转换数据。
另一个可能有用的想法。也许通过在从宽到长的转换之前删除第 1 列到第 16 列来对 Df
进行子集化,只保留一个 ID
列。您可以稍后将第 1 列到第 16 列连接回转换后的数据框。
library(tidyverse)
Df_list <- list()
Institution <- unique(DF$Institution)
for (i in Institution){
Df_temp <- Df %>%
filter(Institution %in% i) %>%
pivot_longer(17:527, names_to = "G", values_to = "N")
Df_list[[i]] <- Df_temp
}
Df <- bind_rows(Df_list)
对于这种大小的数据,reshape2
或 data.table
的旋转可能比 tidyr
的更节省内存。在较小的 800MB 样本中,reshape2::melt
需要的内存大约是原始数据的 2.6 倍,data.table::melt
需要大约 3.6 倍,而本例中的 tidyr::pivot_longer
方法需要大约 12 倍内存很大,速度慢了大约 20 倍。
编辑:在查看警告后,我意识到当我调用 data.table::melt
时,我的早期草稿实际上是在幕后使用 reshape2
,因为我正在给它喂食。添加了明确的 data.table::melt
解决方案,其中包括将数据转换为 data.table。对于此数据,reshape2::melt
似乎更快且内存效率更高。
示例数据
n1 = as.integer(2E8/26)
set.seed(42)
data_long <- data.frame(Institution = 1:n1,
G = rep(letters, each = n1),
Z = rpois(26*n1, 10))
data_wide <- data_long %>% pivot_wider(names_from = G, values_from = Z)
基准
bench::mark(
tidyr::pivot_longer(data_wide, -1),
reshape2::melt(data_wide, id.vars = 1),
data.table::melt(data.table::as.data.table(data_wide), id.vars = 1),
check = FALSE,
iterations = 10
)
# A tibble: 3 x 13
expression min median `itr/sec` mem_alloc `gc/sec` n_itr n_gc total_time
<bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl> <int> <dbl> <bch:tm>
1 tidyr::pivot_longer(data_wide, -1) 26.77s 37.38s 0.0269 10.52GB 0.0538 10 20 6.2m
2 reshape2::melt(data_wide, id.vars = 1) 1.25s 1.73s 0.519 2.23GB 0.156 10 3 19.3s
3 data.table::melt(data.table::as.data.table(data_wide), id.vars = 1) 1.82s 2.41s 0.332 3.01GB 0.232 10 7 30.1s
# … with 4 more variables: result <list>, memory <list>, time <list>, gc <list>