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
I want to avoid column names like Z-normalised temperature (from DB1 before 2018 & from DB2 afterwards), without relying on code comments and in a more native way (e.g. comments can't be saved in a DT.rds file on disk). Hence, request to introduce a metadata function that could retrieve metadata which could have been optionally supplied by the user.
Problem
Pre-modelling, a large amount of time is spent collating and joining data from various sources, transforming some columns to make them just right for the model. Thus, a column may have been transformed multiple number of times, with various edge cases dealt with on a case by case basis.
Current solution
Use descriptive column names or comments. This can easily get unwieldy with column names like Z-normalised temperature (from DB1 before 2018 & from DB2 afterwards). Comments on the other hand, can't be shared as a part of the data.table.
Proposed solution
Introduce a metadata function that contains info stored by the user that optionally describes each column. This would probably also involve a setmetadata function or metadata<- function? Not sure.
Although setmetadata could be extended beyond labels. Another use case I had in mind was the ability to add formulae.
PCPC = PrivCons / Population (PCPC is a newly created column for Private consumption per capita based on existing columns in the original data.table), where description fields like this could be updated if the column names were changed in the associated data.table.
Yes, that's fair, when attached to a column, it will disappear when you transform the data. My use case is mostly long-term storage so it's not a big issue.
You could probably overload := to save and reset the attributes after an operation. Or, keeping the metadata attached to the data.table, rather than the column.
I've used attr and attributes in the past to try and accomplish this, but I've never found a clean way to keep track of an objects attributes.
There are so many times when this would be useful, especially with factor handling. If (for instance) you have a model for 50 states, it would be nice to automatically apply the same levels to a prediction dataset that has one state that doesn't happen to be Alabama.
Another approach is to use an ancillary data.table as a "codebook", optionally that codebook can be an attribute of your main data.table. It's especially useful when you need to label graphs with human-readable labels instead of variable codes. Over the long-run I've found it somewhat easier to keep track of variable definitions, units, and imputations in an entirely separate object. Unfortunately there's never been any widely used standard to annotate statistical datasets.
My own codes often includes things like:
library(data.table)
dt<- data.table(x=1:5)
dt[, `:=`(y=2*x, z=x*x)]
dt.meta<- fread(" code, label, unit, type, description x, weight, kg, numeric, long description y, double weight, kg, numeric, long description with formula z, squared weight, kg, numeric, long description with formula")
Might also want to take a look at how labels/format/etc are implemented in the haven package. they're implemented as vectors with attributes but have some helper functions. These objects seem to behave reasonably well as columns in a data.table.
That's an interesting approach, @mbacou. I've used the dt.meta approach once in the past. The core feature I found missing in that approach was the automatic linking of column names to the metadata. e.g. if the column names were to updated, then dt.meta would also need to be updated, which sort of defeated me.
To add my two cents, I've been using the attr method heavily in a package I have to keep track of things like when the data was last updated and a wrapper around fread/fwrite to read/write the date directly from the filename-basename.
It's a little complicated because I have to remember to copy the attributes after certain transformations/re-assignment.
Not sure what a robust solution would look like but it sounds like a potentially really useful idea
I'm now using R and data.table for the first time. My current workaround for storing metadata about an experiment is to define a method that preserves the attributes on a data.table when I add a new set of experimental observations:
#' add a row to a SafeRankExpt object
#'
#' @param object prior results of experimentation
#' @param row new observations
#'
#' @return updated SafeRankExpt object
rbind.SafeRankExpt <- function(object, row) {
stopifnot(is.SafeRankExpt(object))
ao <- attributes(object)
object = rbind(object, row, use.names = TRUE)
attributes(object) <- ao
stopifnot(is.SafeRankExpt(object))
return(object)
}
BTW I'd happily take suggestions on how to improve my coding style in R. My only prior experience with statistical experimentation was in the early 1990s, using S, to experimentally validate my PRNG package mrandom!
AFAIK most of the design-energy around data.table is to support data analysis (especially of very large datasets) and not data collection in an experimental setting (even in cases where large amounts of experimental data is being collected). I can sort-of understand some reasons why the attributes of a data.table object are not reliably preserved across operations which add rows. In this thread, it seems that contributors are not surprised that attributes of the table, or of its columns, are not reliably preserved. But... to avoid newbies like me picking up the "wrong" package for their task, perhaps the lack of attributes on the returned or modified object could be more clearly disclosed in documentation on functions such as rbindlist which seem (in my very limited) experience with a single release seem to reliably return a data.table without any object-level attributes aside from its class?
And... I believe I do understand why a data-analyst would want to have metadata on their data.table objects which describes their provenance -- and that most (but not all) of the most-relevant provenance metadata would be recording the provenance of individual columns rather than of the data.table as a whole. Digital provenance is a deep subject and I can well understand why it'd be a sinkhole to impose any additional structure on column-level metadata ... but (as some have noted in this thread) it's annoying to develop a bespoke structure for encoding the provenance of a column in its attributes only to discover -- late in the game, during debugging, rather than during code-design -- that the attribute of a column in a data.table is not a reliable place to store information about its provenance.
I'll close this with an explanation of why I think the top-level documentation for data.table should warn experimentalists from using this package to store their experimental data. They should instead be steered toward a matrix, at least until such time as data.table is revved so that it is reliably preserving object-level attributes across all operations -- as is the case AFAIK with data.frame and matrix. Uncharitably, my current understanding of data.table is that it has some poorly-documented delete-on-modify semantics, with respect to all attributes other than class. And a glance through its issues/ suggests to me that the preservation of class attributes on columns is an ongoing difficulty for the project team... which doesn't surprise me in the least because the base semantics of R are very complex with respect to when and how class-coercions "should" occur.
Thanks for reading through this long explanation of my newbie-difficulties with data.table! My impression is that it'll be a great package for my future data analysis, even though it was (in hindsight) a very poor choice for data-collection on stochastic (pseudo-random) experimentation.
Activity
MichaelChirico commentedon Nov 11, 2020
Seems related: #623
raneameya commentedon Nov 11, 2020
Yes, very related. Have thumbs-upped that issue.
Although
setmetadatacould be extended beyond labels. Another use case I had in mind was the ability to add formulae.PCPC=PrivCons/Population(PCPCis a newly created column for Private consumption per capita based on existing columns in the original data.table), where description fields like this could be updated if the column names were changed in the associated data.table.jangorecki commentedon Nov 12, 2020
@gayyaM Not really following how this request extends linked one. Could you please provide example code and expected results?
raneameya commentedon Nov 12, 2020
Sure. Let me know if this is clear. The idea is that
setmetadatacan be extended beyond justDescription&Formula.fcocquemas commentedon Dec 15, 2020
I've been using
attr()for this purpose. In your example I could do:You can even attach the attribute to a column:
Maybe this helps?
KyleHaynes commentedon Dec 15, 2020
I like the idea @fcocquemas, I've done this in the past, but often find it gets lost after basic operations.
Repex
fcocquemas commentedon Dec 15, 2020
Yes, that's fair, when attached to a column, it will disappear when you transform the data. My use case is mostly long-term storage so it's not a big issue.
You could probably overload
:=to save and reset the attributes after an operation. Or, keeping the metadata attached to the data.table, rather than the column.geneorama commentedon Jul 14, 2021
I've used
attrandattributesin the past to try and accomplish this, but I've never found a clean way to keep track of an objects attributes.There are so many times when this would be useful, especially with factor handling. If (for instance) you have a model for 50 states, it would be nice to automatically apply the same levels to a prediction dataset that has one state that doesn't happen to be Alabama.
mbacou commentedon Jul 23, 2021
Another approach is to use an ancillary data.table as a "codebook", optionally that codebook can be an attribute of your main data.table. It's especially useful when you need to label graphs with human-readable labels instead of variable codes. Over the long-run I've found it somewhat easier to keep track of variable definitions, units, and imputations in an entirely separate object. Unfortunately there's never been any widely used standard to annotate statistical datasets.
My own codes often includes things like:
Another way is to use Hmisc
labelledclass, see https://rdrr.io/cran/Hmisc/man/label.html orsjlabelledhttps://cran.r-project.org/web/packages/sjlabelled/vignettes/labelleddata.htmlmyoung3 commentedon Jul 24, 2021
Might also want to take a look at how labels/format/etc are implemented in the haven package. they're implemented as vectors with attributes but have some helper functions. These objects seem to behave reasonably well as columns in a data.table.
raneameya commentedon Jul 28, 2021
That's an interesting approach, @mbacou. I've used the
dt.metaapproach once in the past. The core feature I found missing in that approach was the automatic linking of column names to the metadata. e.g. if the column names were to updated, thendt.metawould also need to be updated, which sort of defeated me.tonyfischetti commentedon Aug 3, 2021
To add my two cents, I've been using the
attrmethod heavily in a package I have to keep track of things like when the data was last updated and a wrapper around fread/fwrite to read/write the date directly from the filename-basename.It's a little complicated because I have to remember to copy the attributes after certain transformations/re-assignment.
Not sure what a robust solution would look like but it sounds like a potentially really useful idea
cthombor commentedon Nov 25, 2022
I'm now using R and data.table for the first time. My current workaround for storing metadata about an experiment is to define a method that preserves the attributes on a data.table when I add a new set of experimental observations:
BTW I'd happily take suggestions on how to improve my coding style in R. My only prior experience with statistical experimentation was in the early 1990s, using S, to experimentally validate my PRNG package mrandom!
cthombor commentedon Nov 26, 2022
AFAIK most of the design-energy around
data.tableis to support data analysis (especially of very large datasets) and not data collection in an experimental setting (even in cases where large amounts of experimental data is being collected). I can sort-of understand some reasons why the attributes of adata.tableobject are not reliably preserved across operations which add rows. In this thread, it seems that contributors are not surprised that attributes of the table, or of its columns, are not reliably preserved. But... to avoid newbies like me picking up the "wrong" package for their task, perhaps the lack of attributes on the returned or modified object could be more clearly disclosed in documentation on functions such as rbindlist which seem (in my very limited) experience with a single release seem to reliably return adata.tablewithout any object-level attributes aside from its class?And... I believe I do understand why a data-analyst would want to have metadata on their
data.tableobjects which describes their provenance -- and that most (but not all) of the most-relevant provenance metadata would be recording the provenance of individual columns rather than of thedata.tableas a whole. Digital provenance is a deep subject and I can well understand why it'd be a sinkhole to impose any additional structure on column-level metadata ... but (as some have noted in this thread) it's annoying to develop a bespoke structure for encoding the provenance of a column in its attributes only to discover -- late in the game, during debugging, rather than during code-design -- that the attribute of a column in adata.tableis not a reliable place to store information about its provenance.I'll close this with an explanation of why I think the top-level documentation for
data.tableshould warn experimentalists from using this package to store their experimental data. They should instead be steered toward a matrix, at least until such time asdata.tableis revved so that it is reliably preserving object-level attributes across all operations -- as is the case AFAIK withdata.frameandmatrix. Uncharitably, my current understanding ofdata.tableis that it has some poorly-documented delete-on-modify semantics, with respect to all attributes other than class. And a glance through its issues/ suggests to me that the preservation of class attributes on columns is an ongoing difficulty for the project team... which doesn't surprise me in the least because the base semantics of R are very complex with respect to when and how class-coercions "should" occur.Thanks for reading through this long explanation of my newbie-difficulties with
data.table! My impression is that it'll be a great package for my future data analysis, even though it was (in hindsight) a very poor choice for data-collection on stochastic (pseudo-random) experimentation.