You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Given the speed of fwrite, it can be used in conjunction with fread as an alternative to do.call(paste, ...) to flatten multiple columns into a character vector. It would be nice to be able to capture the output of fwrite directly as a character vector.
It is much faster than some of the other idiomatic approaches that are often considered.
Here's the behavior I'm hoping to be able to replicate:
@MichaelChirico I had forgotten to mention in my original post that I tried with capture.output and also gave up, and then tried with R.utils::captureOutput which performed much better, but still slower than fpaste.
This sounds impressive. I do not understand how writing to file is faster than manipulating it in RAM. What is happening? Why is capture.output discussed?
You can still manipulate it in RAM with fwrite and fread if you use tempfile having tempdir set to ramdisk (search NEWS.md for "ramdisk"). I assume that capture.output is discussed because fwrite can print to console.
@ColeMiller1 My initial thought was to just use fwrite with file = "" and use fread on that. But that just prints the output. capture.output could be used to convert that into a string, but it's really slow.
Using the relevant parts of R.utils::captureOutput I tried:
This performs well. It's at least as fast if not faster than do.call(stringi::stri_join, c(d2[cols], sep = "-")) but not as fast as writing to file and re-reading it.
My use case for sep="" is to mimic paste0("id",1:1e9).
Just this paste0 command alone takes 40 minutes to evaluate. Most probably due to R's string global cache.
If I could do fwrite(data.frame(a="id",b=1:1e9), sep="") then I can potentially save 40 minutes. I actually need to write it to csv rather than console, so populating R's global cache just to dump that to csv is really sub-efficient.
Just now seeing this today, but I think there certainly is an opportunity to improve vectorized string concatenation performance with a fpaste() function.
Back in 2018, I had a use case where this was the bottleneck in a data pipeline. I posted to stack overflow, https://stackoverflow.com/questions/48233309/fast-concatenation-of-data-table-columns-into-one-string-column , and in the course of investigating, I was suprised to find the same thing others described here - it was faster to fwrite the dataset to disk, use sed to perform the concatenation, and fread to pull back in to memory.
One of the answers by Matrin Modrák proposed repurposing some of the code from /src/fwrite.c that ran 8x faster the previous best - an optimized sprintf call. From there, I put that code into a single function package - fastConcat - that we still use in production at my employer. https://github.com/msummersgill/fastConcat
fastConcat::concat() only supports single digit integers (the use case was highly specific), but it is a working proof of concept that the code in /src/fwrite.c could probably be re-purposed to create a data.table::fpaste() with performance at least an order of magnitude better than base::paste().
Activity
MichaelChirico commentedon Jun 24, 2020
for the record I tried using
capture.outputinstead of disk I/O and it's way, way slower (I gave up running the benchmark)mrdwab commentedon Jun 24, 2020
@MichaelChirico I had forgotten to mention in my original post that I tried with
capture.outputand also gave up, and then tried withR.utils::captureOutputwhich performed much better, but still slower thanfpaste.ColeMiller1 commentedon Jun 24, 2020
This sounds impressive. I do not understand how writing to file is faster than manipulating it in RAM. What is happening? Why is
capture.outputdiscussed?jangorecki commentedon Jun 24, 2020
You can still manipulate it in RAM with fwrite and fread if you use tempfile having tempdir set to ramdisk (search NEWS.md for "ramdisk"). I assume that
capture.outputis discussed becausefwritecan print to console.mrdwab commentedon Jun 24, 2020
@ColeMiller1 My initial thought was to just use
fwritewithfile = ""and usefreadon that. But that just prints the output.capture.outputcould be used to convert that into a string, but it's really slow.Using the relevant parts of
R.utils::captureOutputI tried:This performs well. It's at least as fast if not faster than
do.call(stringi::stri_join, c(d2[cols], sep = "-"))but not as fast as writing to file and re-reading it.jangorecki commentedon Nov 18, 2020
This will not work for a
sep=""becausefwriteexpect non-zero char separator.[-]fwrite output as a character vector[/-][+]fpaste: fwrite output as a character vector[/+]jangorecki commentedon Nov 21, 2020
My use case for
sep=""is to mimicpaste0("id",1:1e9).Just this
paste0command alone takes 40 minutes to evaluate. Most probably due to R's string global cache.If I could do
fwrite(data.frame(a="id",b=1:1e9), sep="")then I can potentially save 40 minutes. I actually need to write it to csv rather than console, so populating R's global cache just to dump that to csv is really sub-efficient.msummersgill commentedon Aug 6, 2021
Just now seeing this today, but I think there certainly is an opportunity to improve vectorized string concatenation performance with a
fpaste()function.Back in 2018, I had a use case where this was the bottleneck in a data pipeline. I posted to stack overflow, https://stackoverflow.com/questions/48233309/fast-concatenation-of-data-table-columns-into-one-string-column , and in the course of investigating, I was suprised to find the same thing others described here - it was faster to
fwritethe dataset to disk, usesedto perform the concatenation, andfreadto pull back in to memory.One of the answers by Matrin Modrák proposed repurposing some of the code from /src/fwrite.c that ran 8x faster the previous best - an optimized
sprintfcall. From there, I put that code into a single function package - fastConcat - that we still use in production at my employer. https://github.com/msummersgill/fastConcatfastConcat::concat()only supports single digit integers (the use case was highly specific), but it is a working proof of concept that the code in /src/fwrite.c could probably be re-purposed to create adata.table::fpaste()with performance at least an order of magnitude better thanbase::paste().