sheet - Razón detrás de la velocidad del fread en el paquete data.table en R
data.table r tutorial (1)
Estoy sorprendido por la velocidad de la función fread
en data.table
en archivos de datos grandes, pero ¿cómo se las arregla para leer tan rápido? ¿Cuáles son las diferencias de implementación básicas entre fread
y read.csv
?
Supongo que estamos comparando a read.csv
con todos los consejos conocidos aplicados, como establecer colClasses
, colClasses
, etc. read.csv(filename)
sin ningún otro argumento es lento, principalmente porque primero lee todo en la memoria como si fuera un character
y luego intenta forzar eso a integer
o numeric
como un segundo paso.
Entonces, comparando fread
con read.csv(filename, colClasses=, nrows=, etc)
...
Ambos están escritos en C, así que no es eso.
No hay una razón en particular, pero, en esencia, la memoria de fread
asigna el archivo a la memoria y luego recorre el archivo utilizando punteros. Mientras que read.csv
lee el archivo en un búfer a través de una conexión.
Si ejecuta fread
con verbose=TRUE
, le dirá cómo funciona e informará el tiempo empleado en cada uno de los pasos. Por ejemplo, observe que se salta directamente a la mitad y al final del archivo para hacer una mejor estimación de los tipos de columna (aunque en este caso los 5 primeros eran suficientes).
> fread("test.csv",verbose=TRUE)
Input contains no /n. Taking this to be a filename to open
File opened, filesize is 0.486 GB
File is opened and mapped ok
Detected eol as /n only (no /r afterwards), the UNIX and Mac standard.
Using line 30 to detect sep (the last non blank line in the first ''autostart'') ... sep='',''
Found 6 columns
First row with 6 fields occurs on line 1 (either column names or first row of data)
All the fields on line 1 are character fields. Treating as the column names.
Count of eol after first data row: 10000001
Subtracted 1 for last eol and any trailing empty lines, leaving 10000000 data rows
Type codes ( first 5 rows): 113431
Type codes (+ middle 5 rows): 113431
Type codes (+ last 5 rows): 113431
Type codes: 113431 (after applying colClasses and integer64)
Type codes: 113431 (after applying drop or select (if supplied)
Allocating 6 column slots (6 - 0 dropped)
Read 10000000 rows and 6 (of 6) columns from 0.486 GB file in 00:00:44
13.420s ( 31%) Memory map (rerun may be quicker)
0.000s ( 0%) sep and header detection
3.210s ( 7%) Count rows (wc -l)
0.000s ( 0%) Column type detection (first, middle and last 5 rows)
1.310s ( 3%) Allocation of 10000000x6 result (xMB) in RAM
25.580s ( 59%) Reading data
0.000s ( 0%) Allocation for type bumps (if any), including gc time if triggered
0.000s ( 0%) Coercing data already read in type bumps (if any)
0.040s ( 0%) Changing na.strings to NA
43.560s Total
NB: estos tiempos en mi netbook muy lento sin SSD. Tanto el tiempo absoluto como el relativo de cada paso variarán ampliamente de una máquina a otra. Por ejemplo, si vuelve a ejecutar fread
por segunda vez, puede notar que el tiempo para mmap es mucho menor porque su sistema operativo lo ha almacenado en caché desde la ejecución anterior.
$ lscpu
Architecture: x86_64
CPU op-mode(s): 32-bit, 64-bit
Byte Order: Little Endian
CPU(s): 2
On-line CPU(s) list: 0,1
Thread(s) per core: 1
Core(s) per socket: 2
Socket(s): 1
NUMA node(s): 1
Vendor ID: AuthenticAMD
CPU family: 20
Model: 2
Stepping: 0
CPU MHz: 800.000 # i.e. my slow netbook
BogoMIPS: 1995.01
Virtualisation: AMD-V
L1d cache: 32K
L1i cache: 32K
L2 cache: 512K
NUMA node0 CPU(s): 0,1