binarios - fwrite en c
Leyendo en trozos a la vez usando fread en el paquete de datos. (3)
Debe utilizar el paquete LaF
. Esto introduce una especie de puntero en sus datos, evitando así el comportamiento molesto, para datos muy grandes, de leer todo el archivo. En cuanto a fread()
en data.table
pckg necesita saber el número total de filas, lo que requiere tiempo para los datos de GB. Usando el puntero en LaF
, puede ir a cada línea que desee; y lea en trozos de datos en los que puede aplicar su función, luego continúe con el siguiente trozo de datos. En mi pequeña PC corrí a través de un archivo csv de 25 GB en pasos de 10e6 líneas y extraje un total de ~ 5e6 observaciones necesarias: cada porción de 10e6 tomó 30 segundos.
ACTUALIZAR:
library(''LaF'')
huge_file <- ''C:/datasets/protein.links.v9.1.txt''
#First detect a data model for your file:
model <- detect_dm_csv(huge_file, sep=" ", header=TRUE)
Luego crea una conexión a tu archivo usando el modelo:
df.laf <- laf_open(model)
Una vez hecho esto, puede hacer todo tipo de cosas sin necesidad de saber el tamaño del archivo como en data.table pckgs. Por ejemplo, coloque el puntero en la línea no 100e6 y lea 1e6 líneas de datos desde aquí:
goto(df.laf, 100e6)
data <- next_block(df.laf,nrows=1e6)
Ahora los data
contienen 1e6 líneas de su archivo CSV (comenzando desde la línea 100e6).
Puede leer fragmentos de datos (tamaño según su memoria) y solo conservar lo que necesita. por ejemplo, el huge_file
en mi ejemplo apunta a un archivo con todas las secuencias de proteínas conocidas y tiene un tamaño de> 27 GB, huge_file
grande para mi PC. Para obtener solo la secuencia humana, filtré utilizando el id de organismo que es 9606 para humanos, y esto debería aparecer al comienzo de la variable protein1
. Una forma sucia es ponerlo en un bucle for simple y solo leer un fragmento de datos a la vez:
library(''dplyr'')
library(''stringr'')
res <- df.laf[1,][0,]
for(i in 1:10){
raw <-
next_block(df.laf,nrows=100e6) %>%
filter(str_detect(protein1,"^9606//."))
res <- rbind(res, raw)
}
Ahora res
contiene los datos humanos filtrados. Pero mejor - y para operaciones más complejas, por ejemplo, el cálculo de datos sobre la marcha - la función process_blocks()
toma como argumento una función. Por lo tanto, en la función que hace lo que quiera en cada dato. Lea la documentación.
Estoy tratando de ingresar un archivo grande delimitado por tabulaciones (alrededor de 2GB) usando la función fread
en el paquete data.table
. Sin embargo, debido a que es tan grande, no cabe completamente en la memoria. Intenté ingresarlo en trozos usando los argumentos skip
y nrow
como:
chunk.size = 1e6
done = FALSE
chunk = 1
while(!done)
{
temp = fread("myfile.txt",skip=(chunk-1)*chunk.size,nrow=chunk.size-1)
#do something to temp
chunk = chunk + 1
if(nrow(temp)<2) done = TRUE
}
En el caso anterior, estoy leyendo en un millón de filas a la vez, realizando un cálculo en ellas y luego obteniendo el siguiente millón, etc. El problema con este código es que después de que se recupera cada fragmento, fread
debe comenzar a escanear. el archivo desde el principio, ya que después de cada iteración de bucle, el skip
aumenta en un millón. Como resultado, después de cada fragmento, el fread
tarda más y más en llegar al siguiente fragmento, lo que lo hace muy ineficiente.
¿Hay una manera de decirle al fread
que haga una pausa cada 1 millón de líneas y luego continúe leyendo a partir de ese momento sin tener que reiniciar desde el principio? ¿Alguna solución, o debería ser una nueva solicitud de características?
Puede utilizar read_''s read_*_chunked
para leer los datos y, por ejemplo, filtrarlo a trozos. Vea read_*_chunked y here para un ejemplo:
# Cars with 3 gears
f <- function(x, pos) subset(x, gear == 3)
read_csv_chunked(readr_example("mtcars.csv"), DataFrameCallback$new(f), chunk_size = 5)
Una opción relacionada es el paquete chunked . Aquí hay un ejemplo con un archivo de texto de 3.5 GB:
library(chunked)
library(tidyverse)
# I want to look at the daily page views of Wikipedia articles
# before 2015... I can get zipped log files
# from here: hhttps://dumps.wikimedia.org/other/pagecounts-ez/merged/2012/2012-12/
# I get bz file, unzip to get this:
my_file <- ''pagecounts-2012-12-14/pagecounts-2012-12-14''
# How big is my file?
print(paste(round(file.info(my_file)$size / 2^30,3), ''gigabytes''))
# [1] "3.493 gigabytes" too big to open in Notepad++ !
# But can read with 010 Editor
# look at the top of the file
readLines(my_file, n = 100)
# to find where the content starts, vary the skip value,
read.table(my_file, nrows = 10, skip = 25)
Aquí es donde empezamos a trabajar en partes del archivo, podemos usar la mayoría de los verbos de dplyr de la forma habitual:
# Let the chunked pkg work its magic! We only want the lines containing
# "Gun_control". The main challenge here was identifying the column
# header
df <-
read_chunkwise(my_file,
chunk_size=5000,
skip = 30,
format = "table",
header = TRUE) %>%
filter(stringr::str_detect(De.mw.De.5.J3M1O1, "Gun_control"))
# this line does the evaluation,
# and takes a few moments...
system.time(out <- collect(df))
Y aquí podemos trabajar en la salida como siempre, ya que es mucho más pequeño que el archivo de entrada:
# clean up the output to separate into cols,
# and get the number of page views as a numeric
out_df <-
out %>%
separate(De.mw.De.5.J3M1O1,
into = str_glue("V{1:4}"),
sep = " ") %>%
mutate(V3 = as.numeric(V3))
head(out_df)
V1 V2 V3
1 en.z Gun_control 7961
2 en.z Category:Gun_control_advocacy_groups_in_the_United_States 1396
3 en.z Gun_control_policy_of_the_Clinton_Administration 223
4 en.z Category:Gun_control_advocates 80
5 en.z Gun_control_in_the_United_Kingdom 68
6 en.z Gun_control_in_america 59
V4
1 A34B55C32D38E32F32G32H20I22J9K12L10M9N15O34P38Q37R83S197T1207U1643V1523W1528X1319
2 B1C5D2E1F3H3J1O1P3Q9R9S23T197U327V245W271X295
3 A3B2C4D2E3F3G1J3K1L1O3P2Q2R4S2T24U39V41W43X40
4 D2H1M1S4T8U22V10W18X14
5 B1C1S1T11U12V13W16X13
6 B1H1M1N2P1S1T6U5V17W12X12
#--------------------