【问题标题】:fread(): reading table with \r\r\n as newline symbolfread(): 以 \r\r\n 作为换行符读取表格
【发布时间】:2016-01-25 04:37:33
【问题描述】:

我在文本文件中有制表符分隔的表格,其中所有行都以\r\r\n (0x0D 0x0D 0x0A) 结尾。如果我尝试使用fread() 读取此类文件,它会显示

行结尾是\r\r\n。 R 的 download.file() 似乎添加了额外的 \r 在 Windows 上的文本模式下。请以二进制模式重新下载 (mode='wb') 这也可能更快。或者,传递 URL 直接到 fread ,它将以二进制模式下载文件 你。

但我没有下载这些文件,我已经有了它们。

到目前为止,我找到的解决方案首先使用read.table() 读取文件(它将\r\r\n 组合视为单个行尾字符),然后将生成的data.frame 转换为data.table()

mydt <- data.table(read.table(myfilename, header = T, sep = '\t', fill = T))

但我想知道是否有任何方法可以避免慢速 read.table() 并改用快速 fread()

【问题讨论】:

    标签: r performance data.table line-endings


    【解决方案1】:

    我建议使用 GNU 实用程序 tr 删除那些不必要的 \r 字符。例如

    cat("a,b,c\r\r\n1, 2, 3\r\r\n4, 5, 6", file = "test.csv")
    fread("test.csv")
    ## Error in fread("test.csv") : 
    ##  Line ending is \r\r\n. R's download.file() appears to add the extra \r in text mode on Windows. Please download again in binary mode (mode='wb') which might be faster too. Alternatively, pass the URL directly to fread and it will download the file in binary mode for you.
    
    system("tr -d '\r' < test.csv > test2.csv")
    fread("test2.csv")
    ##    a b c
    ## 1: 1 2 3
    ## 2: 4 5 6
    

    如果您使用的是 Windows 并且没有 tr 实用程序,您可以获取它here

    添加:

    我使用 100,000 x 5 样本 cvs 数据集对三种方法进行了一些比较。

    • OPcsv 是“慢”read.table 方法
    • freadScan 是一种丢弃纯 R 中多余的 \r 字符的方法
    • freadtr 直接使用fread() 通过shell 调用GNU tr

    第三种方法是迄今为止最快的。

    # create a 100,000 x 5 sample dataset with lines ending in \r\r\n
    delim <- "\r\r\n"
    sample.txt <- paste0("a, b, c, d, e", delim)
    for (i in 1:100000) {
        sample.txt <- paste0(sample.txt,
                            paste(round(runif(5)*100), collapse = ","),
                            delim)
    }
    cat(sample.txt, file = "sample.csv")
    
    
    # function that translates the extra \r characters in R only
    fread2 <- function(filename) {
        tmp <- scan(file = filename, what = "character", quiet = TRUE)
        # remove empty lines caused by \r
        tmp <- tmp[tmp != ""]
        # paste lines back together together with \n character
        tmp <- paste(tmp, collapse = "\n")
        fread(tmp)
    }
    
    # OP function using read.csv that is slow
    readcsvMethod <- function(myfilename)
        data.table(read.table(myfilename, header = TRUE, sep = ',', fill = TRUE))
    
    require(microbenchmark)
    microbenchmark(OPcsv = readcsvMethod("sample.csv"),
                   freadScan = fread2("sample.csv"),
                   freadtr = fread("tr -d \'\\r\' < sample.csv"),
                   unit = "relative")
    ## Unit: relative
    ##           expr      min       lq     mean   median       uq      max neval
    ##          OPcsv 1.331462 1.336524 1.340037 1.365397 1.366041 1.249223   100
    ##      freadScan 1.532169 1.581195 1.624354 1.673691 1.676596 1.355434   100
    ##        freadtr 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000   100
    

    【讨论】:

    • 感谢您的解决方案,但理想情况下我想找到一种不使用外部实用程序的方法(是的,我在 Windows 下)。
    • 好的,我添加了一个 R-only 方法和比较。请参阅编辑后的答案。
    • 您可以将该系统调用放入fread()。执行fread("cat test.csv | tr -d '\r'"),您可以跳过system() 步骤,类似于this\r 周围的引号可能不是必需的。
    • 感谢@RichardScriven,我刚刚发现fread() 可以直接接受shell 命令。但如果没有 \r 周围的引号,它对我不起作用。
    • @DirtySockSniffer 很好的提示,应该添加它,尽管不仅引号似乎是必要的,您还需要双重转义反斜杠,即fread("cat f.csv | tr - d '\\r'")。这是我让它在 Linux 上工作的唯一方法
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-02
    • 1970-01-01
    • 2016-06-23
    • 2023-04-07
    相关资源
    最近更新 更多