第 12 章 数据框
本章主要讲述如何创建一个DataFrame
对象,以及如何访问其元素,及其成员函数。在Rcpp
中,DataFrame
是按照一种向量的方式实施的。换言之,Vector
是一种元素为标量的向量,而DataFrame
是元素为具有相同长度的Vector
的向量。因此,Vector
和DataFrame
在创建对象,访问元素和成员函数上,有很多相同的方法。
12.1 创建数据框对象
DataFrame::create()
被用于创建DataFrame
对象。使用Named()
或 _[]
可以为数据框对象指定列名。
// 由 Vector v1, v2创建数据框
DataFrame df = DataFrame::create(v1, v2);
// 指定列名
DataFrame df = DataFrame::create( Named("V1") = v1 , _["V2"] = v2 );
当用户使用DataFrame::create()
来创建DataFrame
时,原始的Vector
元素不会被复制到数据框的列中,该列实际上是对原始Vector
的“引用”(“reference”)。因此,改变原始Vector
的值,也会改变数据框对应列的值。为了避免上述情况,在创建DataFrame
的列时,我们可以使用clone()
函数来复制Vector
元素的值。
通过下面的代码示例,可以看到使用clone()
和不使用之间的区别。数据框df
的两列v1
和v2
,分别是对Vector
v的引用,以及复制。可以看到,如果改变Vector
v,那么 v1会被改变,但是v2不受影响。
#include <Rcpp.h>
using namespace Rcpp;
// [[Rcpp::plugins(cpp11)]]
// [[Rcpp::export]]
DataFrame rcpp_df(){
// 创建向量v
NumericVector v = {1,2};
// 创建数据框df
DataFrame df = DataFrame::create( Named("V1") = v, // simple assign
Named("V2") = clone(v)); // using clone()
// 改变向量v
v = v * 2;
return df;
}
执行结果如下:
> rcpp_df()
V1 V2
1 2 1
2 4 2
12.2 访问数据框元素
当我们想访问DataFrame
的某一列时,这一列会被暂时地赋值到Vector
对象上,然后通过该对象来访问。与Vector
类似,DataFrame
的列可以通过一个数值向量(某个列数),一个字符串向量(某个列名),或一个逻辑向量来指定。
和DataFrame
的创建类似, 通过上面的方法,给一个DataFrame
列赋到Vector
不会把这个值赋值到 Vector
对象上, 但是会是一个对列的“reference”(引用). 因此,当你改变Vector
对象的值时,该列的值也会被相应地改变。
如果你希望,通过拷贝列值的方式来创建Vector
,使用clone()
函数,这样原始的DataFrmae
列的值不会随着这个Vector
的改变而改变。
NumericVector v1 = df[0]; // v1 成为"reference" df 0列的引用
v1 = v1 * 2; // 改变v1的值,也会导致df[0]的值改变
NumericVector v2 = clone(df[0]); // 将df[0]的值复制给v2
v2 = v2*2; // 改变v2的值,不会导致df[0]的值改变
12.3 成员函数
在Rcpp中,DataFrmae
是利用某些种类的向量来实现的。换言之,Vector
是元素为标量的向量,而DataFrame
是元素为Vector
的向量。因此,DataFrame
和Vector
有着很多共同的成员函数。
12.3.1 length() size()
返回列数。
12.3.2 nrows()
返回行数。
12.3.3 names()
以字符向量的方式返回列名。
12.3.4 offset(name) findName(name)
返回用“name”字符串指定列名的数值索引。
12.3.5 fill(v)
使用Vector
v来填充DataFrame
的所有列。
需要注意的是,如果v的长度不等于数据框的列长度,那么会有warning
#include <Rcpp.h>
using namespace Rcpp;
// [[Rcpp::plugins(cpp11)]]
// [[Rcpp::export]]
DataFrame rcpp_df(NumericVector v){
// 创建向量v
NumericVector v1 = {0,0,0};
// 创建数据框df
DataFrame df = DataFrame::create( Named("V1") = clone(v1),
Named("V2") = clone(v1));
df.fill(v);
return df;
}
在R中,执行下面的代码会有不同的结果。
> sourceCpp('test.cpp')
> rcpp_df(1:6)
V1 V2
1 1 1
2 2 2
3 3 3
Warning message:
In format.data.frame(if (omit) x[seq_len(n0), , drop = FALSE] else x, :
corrupt data frame: columns will be truncated or padded with NAs
> rcpp_df(1:3)
V1 V2
1 1 1
2 2 2
3 3 3
> rcpp_df(1:2)
V1 V2
1 1 1
2 2 2
3 <NA> <NA>
Warning message:
In format.data.frame(if (omit) x[seq_len(n0), , drop = FALSE] else x, :
corrupt data frame: columns will be truncated or padded with NAs
可以看出,只有在向量v和数据框的行数一致时,不会出现报错。向量过长则会丢弃后面的信息,过短则在每列最后用NA来补全。
12.3.6 assign( first_it, last_it)
通过迭代器 first_it 和 last_it 指定的范围来给DataFrmae
的列赋值。具体可以参考Vector
8.3.7章节。
12.3.7 push_back(v)
在DataFrame
后加入Vector
v.
12.3.8 push_back( v, name )
在DataFrame
后加入Vector
v,其列名为指定的“name”。
12.3.9 push_front(x)
在DataFrame
前加入Vector
v.
12.3.10 push_front( x, name )
在DataFrame
前加入Vector
v,其列名为指定的“name”。
12.3.11 begin()
返回一个指向DataFrame
第一列的迭代器。
12.3.12 end()
返回一个指向DataFrame
最后一列的迭代器。
12.3.13 insert( it, v )
通过迭代器指定的位置,在DataFrame
上加入 Vector
v,返回一个指向该元素的迭代器。
12.3.14 erase(i)
删除 DataFrame
的i
列,返回指向该列后一列的迭代器。
12.3.15 erase(it)
删除 迭代器it
所指向的DataFrame
的列,返回指向该列后一列的迭代器。
###erase(first_i, last_i){#DF-erase-first-last-i}
删除first_i
到last_i-1
列,返回指向删除列后一列的迭代器。
12.3.16 erase(first_it, last_it)
删除first_it
到last_it-1
迭代器所指向的列,返回指向删除列后一列的迭代器。
12.3.17 containsElementNamed(name)
如果DataFrame
包含有列名name
所指定的列,那么返回true。
12.3.18 inherits(str)
如果对象的属性“class”中包含有字符串str
,那么返回true。