Is there a general way of passing a data frame with arbitrary columns (integer/factor, numeric, character data) from r to c and back? Pointers to close enough examples would be greatly appreciated.
Thanks.
RT
Is there a general way of passing a data frame with arbitrary columns (integer/factor, numeric, character data) from r to c and back? Pointers to close enough examples would be greatly appreciated.
Thanks.
RT
A data.frame is a list, so along the lines of
#include <Rdefines.h>
SEXP df_fun(SEXP df)
{
int i, len = Rf_length(df);
SEXP result;
PROTECT(result = NEW_CHARACTER(len));
for (i = 0; i < len; ++i)
switch(TYPEOF(VECTOR_ELT(df, i))) {
case INTSXP:
SET_STRING_ELT(result, i, mkChar("integer"));
break;
case REALSXP:
SET_STRING_ELT(result, i, mkChar("numeric"));
break;
default:
SET_STRING_ELT(result, i, mkChar("other"));
break;
};
UNPROTECT(1);
return result;
}
and then after R CMD SHLIB df_fun.c
> dyn.load("df_fun.so")
> df=data.frame(x=1:5, y=letters[1:5], z=pi, stringsAsFactors=FALSE)
> .Call("df_fun", df)
[1] "integer" "other" "numeric"
Use GET_CLASS
, GET_ATTR
and other macros in Rdefines.h (or their equivalent functions, like getAttrib
) to discover other information about the data frame. Note though that a data.frame has an API that can differ from its structure. So for instance the R function row.names
can return something different from the value stored in the row.names attribute. I think most .Call
functions operate on atomic vectors, keeping the manipulation of more complicated objects at the R level.
Here's a link to an example using C++ and package inline by Dirk Eddelbeuttel:
data.frame type is a list with "data.frame" attribute.
This is example of creating data.frame in source of R (src/library/stats/src/model.c):
/* Turn the data "list" into a "data.frame" */
/* so that subsetting methods will work. */
PROTECT(tmp = mkString("data.frame"));
setAttrib(data, R_ClassSymbol, tmp);
UNPROTECT(1);
You can simulate data.frame manually this way:
l <- list(1:5)
attr(l, "class") <- "data.frame"
attr(l, "names") <- "Column 1"
attr(l, "row.names") <- paste("Row ", 1:5)