Проблемы с памятью при использовании bigmemory для загрузки большого набора данных в R
У меня есть большой текстовый файл (>10 миллионов строк, > 1 ГБ), который я хочу обрабатывать по одной строке за раз, чтобы избежать загрузки всего объекта в память. После обработки каждой строки я хочу сохранить некоторые переменные в big.matrix
объект. Вот упрощенный пример:
library(bigmemory)
library(pryr)
con <- file('x.csv', open = "r")
x <- big.matrix(nrow = 5, ncol = 1, type = 'integer')
for (i in 1:5){
print(c(address(x), refs(x)))
y <- readLines(con, n = 1, warn = FALSE)
x[i] <- 2L*as.integer(y)
}
close(con)
где x.csv
содержит
4
18
2
14
16
Следуя совету здесь http://adv-r.had.co.nz/memory.html Я напечатал адрес памяти моего big.matrix
объект, и он, кажется, меняется с каждой итерацией цикла:
[1] "0x101e854d8" "2"
[1] "0x101d8f750" "2"
[1] "0x102380d80" "2"
[1] "0x105a8ff20" "2"
[1] "0x105ae0d88" "2"
Можно
big.matrix
объекты будут изменены на месте?Есть ли лучший способ загрузить, обработать и сохранить эти данные? Текущий метод медленный!
1 ответ
- Есть ли лучший способ загрузить, обработать и сохранить эти данные? Текущий метод медленный!
Самая медленная часть вашего метода, кажется, выполняет вызов для чтения каждой строки в отдельности. Мы можем "разбивать" данные на части или читать по несколько строк за раз, чтобы не превысить предел памяти и, возможно, ускорить процесс.
Вот план:
- Выясните, сколько строк у нас в файле
- Читайте в части этих строк
- Выполните некоторые операции на этом чанке
Вставьте этот кусок обратно в новый файл, чтобы сохранить на потом
library(readr) # Make a file x <- data.frame(matrix(rnorm(10000),100000,10)) write_csv(x,"./test_set2.csv") # Create a function to read a variable in file and double it calcDouble <- function(calc.file,outputFile = "./outPut_File.csv", read.size=500000,variable="X1"){ # Set up variables num.lines <- 0 lines.per <- NULL var.top <- NULL i=0L # Gather column names and position of objective column connection.names <- file(calc.file,open="r+") data.names <- read.table(connection.names,sep=",",header=TRUE,nrows=1) close(connection.names) col.name <- which(colnames(data.names)==variable) #Find length of file by line connection.len <- file(calc.file,open="r+") while((linesread <- length(readLines(connection.len,read.size)))>0){ lines.per[i] <- linesread num.lines <- num.lines + linesread i=i+1L } close(connection.len) # Make connection for doubling function # Loop through file and double the set variables connection.double <- file(calc.file,open="r+") for (j in 1:length(lines.per)){ # if stops read.table from breaking # Read in a chunk of the file if (j == 1) { data <- read.table(connection.double,sep=",",header=FALSE,skip=1,nrows=lines.per[j],comment.char="") } else { data <- read.table(connection.double,sep=",",header=FALSE,nrows=lines.per[j],comment.char="") } # Grab the columns we need and double them double <- data[,I(col.name)] * 2 if (j != 1) { write_csv(data.frame(double),outputFile,append = TRUE) } else { write_csv(data.frame(double),outputFile) } message(paste0("Reading from Chunk: ",j, " of ",length(lines.per))) } close(connection.double) } calcDouble("./test_set2.csv",read.size = 50000, variable = "X1")
Таким образом, мы возвращаем файл.csv с манипулированными данными. Ты можешь измениться double <- data[,I(col.name)] * 2
к тому, что вам нужно сделать с каждым куском.