「R高级」Rcpp学习笔记之数据结构

2024-06-23 20:18

本文主要是介绍「R高级」Rcpp学习笔记之数据结构,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

在使用R语言多年以后,我终于开始去学习Rcpp,利用C++来提高运行速度。其实当你能熟练的使用一门语言后,再去学一门新的语言,并没有想象中的那么难,更何况Rcpp把很多脏活累活都给包办了,在里面调用C++还是挺方便。

C++是一门静态编译面向对象的编程语言,R是动态解释性面向对象语言,那么有一个不同就在于,你需要先声明一个变量,才能调用该变量。而在声明变量的时候,你就会遇到一个R语言中不怎么思考的问题,我这个变量要存放什么样的数据呢?

数据类型

R的基本数据类型有六种 "logical", "integer", "numeric" (等价于"double"), "complex", "character" 和 "raw",但常用的就四种, "integer", "numeric","logical"和"character"。

对于数值数据而言,C++的整型和浮点型可以定义多种精度,而R语言则简化成两种"integer"(32 bit)和"numeric"(53 bits),并且默认情况下数值都是浮点型。

在数据结构上,R语言提供了向量(vector),矩阵(matrix),数组(array),数据框(data.frame)和列表(list),唯独没有标量。其中向量可以认为是R语言的基本单位,是其他数据结构的基础。

原本能够让C++处理R对象,以及将C++处理完结果转成R能识别的对象,你需要了解R的内部结构,但是Rcpp通过定义了一系列数据类型(如下),使得我们能够非常容易地在R和C++之间交换对象。

// Rcpp/include/Rcpp/vector/instantiation.h
namespace Rcpp{typedef Vector<CPLXSXP> ComplexVector ;typedef Vector<INTSXP> IntegerVector ;typedef Vector<LGLSXP> LogicalVector ;typedef Vector<REALSXP> NumericVector ;typedef Vector<REALSXP> DoubleVector ;typedef Vector<RAWSXP> RawVector ;typedef Vector<STRSXP> CharacterVector ;typedef Vector<STRSXP> StringVector ;typedef Vector<VECSXP> GenericVector ;typedef Vector<VECSXP> List ;typedef Vector<EXPRSXP> ExpressionVector ;typedef Matrix<CPLXSXP> ComplexMatrix ;typedef Matrix<INTSXP> IntegerMatrix ;typedef Matrix<LGLSXP> LogicalMatrix ;typedef Matrix<REALSXP> NumericMatrix ;typedef Matrix<RAWSXP> RawMatrix ;typedef Matrix<STRSXP> CharacterMatrix ;typedef Matrix<STRSXP> StringMatrix ;typedef Matrix<VECSXP> GenericMatrix ;typedef Matrix<VECSXP> ListMatrix ;typedef Matrix<EXPRSXP> ExpressionMatrix ;}

以R语言的向量为例,Rcpp考虑到R语言所有可能的数据类型,提供了9种Vector。比如说"NumericVector", "IntegerVector", "LogicalVector"," CharacterVector"就是对应着"integer", "numeric","logical"和"character"这四种数据类型。因此,你可以根据你输入向量的数据类型来进行选择。

我们以一个简单的求和函数作为例子

double sumC(NumericVector v){double total = 0;int num = v.size();for (int i = 0; i< num; i++){total += v[i];}return total;
}

sumC这个函数读取一个数值向量,对其进行结合,返回一个浮点型标量。当然这个浮点型标量在R语言中就表现为一个长度为1的向量。

由于R语言数据类型和C++的不是一一对应,因此在处理过程中,有些时候需要对数据进行转换

std::string(x[i])

变量创建

我们可以通过下面这些方式创建向量

// v <- rep(0, 3)
NumericVector v (3);
// v <- rep(1, 3)
NumericVector v (3,1);
// v <- c(1,2,3) 
// C++11 Initializer list
NumericVector v = {1,2,3}; 
// v <- c(1,2,3)
NumericVector v = NumericVector::create(1,2,3);
// v <- c(x=1, y=2, z=3)
NumericVector v = NumericVector::create(Named("x",1), Named("y")=2 , _["z"]=3);

创建矩阵的方法如下

// m <- matrix(0, nrow=2, ncol=2)
NumericMatrix m1( 2 );
// m <- matrix(0, nrow=2, ncol=3)
NumericMatrix m2( 2 , 3 );
// m <- matrix(v, nrow=2, ncol=3)
NumericMatrix m3( 2 , 3 , v.begin() );

数据框和列表的创建依赖于已有向量,和R语言中创建形式相似。

// Creating DataFrame df from Vector v1, v2
DataFrame df = DataFrame::create(v1, v2);
// When giving names to columns
DataFrame df = DataFrame::create( Named("V1") = v1 , _["V2"] = v2 );// Create list L from vector v1, v2
List L = List::create(v1, v2);
// When giving names to elements
List L = List::create(Named("name1") = v1 , _["name2"] = v2);a

元素获取和赋值

在选取元素之前一定要注意,C++是以0为基,而R是以1为基。

我们可以用[]()进行数据选取向量中的元素并复制,支持利用数值向量或者逻辑向量来选取多个数据

// 新建向量
NumericVector v  {10,20,30,40,50};
// 设置向两名
v.names() = CharacterVector({"A","B","C","D","E"});
// 准备用于获取数据的向量
NumericVector   numeric = {1,3};
IntegerVector   integer = {1,3};
CharacterVector character = {"B","D"};
LogicalVector   logical = {false, true, false, true, false};
// 获取数据
double x1 = v[0];
double x2 = v["A"];
NumericVector res1 = v[numeric];
NumericVector res2 = v[integer];
NumericVector res3 = v[character];
NumericVector res4 = v[logical];
// 赋值
v[0]   = 100;
v["A"] = 100;
NumericVector v2 {100,200};
v[numeric]   = v2;
v[integer]   = v2;
v[character] = v2;
v[logical]   = v2;

对于矩阵而言,建议只用()进行数据选取,因为没有[row_index, col_index]的操作。

// 创建一个5x5的矩阵
NumericMatrix m( 5, 5 );
// 获取0,2的元素
double x = m( 0 , 2 );
// 选择第1行
NumericVector v = m( 0 , _ );
// 选择第3列
NumericVector v = m( _ , 2 );
// 选择第1-2行,3-4列
NumericMatrix m2 = m( Range(0,1) , Range(2,3) );

对于DataFrame和List,两则都只支持[]选择其中向量。

成员函数

成员函数(member function)是C++面向对象编程中的一个概念,通过调用成员函数可以对类进行操作。

举个例子,对于R语言而言,向量是可以有名字的,例如

x <- c(a = 1, b = 2, c = 3) 

R语言是一个面向对象的编程语言,所以这种命名向量其实认为是一个向量拥有了一个名为names的属性而已。

在R语言中attr函数能够增加对象的属性,因此上面代码等价于

y <- c(1,2,3)
attr(y, 'names') <- c('a','b','c')

C++中的向量和矩阵拥有一个成员函数.name()就可以获取/修改/增加变量命名。

NumericVector addname2(NumericVector x, CharacterVector y){x.names() = y;return x;
}

更通用的是.attr函数,它能够修改和增加任意属性

不同数据类型拥有不同的成员函数,参考

  • 向量: https://teuder.github.io/rcpp4everyone_en/080_vector.html#member-functions
  • 矩阵: https://teuder.github.io/rcpp4everyone_en/100_matrix.html#member-functions-1
  • 数据框: https://teuder.github.io/rcpp4everyone_en/140_dataframe.html#member-functions-2
  • 列表: https://teuder.github.io/rcpp4everyone_en/150_list.html#member-functions-3
  • 字符串: https://teuder.github.io/rcpp4everyone_en/170_string.html#member-functions-4
  • 日期: https://teuder.github.io/rcpp4everyone_en/180_date.html#member-functions-5
  • 时间: https://teuder.github.io/rcpp4everyone_en/190_datetime.html#member-functions-6

缺失值

同R一样,缺失值之间以及缺失值和正常值之间的比较没有意义,因此在写代码过程时要提前考虑到缺失值的可能,或者是用R语言处理完缺失值,把不含缺失值的数据作为C++函数的输入。

R语言采用比特模式对每一种数据类型进行标注,也就是针对每一种数据类型(Integer,Numeric,Character,Logical)保留一个比特作为缺失数据的标签值。

为了在C++中处理R的缺失值,Rcpp提供了四个变量对应R的四种数据类型

  • NA_INTEGER: 整型,Integer
  • NA_STRING: 字符串,Character
  • NA_LOGICAL:逻辑性,Logical
  • NA_REAL:双精度浮点型, Numeric

写一个函数进行讲解下缺失值的使用。

double sumC(NumericVector v, bool na_rm){double total = 0;for (int i = 0; i< v.size(); i++){if( ! NumericVector::is_na(v[i])){total += double(v[i]);} else if (NumericVector::is_na(v[i]) & na_rm){continue ;} else {return NA_REAL;}}return total;
}

NumericVector::is_na()用于判断是否为缺失值,不同的数据类型有不同的is_na。如果na_rm=FALSE,那么返回缺失值,也就是NA_REAL.

参考资料

  • CharacterVector元素转string
  • https://teuder.github.io/rcpp4everyone_en
  • https://adv-r.hadley.nz/rcpp.html#rcpp-intro

版权声明:本博客所有文章除特别声明外,均采用 知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议 (CC BY-NC-ND 4.0) 进行许可。

2013053-042d47e898158b14.png
扫码即刻交流

这篇关于「R高级」Rcpp学习笔记之数据结构的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1088166

相关文章

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

Ilya-AI分享的他在OpenAI学习到的15个提示工程技巧

Ilya(不是本人,claude AI)在社交媒体上分享了他在OpenAI学习到的15个Prompt撰写技巧。 以下是详细的内容: 提示精确化:在编写提示时,力求表达清晰准确。清楚地阐述任务需求和概念定义至关重要。例:不用"分析文本",而用"判断这段话的情感倾向:积极、消极还是中性"。 快速迭代:善于快速连续调整提示。熟练的提示工程师能够灵活地进行多轮优化。例:从"总结文章"到"用

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

学习hash总结

2014/1/29/   最近刚开始学hash,名字很陌生,但是hash的思想却很熟悉,以前早就做过此类的题,但是不知道这就是hash思想而已,说白了hash就是一个映射,往往灵活利用数组的下标来实现算法,hash的作用:1、判重;2、统计次数;

【数据结构】——原来排序算法搞懂这些就行,轻松拿捏

前言:快速排序的实现最重要的是找基准值,下面让我们来了解如何实现找基准值 基准值的注释:在快排的过程中,每一次我们要取一个元素作为枢纽值,以这个数字来将序列划分为两部分。 在此我们采用三数取中法,也就是取左端、中间、右端三个数,然后进行排序,将中间数作为枢纽值。 快速排序实现主框架: //快速排序 void QuickSort(int* arr, int left, int rig

零基础学习Redis(10) -- zset类型命令使用

zset是有序集合,内部除了存储元素外,还会存储一个score,存储在zset中的元素会按照score的大小升序排列,不同元素的score可以重复,score相同的元素会按照元素的字典序排列。 1. zset常用命令 1.1 zadd  zadd key [NX | XX] [GT | LT]   [CH] [INCR] score member [score member ...]

【机器学习】高斯过程的基本概念和应用领域以及在python中的实例

引言 高斯过程(Gaussian Process,简称GP)是一种概率模型,用于描述一组随机变量的联合概率分布,其中任何一个有限维度的子集都具有高斯分布 文章目录 引言一、高斯过程1.1 基本定义1.1.1 随机过程1.1.2 高斯分布 1.2 高斯过程的特性1.2.1 联合高斯性1.2.2 均值函数1.2.3 协方差函数(或核函数) 1.3 核函数1.4 高斯过程回归(Gauss

【学习笔记】 陈强-机器学习-Python-Ch15 人工神经网络(1)sklearn

系列文章目录 监督学习:参数方法 【学习笔记】 陈强-机器学习-Python-Ch4 线性回归 【学习笔记】 陈强-机器学习-Python-Ch5 逻辑回归 【课后题练习】 陈强-机器学习-Python-Ch5 逻辑回归(SAheart.csv) 【学习笔记】 陈强-机器学习-Python-Ch6 多项逻辑回归 【学习笔记 及 课后题练习】 陈强-机器学习-Python-Ch7 判别分析 【学

6.1.数据结构-c/c++堆详解下篇(堆排序,TopK问题)

上篇:6.1.数据结构-c/c++模拟实现堆上篇(向下,上调整算法,建堆,增删数据)-CSDN博客 本章重点 1.使用堆来完成堆排序 2.使用堆解决TopK问题 目录 一.堆排序 1.1 思路 1.2 代码 1.3 简单测试 二.TopK问题 2.1 思路(求最小): 2.2 C语言代码(手写堆) 2.3 C++代码(使用优先级队列 priority_queue)

系统架构师考试学习笔记第三篇——架构设计高级知识(20)通信系统架构设计理论与实践

本章知识考点:         第20课时主要学习通信系统架构设计的理论和工作中的实践。根据新版考试大纲,本课时知识点会涉及案例分析题(25分),而在历年考试中,案例题对该部分内容的考查并不多,虽在综合知识选择题目中经常考查,但分值也不高。本课时内容侧重于对知识点的记忆和理解,按照以往的出题规律,通信系统架构设计基础知识点多来源于教材内的基础网络设备、网络架构和教材外最新时事热点技术。本课时知识