1

I tried to create a DataTable in my Shiny App, with the following code:

    output$table <- renderDataTable({
    dat
    })

This dat object is a data.table. And I got this error:

Warning: Error in dimnames.data.table: data.table inherits from data.frame (from v1.5) but this data.table does not. Has it been created manually (e.g. by using 'structure' rather than 'data.table') or saved to disk using a prior version of data.table? The correct class is c('data.table','data.frame').

Is it because I can't use data.table to create DataTable? What can I do?

Roy C
  • 197
  • 2
  • 12
  • 1
    what is `class(dat)` ? – SymbolixAU Apr 27 '16 at 02:05
  • 2
    and how did you create `dat`? (`DT::datatable` works with `data.table`, I use it often) – SymbolixAU Apr 27 '16 at 02:06
  • 5
    Please attempt to provide a [reproducible example](http://stackoverflow.com/questions/5963269/how-to-make-a-great-r-reproducible-example) – MrFlick Apr 27 '16 at 02:06
  • `class(dat) [1] "grouped_dt" "tbl_dt" "tbl" "tbl_dt" "tbl" "data.table" "data.frame"` – Roy C Apr 27 '16 at 02:06
  • 1
    use, `as.data.table(dat)` (it looks like you've used a `dplyr` chain to manipulate your `dat`. Stick a `%>% ungroup %>% as.data.table` on the end) – SymbolixAU Apr 27 '16 at 02:07
  • I'm building a shiny app based on someone's R functions. So I'm not really sure how the `dat` was created. – Roy C Apr 27 '16 at 02:09
  • Hmm, this appears to be a bug. I'll put in a fix and hopefully it'll be pushed out to the development version soon. For now, I guess `setDT(dat)[]` instead of `dat` should fix your code. – MichaelChirico Apr 27 '16 at 02:12
  • `as.data.table' works! Thank you! @Symbolix – Roy C Apr 27 '16 at 02:14
  • `as.data.table` will make a copy. This is sub-optimal. – MichaelChirico Apr 27 '16 at 02:15
  • @MichaelChirico - will `setDT()` set the correct class? – SymbolixAU Apr 27 '16 at 02:16
  • @Symbolix yes, unless I'm mistaken, all branches of `setDT` use `setattr(x, "class", c("data.table", "data.frame"))` at some point (of course it'd be faster to just run this line on `dat` and skip the overhead, but `setDT` allows the one-liner and should be roughly as fast) – MichaelChirico Apr 27 '16 at 02:17
  • 1
    I don't know. But both `as.data.table` and `setDT` successfully work. – Roy C Apr 27 '16 at 02:18
  • 1
    @Symbolix maybe I am mistaken after all, according to [this issue](https://github.com/Rdatatable/data.table/issues/1078) – MichaelChirico Apr 27 '16 at 21:17

2 Answers2

0

Thanks @DaisyLee for pointing out this issue. It seems you managed to dig up a rather obscure and very old test that was improperly erroring on your code.

I filed an issue about the problem and pushed a fix.

Your code should now run on data.table versions 1.9.8+.

Once you update, you should be able to run the snippet of code you originally tried without error, and without needing to use as.data.table or setDT.

In case you're interested, here's the code that was fixed.

MichaelChirico
  • 33,841
  • 14
  • 113
  • 198
  • Thanks a lot for your work. If you have time, can you please explain more about why i had that error, and what's the difference between using `as.data.table`/`setDT` and this new solution? Thank you again! – Roy C Apr 28 '16 at 17:12
  • If you look at the [diff compared to the old code](https://github.com/Rdatatable/data.table/commit/e9f1d1d908d76402d582fda475f33ea0d11435fb), you'll see there was a test that would cause an error if the `class` of your object was not _identical_ to `c("data.table", "data.frame")`. But through being sent to a `dplyr` function, your object had acquired some other classes, as you mentioned. This is fine, in principal. All that matters for the `dimnames.data.table` function to work is that at least one component of `class` is `data.frame`. The new code reflects this -- `inherits(x, "data.frame")` – MichaelChirico Apr 28 '16 at 17:15
  • Got it. Really appreciate! – Roy C Apr 28 '16 at 17:16
  • Sorry, comment ran long. `inherits(x, "data.frame")` basically checks `"data.frame" %in% class(x)`. The workarounds we suggested, `as.data.table` and `setDT`, were both designed to strip away all the classes of your object and reset it to `c("data.table", "data.frame")` to trick the test into working. The updated code is clearly superior since it doesn't require this workaround. – MichaelChirico Apr 28 '16 at 17:18
0

I would like to submit this reproduceable example of the solution because I experienced exactly the same trouble in attempting to apply data.table functions to a data frame without the class of data.table. It took me considerable effort to figure this out on my own, because the solution on this page is buried inside the comments and those comments did not explain how to reproduce the solution.

As soon as I found out that DF2 was missing the data table class, I immediately used DT2 <- as.data.table(DF2) right after the incidence of transform() and aggregate(). In other words, I simply used the name of the object I originally believed was the data table, on both sides of the formula. For example, if it was named PuTTy_2 <- DF2, then my formula was

PuTTy_2 <- as.data.table(PuTTy_2)

I ran all available package updates, including for data.table, which did not solve my problem. Only when I tried class(DT2) vs. class(DT1) did I find out that DT2 was missing the data table class and had only the data frame class. Therefore, DF2 and DT1 would have been the appropriate abbreviations.

This seemed like the result of running DF2 <- transform(DT1, ... ) and also DF2 <- aggregate( ... , DT1). Although I did not check this directly by troubleshooting my code, I looked up transform() and aggregate() functions, and I confirmed that both those functions work exclusively with data frames.