readLines 占用太多存储空间
readLines taking up too much storage
我正在使用 readLines
读取大量带有 ; 的非常大的 .csvs。使用以下代码分隔符:
read_p <- function(flnm) {
readLines(flnm) %>% str_split(pattern = "; ")
}
for (i in 1:length(files)){
dat[[i]] <- read_p(files[[i]])
}
其中 files
是文件名向量。代码本身运行得相当快,但它在 R 中占用了大约 4GB,而它在文件夹中只占用了 ~500MB——我在阅读它时是否遗漏了什么以避免?
我需要使用 readLines,因为没有 headers(所以它不是真正的 csv)并且每一行都有不同的 length/number 列。
感谢您的帮助!
从您之前(已删除)的问题中 test.csv
进行操作,转换为 numeric
后可能会有明显的不同。
作为记录,文件看起来像
996; 1160.32; 1774.51; 4321.05; 2530.97; 2817.63; 1796.18; ...
1008; 1774.51; 1796.18; 1192.42; 1285.69; 1225.96; 2229.92; ...
1020; 1796.18; 1285.69; 711.67; 1761.44; 1016.74; 1671.90; ...
1032; 1285.69; 1761.44; 1016.74; 1671.90; 725.51; 2466.49; ...
1044; 1761.44; 1016.74; 725.51; 2466.49; 661.82; 1378.85; ...
1056; 1761.44; 1016.74; 2466.49; 661.82; 1378.85; 972.94; ...
1068; 2466.49; 661.82; 1378.85; 972.94; 2259.46; 3648.49; ...
1080; 2466.49; 1378.85; 972.94; 2259.46; 1287.72; 1074.63; ...
虽然真正的 test.csv
有 751 行文本,每行有 10001-10017 个 ;
分隔的字段。这个(未删节的)文件不到 64 MiB。
读入、解析然后转换为数字对其对象大小有显着影响:
object.size(aa1 <- readLines("test.csv"))
# Warning in readLines("test.csv") :
# incomplete final line found on 'test.csv'
# 67063368 bytes
object.size(aa2 <- strsplit(aa1, "[; ]+"))
# 476021832 bytes
object.size(aa3 <- lapply(aa2, as.numeric))
# 60171040 bytes
我们最终得到:
length(aa3)
# [1] 751
str(aa3[1:4])
# List of 4
# $ : num [1:10006] 996 1160 1775 4321 2531 ...
# $ : num [1:10008] 1008 1775 1796 1192 1286 ...
# $ : num [1:10009] 1020 1796 1286 712 1761 ...
# $ : num [1:10012] 1032 1286 1761 1017 1672 ...
因此,将其读入全长字符串并不是内存爆炸的原因,而是将其拆分为每行 10000 多个字段。这是因为每个 的开销更大 character
对象:
### vec-1, nchar-0
object.size("")
# 112 bytes
### vec-5, nchar-0
object.size(c("","","","",""))
# 152 bytes
### vec-5, nchar-10
object.size(c("aaaaaaaaaa","aaaaaaaaaa","aaaaaaaaaa","aaaaaaaaaa","aaaaaaaaaa"))
# 160 bytes
如果我们查看原始数据,我们会看到爆炸:
object.size(aa1[1]) # whole lines at a time, so one line is 10000+ characters
# 89312 bytes
object.size(aa2[[1]]) # vector of 10000+ strings, each between 3-8 characters
# 633160 bytes
不过好在内存中的数字要小得多:
object.size(1)
# 56 bytes
object.size(c(1,2,3,4,5))
# 96 bytes
而且它的扩展性更好。显然,将 R 存储中的数据从 453MiB(拆分,字符串)减少到 57MiB(拆分,数字)就足够了。
在读取这些文件时,您仍然会看到 R 的内存使用量激增。您可以尝试通过在 strsplit
之后立即转换为数字来减少它;老实说,我不知道 R 的垃圾收集器(高级编程语言的常见事物)有多快 return 内存,我也不确定根据 R 的 "global string pool".但是如果你有兴趣,你可以试试这个改编你的功能。
func <- function(path) {
aa1 <- readLines(path)
aa2 <- lapply(aa1, function(st) as.numeric(strsplit(st, "[; ]+")[[1]]))
aa2
}
(我不保证它不会仍然“绽放”你的内存使用,但也许它不那么糟糕。)
然后 for
循环的规范替换(虽然那个循环很好)是
dat <- lapply(files, func)
我正在使用 readLines
读取大量带有 ; 的非常大的 .csvs。使用以下代码分隔符:
read_p <- function(flnm) {
readLines(flnm) %>% str_split(pattern = "; ")
}
for (i in 1:length(files)){
dat[[i]] <- read_p(files[[i]])
}
其中 files
是文件名向量。代码本身运行得相当快,但它在 R 中占用了大约 4GB,而它在文件夹中只占用了 ~500MB——我在阅读它时是否遗漏了什么以避免?
我需要使用 readLines,因为没有 headers(所以它不是真正的 csv)并且每一行都有不同的 length/number 列。
感谢您的帮助!
从您之前(已删除)的问题中 test.csv
进行操作,转换为 numeric
后可能会有明显的不同。
作为记录,文件看起来像
996; 1160.32; 1774.51; 4321.05; 2530.97; 2817.63; 1796.18; ...
1008; 1774.51; 1796.18; 1192.42; 1285.69; 1225.96; 2229.92; ...
1020; 1796.18; 1285.69; 711.67; 1761.44; 1016.74; 1671.90; ...
1032; 1285.69; 1761.44; 1016.74; 1671.90; 725.51; 2466.49; ...
1044; 1761.44; 1016.74; 725.51; 2466.49; 661.82; 1378.85; ...
1056; 1761.44; 1016.74; 2466.49; 661.82; 1378.85; 972.94; ...
1068; 2466.49; 661.82; 1378.85; 972.94; 2259.46; 3648.49; ...
1080; 2466.49; 1378.85; 972.94; 2259.46; 1287.72; 1074.63; ...
虽然真正的 test.csv
有 751 行文本,每行有 10001-10017 个 ;
分隔的字段。这个(未删节的)文件不到 64 MiB。
读入、解析然后转换为数字对其对象大小有显着影响:
object.size(aa1 <- readLines("test.csv"))
# Warning in readLines("test.csv") :
# incomplete final line found on 'test.csv'
# 67063368 bytes
object.size(aa2 <- strsplit(aa1, "[; ]+"))
# 476021832 bytes
object.size(aa3 <- lapply(aa2, as.numeric))
# 60171040 bytes
我们最终得到:
length(aa3)
# [1] 751
str(aa3[1:4])
# List of 4
# $ : num [1:10006] 996 1160 1775 4321 2531 ...
# $ : num [1:10008] 1008 1775 1796 1192 1286 ...
# $ : num [1:10009] 1020 1796 1286 712 1761 ...
# $ : num [1:10012] 1032 1286 1761 1017 1672 ...
因此,将其读入全长字符串并不是内存爆炸的原因,而是将其拆分为每行 10000 多个字段。这是因为每个 的开销更大 character
对象:
### vec-1, nchar-0
object.size("")
# 112 bytes
### vec-5, nchar-0
object.size(c("","","","",""))
# 152 bytes
### vec-5, nchar-10
object.size(c("aaaaaaaaaa","aaaaaaaaaa","aaaaaaaaaa","aaaaaaaaaa","aaaaaaaaaa"))
# 160 bytes
如果我们查看原始数据,我们会看到爆炸:
object.size(aa1[1]) # whole lines at a time, so one line is 10000+ characters
# 89312 bytes
object.size(aa2[[1]]) # vector of 10000+ strings, each between 3-8 characters
# 633160 bytes
不过好在内存中的数字要小得多:
object.size(1)
# 56 bytes
object.size(c(1,2,3,4,5))
# 96 bytes
而且它的扩展性更好。显然,将 R 存储中的数据从 453MiB(拆分,字符串)减少到 57MiB(拆分,数字)就足够了。
在读取这些文件时,您仍然会看到 R 的内存使用量激增。您可以尝试通过在 strsplit
之后立即转换为数字来减少它;老实说,我不知道 R 的垃圾收集器(高级编程语言的常见事物)有多快 return 内存,我也不确定根据 R 的 "global string pool".但是如果你有兴趣,你可以试试这个改编你的功能。
func <- function(path) {
aa1 <- readLines(path)
aa2 <- lapply(aa1, function(st) as.numeric(strsplit(st, "[; ]+")[[1]]))
aa2
}
(我不保证它不会仍然“绽放”你的内存使用,但也许它不那么糟糕。)
然后 for
循环的规范替换(虽然那个循环很好)是
dat <- lapply(files, func)