LoginSignup
3
4

More than 5 years have passed since last update.

R の data.frame を作る C の関数

Last updated at Posted at 2015-01-09

C言語でRの書く拡張の中で data.frame を新しく作る例です。ソースコードはgithub/junkoda/Rext-examples

この例では x,y,z という3つのベクトルをもつ data.frame を返す。Rでいうところの:

> x <- c(0,0,0,0); y <- c(0,0,0,0); z <- c(0,0,0,0)
> data.frame(x,y,z)
  x y z
1 0 0 0
2 0 0 0
3 0 0 0
4 0 0 0

以下、C側での関数 return_data_frame の説明が続きます。

#include <R.h>
#include <Rinternals.h>

SEXP return_data_frame(void)
{

まずはベクトル x, y, z を作っておく。

const int nrow= 4;
SEXP x;

PROTECT(x = allocVector(REALSXP, nrow));
double* rx= REAL(x);

for(int i=0; i<nrow; i++)
  rx[i]= 0.0;

y,z も同様。

data.frame とは class="data.frame" 属性をもつリストで、printで表示するためには行番号も必要。リストも内部的にはベクトル。

const int ncol= 3; // Column are x,y,z  
SEXP list;
PROTECT(list = allocVector(VECSXP, ncol));

setAttrib(list, R_ClassSymbol, ScalarString(mkChar("data.frame")));

列の名前 x y z:

SEXP col_names;
PROTECT(col_names = allocVector(STRSXP, ncol));
SET_STRING_ELT(col_names, 0, mkChar("x"));
SET_STRING_ELT(col_names, 1, mkChar("y"));
SET_STRING_ELT(col_names, 2, mkChar("z"));
setAttrib(list, R_NamesSymbol, col_names);

同様に列番号 1 2 3 4 をセット:

SEXP row_names;
PROTECT(row_names = allocVector(STRSXP, nrow));

char rname[10];
for(int i=0; i<nrow; i++) {
  sprintf(rname, "%d", i+1);
  SET_STRING_ELT(row_names, i, mkChar(rname));
}
setAttrib(list, R_RowNamesSymbol, row_names);

ベクトルを data.frame にセット:

SET_VECTOR_ELT(list, 0, x);
SET_VECTOR_ELT(list, 1, y);
SET_VECTOR_ELT(list, 2, z);

最後に PROTECTした回数だけ UNPROTECT:

UNPROTECT(6);

ここでは x,y,z,list,row_names, col_names の6回なので 6。

こうして作った list が SEXP return_data_frame(void) の戻り値:

return list;
}

R から使う。

コンパイル

R CMD SHLIB dataframe.c
dyn.load("dataframe.so")

return.data.frame <- function() {
  .Call("return_data_frame")
}

d <- return.data.frame()

print(d)
#  x y z
# 1 0 0 0
# 2 0 0 0
# 3 0 0 0
# 4 0 0 0

print(is.data.frame(d)) #=> TRUE

参考

data.frame() のソースをみると

attr(value, "row.names") <- row.names
attr(value, "class") <- "data.frame"

と書いてある。"class" を設定しないと data.frame とは認識されない。"row.names" がないと print() で表示してくれない。

Cからリストをつくる方法は R のソース builtin.c do_makelist() 関数をみるとよい。

3
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
4