Fast and friendly file finagler
fread.Rd
Similar to read.csv()
and read.delim()
but faster and more convenient. All controls such as sep
, colClasses
and nrows
are automatically detected.
bit64::integer64
, IDate
, and POSIXct
types are also detected and read directly without needing to read as character before converting.
fread
is for regular delimited files; i.e., where every row has the same number of columns. In future, secondary separator (sep2
) may be specified within each column. Such columns will be read as type list
where each cell is itself a vector.
Usage
fread(input, file, text, cmd, sep="auto", sep2="auto", dec="auto", quote="\"",
nrows=Inf, header="auto",
na.strings=getOption("datatable.na.strings","NA"), # due to change to ""; see NEWS
stringsAsFactors=FALSE, verbose=getOption("datatable.verbose", FALSE),
skip="__auto__", select=NULL, drop=NULL, colClasses=NULL,
integer64=getOption("datatable.integer64", "integer64"),
col.names,
check.names=FALSE, encoding="unknown",
strip.white=TRUE, fill=FALSE, blank.lines.skip=FALSE,
key=NULL, index=NULL,
showProgress=getOption("datatable.showProgress", interactive()),
data.table=getOption("datatable.fread.datatable", TRUE),
nThread=getDTthreads(verbose),
logical01=getOption("datatable.logical01", FALSE), # due to change to TRUE; see NEWS
keepLeadingZeros = getOption("datatable.keepLeadingZeros", FALSE),
yaml=FALSE, autostart=NA, tmpdir=tempdir(), tz="UTC"
)
Arguments
- input
A single character string. The value is inspected and deferred to either
file=
(if no \n present),text=
(if at least one \n is present) orcmd=
(if no \n is present, at least one space is present, and it isn't a file name). Exactly one ofinput=
,file=
,text=
, orcmd=
should be used in the same call.- file
File name in working directory, path to file (passed through
path.expand
for convenience), or a URL starting http://, file://, etc. Compressed files with extension.gz
and.bz2
are supported if theR.utils
package is installed.- text
The input data itself as a character vector of one or more lines, for example as returned by
readLines()
.- cmd
A shell command that pre-processes the file; e.g.
fread(cmd=paste("grep",word,"filename"))
. See Details.- sep
The separator between columns. Defaults to the character in the set
[,\t |;:]
that separates the sample of rows into the most number of lines with the same number of fields. UseNULL
or""
to specify no separator; i.e. each line a single character column likebase::readLines
does.- sep2
The separator within columns. A
list
column will be returned where each cell is a vector of values. This is much faster using less working memory thanstrsplit
afterwards or similar techniques. For each columnsep2
can be different and is the first character in the same set above [,\t |;
], other thansep
, that exists inside each field outside quoted regions in the sample. NB:sep2
is not yet implemented.- nrows
The maximum number of rows to read. Unlike
read.table
, you do not need to set this to an estimate of the number of rows in the file for better speed because that is already automatically determined byfread
almost instantly using the large sample of lines.nrows=0
returns the column names and typed empty columns determined by the large sample; useful for a dry run of a large file or to quickly check format consistency of a set of files before starting to read any of them.- header
Does the first data line contain column names? Defaults according to whether every non-empty field on the first data line is type character. If so, or TRUE is supplied, any empty column names are given a default name.
- na.strings
A character vector of strings which are to be interpreted as
NA
values. By default,",,"
for columns of all types, including typecharacter
is read asNA
for consistency.,"",
is unambiguous and read as an empty string. To read,NA,
asNA
, setna.strings="NA"
. To read,,
as blank string""
, setna.strings=NULL
. When they occur in the file, the strings inna.strings
should not appear quoted since that is how the string literal,"NA",
is distinguished from,NA,
, for example, whenna.strings="NA"
.- stringsAsFactors
Convert all or some character columns to factors? Acceptable inputs are
TRUE
,FALSE
, or a decimal value between 0.0 and 1.0. ForstringsAsFactors = FALSE
, all string columns are stored ascharacter
vs. all stored asfactor
whenTRUE
. WhenstringsAsFactors = p
for0 <= p <= 1
, string columnscol
are stored asfactor
ifuniqueN(col)/nrow < p
.- verbose
Be chatty and report timings?
- skip
If 0 (default) start on the first line and from there finds the first row with a consistent number of columns. This automatically avoids irregular header information before the column names row.
skip>0
means ignore the firstskip
rows manually.skip="string"
searches for"string"
in the file (e.g. a substring of the column names row) and starts on that line (inspired by read.xls in package gdata).- select
A vector of column names or numbers to keep, drop the rest.
select
may specify types too in the same way ascolClasses
; i.e., a vector ofcolname=type
pairs, or alist
oftype=col(s)
pairs. In all forms ofselect
, the order that the columns are specified determines the order of the columns in the result.- drop
Vector of column names or numbers to drop, keep the rest.
- colClasses
As in
utils::read.csv
; i.e., an unnamed vector of types corresponding to the columns in the file, or a named vector specifying types for a subset of the columns by name. The default,NULL
means types are inferred from the data in the file. Further,data.table
supports a namedlist
of vectors of column names or numbers where thelist
names are the class names; see examples. Thelist
form makes it easier to set a batch of columns to be a particular class. When column numbers are used in thelist
form, they refer to the column number in the file not the column number afterselect
ordrop
has been applied. If type coercion results in an error, introducesNA
s, or would result in loss of accuracy, the coercion attempt is aborted for that column with warning and the column's type is left unchanged. If you really desire data loss (e.g. reading3.14
asinteger
) you have to truncate such columns afterwards yourself explicitly so that this is clear to future readers of your code.- integer64
"integer64" (default) reads columns detected as containing integers larger than 2^31 as type
bit64::integer64
. Alternatively,"double"|"numeric"
reads asutils::read.csv
does; i.e., possibly with loss of precision and if so silently. Or, "character".- dec
The decimal separator as in
utils::read.csv
. When"auto"
(the default), an attempt is made to decide whether"."
or","
is more suitable for this input. See details.- col.names
A vector of optional names for the variables (columns). The default is to use the header column if present or detected, or if not "V" followed by the column number. This is applied after
check.names
and beforekey
andindex
.- check.names
default is
FALSE
. IfTRUE
then the names of the variables in thedata.table
are checked to ensure that they are syntactically valid variable names. If necessary they are adjusted (bymake.names
) so that they are, and also to ensure that there are no duplicates.- encoding
default is
"unknown"
. Other possible options are"UTF-8"
and"Latin-1"
. Note: it is not used to re-encode the input, rather enables handling of encoded strings in their native encoding.- quote
By default (
"\""
), if a field starts with a double quote,fread
handles embedded quotes robustly as explained underDetails
. If it fails, then another attempt is made to read the field as is, i.e., as if quotes are disabled. By settingquote=""
, the field is always read as if quotes are disabled. It is not expected to ever need to pass anything other than \"\" to quote; i.e., to turn it off.- strip.white
Logical, default
TRUE
, in which case leading and trailing whitespace is stripped from unquoted"character"
fields."numeric"
fields are always stripped of leading and trailing whitespace.- fill
logical or integer (default is
FALSE
). IfTRUE
then in case the rows have unequal length, number of columns is estimated and blank fields are implicitly filled. If an integer is provided it is used as an upper bound for the number of columns. Iffill=Inf
then the whole file is read for detecting the number of columns.- blank.lines.skip
logical
, default isFALSE
. IfTRUE
blank lines in the input are ignored.- key
Character vector of one or more column names which is passed to
setkey
. Only valid when argumentdata.table=TRUE
. Where applicable, this should refer to column names given incol.names
.- index
Character vector or list of character vectors of one or more column names which is passed to
setindexv
. As withkey
, comma-separated notation likeindex="x,y,z"
is accepted for convenience. Only valid when argumentdata.table=TRUE
. Where applicable, this should refer to column names given incol.names
.- showProgress
TRUE
displays progress on the console if the ETA is greater than 3 seconds. It is produced in fread's C code where the very nice (but R level) txtProgressBar and tkProgressBar are not easily available.- data.table
TRUE returns a
data.table
. FALSE returns adata.frame
. The default for this argument can be changed withoptions(datatable.fread.datatable=FALSE)
.- nThread
The number of threads to use. Experiment to see what works best for your data on your hardware.
- logical01
If TRUE a column containing only 0s and 1s will be read as logical, otherwise as integer.
- keepLeadingZeros
If TRUE a column containing numeric data with leading zeros will be read as character, otherwise leading zeros will be removed and converted to numeric.
- yaml
If
TRUE
,fread
will attempt to parse (usingyaml.load
) the top of the input as YAML, and further to glean parameters relevant to improving the performance offread
on the data itself. The entire YAML section is returned as parsed into alist
in theyaml_metadata
attribute. SeeDetails
.- autostart
Deprecated and ignored with warning. Please use
skip
instead.- tmpdir
Directory to use as the
tmpdir
argument for anytempfile
calls, e.g. when the input is a URL or a shell command. The default istempdir()
which can be controlled by settingTMPDIR
before starting the R session; seebase::tempdir
.- tz
Relevant to datetime values which have no Z or UTC-offset at the end, i.e. unmarked datetime, as written by
utils::write.csv
. The defaulttz="UTC"
reads unmarked datetime as UTC POSIXct efficiently.tz=""
reads unmarked datetime as type character (slowly) so thatas.POSIXct
can interpret (slowly) the character datetimes in local timezone; e.g. by using"POSIXct"
incolClasses=
. Note thatfwrite()
by default writes datetime in UTC including the final Z and thereforefwrite
's output will be read byfread
consistently and quickly without needing to usetz=
orcolClasses=
. If theTZ
environment variable is set to"UTC"
(or""
on non-Windows where unset vs `""` is significant) then the R session's timezone is already UTC andtz=""
will result in unmarked datetimes being read as UTC POSIXct. For more information, please see the news items from v1.13.0 and v1.14.0.
Details
A sample of 10,000 rows is used for a very good estimate of column types. 100 contiguous rows are read from 100 equally spaced points throughout the file including the beginning, middle and the very end. This results in a better guess when a column changes type later in the file (e.g. blank at the beginning/only populated near the end, or 001 at the start but 0A0 later on). This very good type guess enables a single allocation of the correct type up front once for speed, memory efficiency and convenience of avoiding the need to set colClasses
after an error. Even though the sample is large and jumping over the file, it is almost instant regardless of the size of the file because a lazy on-demand memory map is used. If a jump lands inside a quoted field containing newlines, each newline is tested until 5 lines are found following it with the expected number of fields. The lowest type for each column is chosen from the ordered list: logical
, integer
, integer64
, double
, character
. Rarely, the file may contain data of a higher type in rows outside the sample (referred to as an out-of-sample type exception). In this event fread
will automatically reread just those columns from the beginning so that you don't have the inconvenience of having to set colClasses
yourself; particularly helpful if you have a lot of columns. Such columns must be read from the beginning to correctly distinguish "00" from "000" when those have both been interpreted as integer 0 due to the sample but 00A occurs out of sample. Set verbose=TRUE
to see a detailed report of the logic deployed to read your file.
There is no line length limit, not even a very large one. Since we are encouraging list
columns (i.e. sep2
) this has the potential to encourage longer line lengths. So the approach of scanning each line into a buffer first and then rescanning that buffer is not used. There are no buffers used in fread
's C code at all. The field width limit is limited by R itself: the maximum width of a character string (currently 2^31-1 bytes, 2GB).
The filename extension (such as .csv) is irrelevant for "auto" sep
and sep2
. Separator detection is entirely driven by the file contents. This can be useful when loading a set of different files which may not be named consistently, or may not have the extension .csv despite being csv. Some datasets have been collected over many years, one file per day for example. Sometimes the file name format has changed at some point in the past or even the format of the file itself. So the idea is that you can loop fread
through a set of files and as long as each file is regular and delimited, fread
can read them all. Whether they all stack is another matter but at least each one is read quickly without you needing to vary colClasses
in read.table
or read.csv
.
If an empty line is encountered then reading stops there with warning if any text exists after the empty line such as a footer. The first line of any text discarded is included in the warning message. Unless, it is single-column input. In that case blank lines are significant (even at the very end) and represent NA in the single column. So that fread(fwrite(DT))==DT
. This default behaviour can be controlled using blank.lines.skip=TRUE|FALSE
.
Line endings: All known line endings are detected automatically: \n
(*NIX including Mac), \r\n
(Windows CRLF), \r
(old Mac) and \n\r
(just in case). There is no need to convert input files first. fread
running on any architecture will read a file from any architecture. Both \r
and \n
may be embedded in character strings (including column names) provided the field is quoted.
Decimal separator: dec
is used to parse numeric fields as the separator between integral and fractional parts. When dec='auto'
, during column type detection, when a field is a candidate for being numeric (i.e., parsing as lower types has already failed), dec='.'
is tried, and, if it fails to create a numeric field, dec=','
is tried. At the end of the sample lines, if more were successfully parsed with dec=','
, dec
is set to ','
; otherwise, dec
is set to '.'
.
Automatic detection of sep
occurs prior to column type detection -- as such, it is possible that sep
has been inferred to be ','
, in which case dec
is set to '.'
.
Quotes:
When quote
is a single character,
Spaces and other whitespace (other than
sep
and\n
) may appear in unquoted character fields, e.g.,...,2,Joe Bloggs,3.14,...
.When
character
columns are quoted, they must start and end with that quoting character immediately followed bysep
or\n
, e.g.,...,2,"Joe Bloggs",3.14,...
.In essence quoting character fields are required only if
sep
or\n
appears in the string value. Quoting may be used to signify that numeric data should be read as text. Unescaped quotes may be present in a quoted field, e.g.,...,2,"Joe, "Bloggs"",3.14,...
, as well as escaped quotes, e.g.,...,2,"Joe \",Bloggs\"",3.14,...
.If an embedded quote is followed by the separator inside a quoted field, the embedded quotes up to that point in that field must be balanced; e.g.
...,2,"www.blah?x="one",y="two"",3.14,...
.On those fields that do not satisfy these conditions, e.g., fields with unbalanced quotes,
fread
re-attempts that field as if it isn't quoted. This is quite useful in reading files that contains fields with unbalanced quotes as well, automatically.
To read fields as is instead, use quote = ""
.
CSVY Support:
Currently, the yaml
setting is somewhat inflexible with respect to incorporating metadata to facilitate file reading. Information on column classes should be stored at the top level under the heading schema
and subheading fields
; those with both a type
and a name
sub-heading will be merged into colClasses
. Other supported elements are as follows:
sep
(or aliasdelimiter
)header
quote
(or aliasesquoteChar
,quote_char
)dec
(or aliasdecimal
)na.strings
File Download:
When input
begins with http://, https://, ftp://, ftps://, or file://, fread
detects this and downloads the target to a temporary file (at tempfile()
) before proceeding to read the file as usual. URLS (ftps:// and https:// as well as ftp:// and http://) paths are downloaded with download.file
and method
set to getOption("download.file.method")
, defaulting to "auto"
; and file:// is downloaded with download.file
with method="internal"
. NB: this implies that for file://, even files found on the current machine will be "downloaded" (i.e., hard-copied) to a temporary file. See download.file
for more details.
Shell commands:
fread
accepts shell commands for convenience. The input command is run and its output written to a file in tmpdir
(tempdir()
by default) to which fread
is applied "as normal". The details are platform dependent -- system
is used on UNIX environments, shell
otherwise; see system
.
References
Background :
https://cran.r-project.org/doc/manuals/R-data.html
https://stackoverflow.com/questions/1727772/quickly-reading-very-large-tables-as-dataframes-in-r
https://stackoverflow.com/questions/9061736/faster-than-scan-with-rcpp
https://stackoverflow.com/questions/415515/how-can-i-read-and-manipulate-csv-file-data-in-c
https://stackoverflow.com/questions/9352887/strategies-for-reading-in-csv-files-in-pieces
https://stackoverflow.com/questions/11782084/reading-in-large-text-files-in-r
https://stackoverflow.com/questions/45972/mmap-vs-reading-blocks
https://stackoverflow.com/questions/258091/when-should-i-use-mmap-for-file-access
https://stackoverflow.com/a/9818473/403310
https://stackoverflow.com/questions/9608950/reading-huge-files-using-memory-mapped-files
finagler = "to get or achieve by guile or manipulation" https://dictionary.reference.com/browse/finagler
On YAML, see https://yaml.org/.
Examples
# Reads text input directly :
fread("A,B\n1,2\n3,4")
#> A B
#> <int> <int>
#> 1: 1 2
#> 2: 3 4
# Reads pasted input directly :
fread("A,B
1,2
3,4
")
#> A B
#> <int> <int>
#> 1: 1 2
#> 2: 3 4
# Finds the first data line automatically :
fread("
This is perhaps a banner line or two or ten.
A,B
1,2
3,4
")
#> A B
#> <int> <int>
#> 1: 1 2
#> 2: 3 4
# Detects whether column names are present automatically :
fread("
1,2
3,4
")
#> V1 V2
#> <int> <int>
#> 1: 1 2
#> 2: 3 4
# Numerical precision :
DT = fread("A\n1.010203040506070809010203040506\n")
# TODO: add numerals=c("allow.loss", "warn.loss", "no.loss") from base::read.table, +"use.Rmpfr"
typeof(DT$A)=="double" # currently "allow.loss" with no option
#> [1] TRUE
DT = fread("A\n1.46761e-313\n") # read as 'numeric'
DT[,sprintf("%.15E",A)] # beyond what double precision can store accurately to 15 digits
#> [1] "1.467610000018072E-313"
# For greater accuracy use colClasses to read as character, then package Rmpfr.
# colClasses
data = "A,B,C,D\n1,3,5,7\n2,4,6,8\n"
fread(data, colClasses=c(B="character",C="character",D="character")) # as read.csv
#> A B C D
#> <int> <char> <char> <char>
#> 1: 1 3 5 7
#> 2: 2 4 6 8
fread(data, colClasses=list(character=c("B","C","D"))) # saves typing
#> A B C D
#> <int> <char> <char> <char>
#> 1: 1 3 5 7
#> 2: 2 4 6 8
fread(data, colClasses=list(character=2:4)) # same using column numbers
#> A B C D
#> <int> <char> <char> <char>
#> 1: 1 3 5 7
#> 2: 2 4 6 8
# drop
fread(data, colClasses=c("B"="NULL","C"="NULL")) # as read.csv
#> A D
#> <int> <int>
#> 1: 1 7
#> 2: 2 8
fread(data, colClasses=list(NULL=c("B","C"))) #
#> A D
#> <int> <int>
#> 1: 1 7
#> 2: 2 8
fread(data, drop=c("B","C")) # same but less typing, easier to read
#> A D
#> <int> <int>
#> 1: 1 7
#> 2: 2 8
fread(data, drop=2:3) # same using column numbers
#> A D
#> <int> <int>
#> 1: 1 7
#> 2: 2 8
# select
# (in read.csv you need to work out which to drop)
fread(data, select=c("A","D")) # less typing, easier to read
#> A D
#> <int> <int>
#> 1: 1 7
#> 2: 2 8
fread(data, select=c(1,4)) # same using column numbers
#> A D
#> <int> <int>
#> 1: 1 7
#> 2: 2 8
# select and types combined
fread(data, select=c(A="numeric", D="character"))
#> A D
#> <num> <char>
#> 1: 1 7
#> 2: 2 8
fread(data, select=list(numeric="A", character="D"))
#> A D
#> <num> <char>
#> 1: 1 7
#> 2: 2 8
# skip blank lines
fread("a,b\n1,a\n2,b\n\n\n3,c\n", blank.lines.skip=TRUE)
#> a b
#> <int> <char>
#> 1: 1 a
#> 2: 2 b
#> 3: 3 c
# fill
fread("a,b\n1,a\n2\n3,c\n", fill=TRUE)
#> a b
#> <int> <char>
#> 1: 1 a
#> 2: 2
#> 3: 3 c
fread("a,b\n\n1,a\n2\n\n3,c\n\n", fill=TRUE)
#> a b
#> <int> <char>
#> 1: NA
#> 2: 1 a
#> 3: 2
#> 4: NA
#> 5: 3 c
#> 6: NA
# fill with skip blank lines
fread("a,b\n\n1,a\n2\n\n3,c\n\n", fill=TRUE, blank.lines.skip=TRUE)
#> a b
#> <int> <char>
#> 1: 1 a
#> 2: 2
#> 3: 3 c
# check.names usage
fread("a b,a b\n1,2\n")
#> a b a b
#> <int> <int>
#> 1: 1 2
fread("a b,a b\n1,2\n", check.names=TRUE) # no duplicates + syntactically valid names
#> a.b a.b.1
#> <int> <int>
#> 1: 1 2
if (FALSE) {
# Demo speed-up
n = 1e6
DT = data.table( a=sample(1:1000,n,replace=TRUE),
b=sample(1:1000,n,replace=TRUE),
c=rnorm(n),
d=sample(c("foo","bar","baz","qux","quux"),n,replace=TRUE),
e=rnorm(n),
f=sample(1:1000,n,replace=TRUE) )
DT[2,b:=NA_integer_]
DT[4,c:=NA_real_]
DT[3,d:=NA_character_]
DT[5,d:=""]
DT[2,e:=+Inf]
DT[3,e:=-Inf]
write.table(DT,"test.csv",sep=",",row.names=FALSE,quote=FALSE)
cat("File size (MB):", round(file.info("test.csv")$size/1024^2),"\n")
# 50 MB (1e6 rows x 6 columns)
system.time(DF1 <-read.csv("test.csv",stringsAsFactors=FALSE))
# 5.4 sec (first time in fresh R session)
system.time(DF1 <- read.csv("test.csv",stringsAsFactors=FALSE))
# 3.9 sec (immediate repeat is faster, varies)
system.time(DF2 <- read.table("test.csv",header=TRUE,sep=",",quote="",
stringsAsFactors=FALSE,comment.char="",nrows=n,
colClasses=c("integer","integer","numeric",
"character","numeric","integer")))
# 1.2 sec (consistently). All known tricks and known nrows, see references.
system.time(DT <- fread("test.csv"))
# 0.1 sec (faster and friendlier)
identical(DF1, DF2)
all.equal(as.data.table(DF1), DT)
# Scaling up ...
l = vector("list",10)
for (i in 1:10) l[[i]] = DT
DTbig = rbindlist(l)
tables()
write.table(DTbig,"testbig.csv",sep=",",row.names=FALSE,quote=FALSE)
# 500MB csv (10 million rows x 6 columns)
system.time(DF <- read.table("testbig.csv",header=TRUE,sep=",",
quote="",stringsAsFactors=FALSE,comment.char="",nrows=1e7,
colClasses=c("integer","integer","numeric",
"character","numeric","integer")))
# 17.0 sec (varies)
system.time(DT <- fread("testbig.csv"))
# 0.8 sec
all(mapply(all.equal, DF, DT))
# Reads URLs directly :
fread("https://www.stats.ox.ac.uk/pub/datasets/csb/ch11b.dat")
# Decompresses .gz and .bz2 automatically :
fread("https://github.com/Rdatatable/data.table/raw/1.14.0/inst/tests/ch11b.dat.bz2")
fread("https://github.com/Rdatatable/data.table/raw/1.14.0/inst/tests/issue_785_fread.txt.gz")
}