Preventing column-class inference in fread()

后端 未结 2 1125
挽巷
挽巷 2020-12-10 12:53

Is there a way for fread to mimic the behaviour of read.table whereby the class of the variable is set by the data that is read in.

相关标签:
2条回答
  • 2020-12-10 13:27

    Ok, the customer is abusing CSV format to intentionally write out trailing string rows to an integer column, yet without those rows starting with a comment.char (#).

    Then you somehow expect you can override fread()'s type inference to read those as integer, by using nrow to try to limit it to just see the integer rows. read.csv(..., nrow) will accept this, however fread() always uses all rows for type-inference (not just the ones specified by nrow, skip, header), and even if they start with comment.char (that's a bug).

    1. Sounds like an abuse of CSV. Your comment rows should be prepended with #
    2. Yes, fread() needs a fix/enhance to ignore comment rows for type inference.
    3. For now, you can workaround with fread() by post-processing the data-table read in.
    4. It's arguable whether fread() should be changed to support the behavior you want: using nrows to limit what gets exposed to type-inference. It might fix your (pretty unique) case and break some others.

    I don't see why you (EDIT: the customer) can't write your comments to a separate .txt/README/data-dictionary file to accompany the .csv. The practice of using a separate data-dictionary file is pretty well-established. I've never seen someone do this to a CSV file. At least move the comments to the header, not a footer.

    0 讨论(0)
  • 2020-12-10 13:38

    Option 1: Using a system command

    fread() allows the use of a system command in its first argument. We can use it to remove the quotes in the first column of the file.

    indt <- data.table::fread("cat test.csv | tr -d '\"'", nrows = 100)
    str(indt)
    # Classes ‘data.table’ and 'data.frame':    100 obs. of  2 variables:
    #  $ x: int  1 2 3 4 5 6 7 8 9 10 ...
    #  $ y: int  1 2 3 4 5 6 7 8 9 10 ...
    #  - attr(*, ".internal.selfref")=<externalptr> 
    

    The system command cat test.csv | tr -d '\"' explained:

    • cat test.csv reads the file to standard output
    • | is a pipe, using the output of the previous command as input for the next command
    • tr -d '\"' deletes (-d) all occurrences of double quotes ('\"') from the current input

    Option 2: Coercion after reading

    Since option 1 doesn't seem to be working on your system, another possibility is to read the file as you did, but convert the x column with type.convert().

    library(data.table)
    indt2 <- fread("test.csv", nrows = 100)[, x := type.convert(x)]
    str(indt2)
    # Classes ‘data.table’ and 'data.frame':    100 obs. of  2 variables:
    #  $ x: int  1 2 3 4 5 6 7 8 9 10 ...
    #  $ y: int  1 2 3 4 5 6 7 8 9 10 ...
    #  - attr(*, ".internal.selfref")=<externalptr> 
    

    Side note: I usually prefer to use type.convert() over as.numeric() to avoid the "NAs introduced by coercion" warning triggered in some cases. For example,

    x <- c("1", "4", "NA", "6")
    as.numeric(x)
    # [1]  1  4 NA  6
    # Warning message:
    # NAs introduced by coercion 
    type.convert(x)
    # [1]  1  4 NA  6
    

    But of course you can use as.numeric() as well.


    Note: This answer assumes data.table dev v1.9.5

    0 讨论(0)
提交回复
热议问题