# What is a good use of the 'comment' function in R?

I just discovered the comment function in R. Example:

x <- matrix(1:12, 3,4)
comment(x) <- c("This is my very important data from experiment #0234",
"Jun 5, 1998")
x
comment(x)


This is the first time I came by this function and was wondering what are common/useful uses of it. Since it is quite difficult to search "R comment" in google and find relevant results, I was hoping someone here might share with his experience.

-
I don't think that this question really needs to be a CW. It is borderline, but it's not too bad. –  csgillespie Nov 9 '10 at 15:22
great information! (the time series package 'xts' has similar this metadata functionality.) –  doug Nov 9 '10 at 17:38

To second @Gavin, Frank Harrell has developed efficient ways to handle annotated data.frame in R in his Hmisc package. For example, the label() and units() functions allow to add dedicated attributes to R objects. I find them very handy when producing summary of data.frame (e.g., with describe()).

Another useful way of using such an extra attribute is to apply a timestamp on a data set. I also add an attribute for things like random seed, fold number (when I use k-kold or LOO cross-validation).

-

One thing I often find myself doing in my R scripts for a particular data analysis task is to include comments in the script about the units of variables in my data frames. I work with environmental data and chemists and ecologists seem to enjoy using a wide range of different units for the same things (mg L$^{-1}$ vs mu eq L$^{-1}$, etc). My colleagues usually store this information in the row immediately below the column names in Excel sheets.

I'd see comment() as a nice way of attaching this information to a data frame for future reference.

-
The standard solution is to include a field for the units of measurement, so that the computer can be programmed to convert all numerical results to common (parameter-specific) units. Burying this crucial information in comments makes implementing this capability difficult or impossible. –  whuber Dec 8 '11 at 7:46
@whuber but R doesn't have such a construct in it's base objects and I don't want to write an entire stack of S4 methods to reproduce data frames that carry around the unit info. Note that comment() is not comments in code. It attaches a specific attribute to the object that can be a vector, one element per column of the data frame containing the units information. It is easy to extract this info so I don't see why implementing anything would be difficult or impossible? –  Gavin Simpson Dec 8 '11 at 17:33
Gavin, I'm suggesting something much simpler. For instance, if sometimes selenium concentrations are recorded in mg/L and other times as meq/L, you can easily select all instances of the latter and multiply the concentration by the appropriate factor to convert it to mg/L. However--this may be the source of your objection--R is definitely not the right place to be maintaining databases and performing processes of this type, even though it's capable of doing so. It is best supplemented by a good database management system for such work. –  whuber Dec 8 '11 at 18:19
Amen to that! comment() et al are handy for ad hoc notes and info, but a proper system is required for larger scale data handling. Interestingly we are having to address this now within the research group and consultancy I work for in regard to our chemistry data and needing to get it into a proper database. –  Gavin Simpson Dec 9 '11 at 1:36

Similar facilities exist in other packages, such as the -notes- command in Stata. We use this to document full details of a variable, e.g. details of assay for a biochemical measurement, or exact wording of the question asked for questionnaire data. This is often too much info for the variable name or label, one or both of which are displayed in the output of every analysis involving the variable and are therefore best kept reasonably short.

-

One of the things I find myself doing a lot is tracking the commands used to generate data and objects, and have found the comment to be a useful tool for this.

The 'matched.call.data' and 'generate.command.string' do the trick. Not perfect, but helpful and a use for 'comment()'. :)

# Comments only accept strings...
# Substituting the escaped quotes ('\"') makes it prettier.
generate.command.string <- function( matched.call.data )
{
command.string <- as.character( bquote( .( list( matched.call.data ) ) ) )
sapply( bquote( .(command.string) ),
USE.NAMES=FALSE,
function( x )
gsub( "\\\"", "\'", as.list( match.call() )\$x )[[2]] )
}

# Some generating function...
generate.matrix <- function( nrows, ncols, data=NA ) {
# Some generated object
mat <- matrix( data= data, nrow= nrows, ncol= ncols )

matched.call.data <- do.call( "call",
c( list( as.character( match.call()[[1]] ) ),
lapply( as.list( match.call() )[-1], eval ) ) )
comment( mat ) <- c( Generated= date(),
Command = generate.command.string( matched.call.data ) )

mat
}

# Generate an object with a missing argument.
emptyMat <- generate.matrix( nrows=2, ncols=2 )
comment( emptyMat )

# Generate without formally stating arguments.
dataMat <- generate.matrix( 2, 2, sample(1:4, 4, replace= TRUE ) )
comment( dataMat )

# And with a longer command.
charMat <- generate.matrix( 3, 3,
c( 'This', 'is', 'a', 'much', 'longer',
'argument', 'section', 'that', 'wraps') )
comment( charMat )

# And with a variable.
myData <- c( 'An', 'expanded', 'command', 'argument')
charMat2 <- generate.matrix( 2, 2, myData )
comment( charMat2 )

# Create a new object from an original command.
Sys.sleep(1)
emptyMat2 <- eval( parse( text= comment( emptyMat )[['Command']] ) )
dataMat2 <- eval( parse( text= comment( emptyMat )[['Command']] ) )

# Check equality of the static matrices.
identical( emptyMat, emptyMat2 )

# The generation dates are different.
all.equal( emptyMat, emptyMat2, check.attributes= FALSE )
comment( emptyMat )['Generated'] <- NA
comment( emptyMat2 )['Generated'] <- NA
identical( emptyMat, emptyMat2 )

# Command argument structure still works too.
str( as.list( match.call(
generate.matrix, parse( text=comment( charMat2 )[[ 'Command' ]] ) ) )[-1] )

-