添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
  • 45.2.1 evalCpp() 转换单一计算表达式
  • 45.2.2 cppFunction() 转换简单的C++函数—Fibnacci例子
  • 45.2.3 sourceCpp() 转换C++程序—正负交替迭代例子
  • 45.2.4 sourceCpp() 转换C++源文件中的程序—正负交替迭代例子
  • 45.2.5 sourceCpp() 转换C++源程序文件—卷积例子
  • 45.2.6 随机数例子
  • 45.2.7 bootstrap例子
  • 45.2.8 在Rmd文件中使用C++源程序文件
  • 46 R与C++的类型转换
  • 46.1 wrap() 把C++变量返回到R中
  • 46.2 as() 函数把R变量转换为C++类型
  • 46.3 as() wrap() 的隐含调用
  • 47 Rcpp 属性
  • 47.1 Rcpp属性介绍
  • 47.2 在C++源程序中指定要导出的C++函数
  • 47.2.1 特殊注释 //[[Rcpp::export]]
  • 47.2.2 修改导出的函数名
  • 47.2.3 可导出的函数
  • 47.3 在R中编译链接C++代码
  • 47.3.1 sourceCpp() 函数中直接包含C++源程序字符串
  • 47.3.2 cppFunction() 函数中直接包含C++函数源程序字符串
  • 47.3.3 evalCpp() 函数中直接包含C++源程序表达式字符串
  • 47.3.4 depends 指定要链接的库
  • 47.4 Rcpp属性的其它功能
  • 47.4.1 自变量有缺省值的函数
  • 47.4.2 异常传递
  • 47.4.3 允许用户中断
  • 47.4.4 把R代码写在C++源文件中
  • 47.4.5 invisible 要求函数结果不自动显示
  • 47.4.6 在C++中调用R的随机数发生器
  • 48 Rcpp提供的C++数据类型
  • 48.1 RObject类
  • 48.2 IntegerVector类
  • 48.2.1 IntegerVector示例1:返回完全数
  • 48.2.2 IntegerVector示例2:输入整数向量
  • 48.3 NumericVector类
  • 48.3.1 示例1:计算元素 \(p\) 次方的和
  • 48.3.2 示例2: clone 函数
  • 48.3.3 示例3:向量子集
  • 48.4 NumericMatrix类
  • 48.4.1 示例1:计算矩阵各列模的最大值
  • 48.4.2 示例2:把输入矩阵制作副本计算元素平方根
  • 48.4.3 示例3:访问列子集
  • 48.5 Rcpp的其它向量类
  • 48.5.1 Rcpp的LogicalVector类
  • 48.5.2 Rcpp的CharacterVector类型
  • 48.6 Rcpp提供的其它数据类型
  • 48.6.1 Named类型
  • 48.6.2 List类型
  • 48.6.3 Rcpp的DataFrame类
  • 48.6.4 Rcpp的Function类
  • 48.6.5 Rcpp的Environment类
  • 49 Rcpp糖
  • 49.1 简单示例
  • 49.2 向量化的运算符
  • 49.2.1 向量化的四则运算
  • 49.2.2 向量化的赋值运算
  • 49.2.3 向量化的二元逻辑运算
  • 49.2.4 向量化的一元运算符
  • 49.3 用Rcpp访问数学函数
  • 49.4 用Rcpp访问统计分布类函数
  • 49.5 在Rcpp中产生随机数
  • 49.6 返回单一逻辑值的函数
  • 49.7 返回糖表达式的函数
  • 49.7.1 is_na
  • 49.7.2 seq_along
  • 49.7.3 seq_len
  • 49.7.4 pmin pmax
  • 49.7.5 ifelse
  • 49.7.6 sapply lapply
  • 49.7.7 sign
  • 49.7.8 diff
  • 49.8 R与Rcpp不同语法示例
  • 49.9 用RcppArmadillo执行矩阵运算
  • 49.9.1 生成多元正态分布随机数
  • 49.9.2 快速计算线性回归
  • 50 用Rcpp帮助制作R扩展包
  • 50.1 不用扩展包共享C++代码的方法
  • 50.2 生成扩展包
  • 50.2.1 利用已有基于Rcpp属性的源程序制作扩展包
  • 50.2.2 DESCRIPTION文件
  • 50.2.3 NAMESPACE文件
  • 50.3 重新编译
  • 50.4 建立C++用的接口界面
  • 51 R编程例子
  • 51.1 R语言
  • 51.1.1 用向量作逆变换
  • 51.1.2 斐波那契数列计算
  • 51.1.3 穷举所有排列
  • 51.1.4 可重复分组方式穷举
  • 51.1.5 升降连计数
  • 51.1.6 高斯八皇后问题
  • 51.1.7 最小能量路径
  • 51.2 概率
  • 51.2.1 智者千虑必有一失
  • 51.2.2 圆桌夫妇座位问题
  • 51.3 科学计算
  • 51.3.1 城市间最短路径
  • 51.3.2 Daubechies小波函数计算
  • 51.3.3 房间加热温度变化
  • 51.4 统计计算
  • 51.4.1 线性回归实例
  • 51.4.2 核回归与核密度估计
  • 51.4.3 二维随机模拟积分
  • 51.4.4 潜周期估计
  • 51.4.5 ARMA(1,1)模型估计
  • 51.4.6 VAR模型平稳性
  • 51.4.7 贮存可靠性评估
  • 51.5 数据处理
  • 51.5.1 小题分题型分数汇总
  • 51.5.2 类别编号重排
  • 51.6 文本处理
  • 51.6.1 用R语言下载处理《红楼梦》htm文件
  • 52 使用经验
  • 52.1 文件管理
  • 52.1.1 文件备份
  • 52.1.2 工作空间
  • 52.2 程序格式
  • A R Markdown文件格式
  • A.1 R Markdown文件
  • A.2 R Markdown文件的编译
  • A.2.1 编译的实际过程
  • A.3 在R Markdown文件中插入R代码
  • A.4 输出表格
  • A.5 利用R程序插图
  • A.6 冗余输出控制
  • A.7 代码段选项
  • A.7.1 代码和文本输出结果格式
  • A.7.2 图形选项
  • A.7.3 缓存(cache)选项
  • A.8 章节目录链接问题
  • A.9 其它编程语言引擎
  • A.10 交互内容
  • A.11 属性设置
  • A.11.1 YAML元数据
  • A.11.2 输出格式
  • A.11.3 输出格式设置
  • A.11.4 目录设置
  • A.11.5 章节自动编号
  • A.11.6 Word输出章节自动编号及模板功能
  • A.11.7 HTML特有输出格式设置
  • A.11.8 关于数学公式支持的设置
  • A.11.9 输出设置文件
  • A.12 LaTeX和PDF输出
  • A.12.1 TinyTex的安装使用
  • A.12.2 Rmd中Latex设置
  • A.13 生成期刊文章
  • A.14 附录:经验与问题
  • A.14.1 Word模板制作
  • A.14.2 数学公式设置补充
  • B 用bookdown制作图书
  • B.1 介绍
  • B.2 一本书的设置
  • B.3 章节结构
  • B.4 书的编译
  • B.5 交叉引用
  • B.6 数学公式和公式编号
  • B.7 定理类编号
  • B.8 文献引用
  • B.9 插图
  • B.10 表格
  • B.10.1 Markdown表格
  • B.10.2 kable() 函数制作表格
  • B.10.3 R中其它制作表格的包
  • B.11 数学公式的设置
  • B.12 使用经验
  • B.12.1 学位论文
  • B.12.2 LaTeX
  • B.12.3 算法
  • B.12.4 中文乱码
  • B.12.5 图片格式
  • B.12.6 其它经验
  • B.13 bookdown的一些使用问题
  • C 用R Markdown制作简易网站
  • C.1 介绍
  • C.2 简易网站制作
  • C.2.1 网站结构
  • C.2.2 编译
  • C.2.3 内容文件
  • C.2.4 网站设置
  • C.3 用blogdown制作网站
  • C.3.1 生成新网站的框架
  • C.3.2 网页内容文件及其设置
  • C.3.3 初学者的工作流程
  • C.3.4 网站设置文件
  • C.3.5 静态文件
  • D 制作幻灯片
  • D.1 介绍
  • D.2 Slidy幻灯片
  • D.2.1 文件格式
  • D.2.2 幻灯片编译
  • D.2.3 播放控制
  • D.2.4 生成单页HTML
  • D.2.5 数学公式处理与输出设置文件
  • D.2.6 其它选项
  • D.2.7 slidy幻灯片激光笔失效问题的修改
  • D.3 MS PowerPoint幻灯片
  • D.4 Bearmer幻灯片格式
  • D.5 R Presentation格式
  • References
  • 编著:李东风
  • 这可以用专门的性能分析(profiling)功能实现。 R软件中的 Rprof() 函数可以执行性能分析的数据收集工作, 收集到的性能数据用 summaryRprof() 函数可以显示运行最慢的函数。 如果使用RStudio软件,可以用 Profile 菜单执行性能数据收集与分析, 可以在图形界面中显示程序中哪些部分运行花费时间最多。

    在改进已有程序的效率时, 第一要注意的就是不要把原来的正确算法改成一个速度更快但是结果错误的算法。 这个问题可以通过建立试验套装, 用原算法与新算法同时试验看结果是否一致来避免。 多种解决方案的正确性都可以这样保证, 也可以比较多种解决方案的效率。

    本章后面部分描述常用的改善性能的方法。 对于涉及到大量迭代的算法, 如果用R实现性能太差不能满足要求, 可以改成C++编码,用Rcpp扩展包连接到R中。 Rcpp扩展包的使用将单独讲授。

    R的运行效率也受到内存的影响, 占用内存过多的算法有可能受到物理内存大小限制无法运行, 过多复制也会影响效率。

    如果要实现一个比较单纯的不需要利用R已有功能的算法, 发现用R计算速度很慢的时候, 也可以考虑先用Julia语言实现。 Julia语言设计比R更先进,运算速度快得多, 运算速度经常能与编译代码相比, 缺点是刚刚诞生几年的时间, 可用的软件包还比较少。

    18.2 性能比较和向量化编程示例

    充分利用R的向量化编程和内建函数可以提高程序效率。 R函数 system.time() 可以测量某个表达式的运行时间, proc.time() 可以用作会话期间的计时时钟, 扩展包bench可以用来比较不同表达式的运行时间。

    例18.1 假设要计算如下的统计量: w = \frac{1}{n} \sum_{i=1}^n | x_i - \hat m |, 其中 \(x_1, x_2, \dots, x_n\) 是某总体的样本, \(\hat m\) 是样本中位数。 比较不同的编程方法。

    用传统的编程风格, 把这个统计量的计算变成一个R函数,可能会写成:

    显式循环是R运行速度较慢的部分, 有循环的程序也比较冗长, 与R的向量化简洁风格不太匹配。 在循环内修改数据子集,例如数据框子集, 可能会先制作副本再修改, 这当然会损失很多效率。 R 3.1.0版本以后列表元素在修改时不制作副本, 但数据框还会制作副本。

    前面已经指出, 利用R的向量化运算可以减少很多循环程序。

    R中的有些运算可以用内建函数完成, 如sum, prod, cumsum, cumprod, mean, var, sd等。 这些函数以编译程序的速度运行, 不存在效率损失。

    R的sin, sqrt, log等函数都是向量化的, 可以直接对输入向量的每个元素进行变换。

    对矩阵,用apply函数汇总矩阵每行或每列。 colMeans, rowMeans可以计算矩阵列平均和行平均, colSums, rowSums可以计算矩阵列和与行和。

    apply类函数有多个, 包括apply, sapply, lapply, tapply, vapply, replicate等。 这些函数不一定能提高程序运行速度, 但是使用这些函数更符合R的程序设计风格, 使程序变得简洁, 程序更简洁并不等同于程序更容易理解, 要理解这样的程序, 需要更多学习与实践。 参见25

    18.3.1 replicate()函数

    replicate()函数用来执行某段程序若干次, 类似于for()循环但是没有计数变量。 常用于随机模拟。 replicate()的缺省设置会把重复结果尽可能整齐排列成一个多维数组输出。

    replicate(重复次数, 要重复的表达式)

    其中的表达式可以是复合语句, 也可以是执行一次模拟的函数。

    下面举一个简单模拟例子。 设总体\(X\)\(\text{N}(0, 1)\), 取样本量\(n=5\), 重复地生成模拟样本共\(B=6\)组, 输出每组样本的样本均值和样本标准差。 模拟可以用如下的replicate()实现:

    类似于x <- c(x, y)这样的累积结果每次运行都会制作一个x的副本, 在x存储量较大或者重复修改次数很多时会减慢程序。

    例18.4 执行10000次模拟, 每次模拟求10个U(0,1)均匀随机数的极差, 保存每次的极差, 求平均极差。

    x <- c(x, y)这样的写法:

    R的性能分析工具可以按较高频率(如每隔几毫秒)抽查正在被调用的函数, 因为函数可以嵌套调用, 所以会记录下来正在嵌套调用的各个函数。 因为抽查的速度很快, 所以会得到大量的被调用函数的抽样数据, 这样就可以进行概括, 得知哪些函数被调用最频繁, 调用的途径是怎样的。 基本R的utils::Rprof()可以收集程序运行的性能分析用数据, 而utils::summaryRprof()则可以用文本格式提供性能分析的概括。

    在RStudio软件中, 借助于profvis扩展包, 我们可以从Profile菜单对选定行进行性能分析。 对比较复杂的程序, 应该将要分析的程序保存为一个R源文件, 并用source()的方法将要运行的函数载入, 并用profvis()函数调用该函数并显示运行后性能分析结果。

    例18.6 18.4的程序为例。 我们将第一个程序包装为一个函数bad_copy()并存入文件bad_copy.R中, 然后用profvis进行性能分析。

    bad_copy.R文件内容为:

    R中提供了大量的数学函数、统计函数和特殊函数, 可以打开R的HTML帮助页面, 进入“Search Enging & Keywords”链接, 查看其中与算术、数学、优化、线性代数等有关的专题。

    这里简单列出一部分常用函数, 并对数学计算中常用函数filter, fft, convolve进行较详细说明。

    18.6.1 数学函数

    常用数学函数包括abs, sign, log, log10, sqrt, exp, sin, cos, tan, asin, acos, atan, atan2, sinh, cosh, tanh。 还有gamma, lgamma(伽玛函数的自然对数)。

    用于取整的函数有ceiling, floor, round, trunc, signif, as.integer等。 这些函数是向量化的一元函数。

    choose(n,k)返回从\(n\)中取\(k\)的组合数。 factorial(x)返回\(x!\)结果。 combn(x,m)返回从集合\(x\)中每次取出不计次序的\(m\)个的所有不同取法, 结果为一个矩阵,矩阵每列为一种取法的\(m\)个元素值。

    18.6.2 概括函数

    sum对向量求和, prod求乘积。

    cumsumcumprod计算累计, 得到和输入等长的向量结果。

    diff计算前后两项的差分(后一项减去前一项)。

    mean计算均值,var计算样本方差或协方差矩阵, sd计算样本标准差, median计算中位数, quantile计算样本分位数。 cor计算相关系数。

    colSums, colMeans, rowSums, rowMeans对矩阵的每列或每行计算总和或者平均值, 效率比用apply函数要高。

    rleinverse.rle用来计算数列中“连”长度及其逆向恢复, “连”经常用在统计学的随机性检验中。

    18.6.3 最值

    maxmin求最大和最小, cummaxcummin累进计算。

    range返回最小值和最大值两个元素。

    对于max, min, range, 如果有多个自变量可以把这些自变量连接起来后计算。

    pmax(x1,x2,...)对若干个等长向量计算对应元素的最大值, 不等长时短的被重复使用。 pmin类似。 比如,pmax(0, pmin(1,x))x限制到\([0,1]\)内。

    18.6.4 排序

    sort返回排序结果。 可以用decreasing=TRUE选项进行降序排序。 sort可以有一个partial=选项, 这样只保证结果中partial=指定的下标位置是正确的。 比如:

    integrate(f, lower, upper)对一元函数f计算从lowerupper的定积分。 使用自适应算法保证精度。

    uniroot(f, interval)对函数f在给定区间内求一个根, interval为区间的两个端点。 要求f在两个区间端点的值异号。 即使有多个根也只能给出一个。 如\(x(x-1)(x+1)\)函数在\([-2,2]\)的根:

    R中fft函数使用快速傅立叶变换算法计算离散傅立叶变换。 设x为长度n的向量, y=fft(x),则

    R在遇到向量自身迭代时很难用向量化编程解决, filter函数可以解决其中部分问题。 filter函数可以进行卷积型或自回归型的迭代。 语法为

    对输入序列\(x_t, t=1,2,\dots,n\), 希望进行如下滤波计算: \begin{aligned} y_{t} = \sum_{j=-k}^k a_j x_{t-j}, \ k+1 \leq t \leq n-k-1, \end{aligned} 其中\((a_{-k}, \dots, a_0, \dots, a_{k})\)是长度为\(2k+1\)的向量。 注意公式中\(a_j\)\(x_{t-j}\)对应。

    假设\(x\)保存在向量x中, \((a_{-k}, \dots, a_0, \dots, a_{k})\)保存在向量f中, \(y_{k+1}, \dots, y_{n-k}\)保存在向量y中, 无定义部分取NA, 程序可以写成

    对输入序列\(x_t, t=1,2,\dots,n\), 希望进行如下滤波计算: \begin{aligned} y_{t} = \sum_{j=0}^k a_j x_{t-j}, \ k+1 \leq t \leq n, \end{aligned} 其中\((a_0, \dots, a_{k})\)是长度为\(k+1\)的向量。 注意公式中\(a_j\)\(x_{t-j}\)对应。

    假设\(x\)保存在向量x中, \((a_0, \dots, a_{k})\)保存在向量f中, \(y_{k+1}, \dots, y_{n}\)保存在向量y中, 无定义部分取NA, 程序可以写成

    设输入\(e_t, t=1,2,\dots, n\), \begin{aligned} y_t = \sum_{j=1}^k a_j y_{t-j} + e_t, \ t=1,2,\dots,n, \end{aligned} 其中\((a_1, \dots, a_k)\)\(k\)个实数, \((y_{-k+1}, \dots, y_0)\)已知。

    \(x\)保存在向量x中,\((a_1, \dots, a_k)\)保存在向量a中, \((y_1, \dots, y_n)\)保存在向量y中。

    如果\((y_{-k+1}, \dots, y_0)\)都等于零, 可以用如下程序计算\(y_1, y_2, \dots, y_n\):

    考虑如下计算问题: S_{k,n} = \sum_{i=1}^n \frac{1}{i^k}

    下面的程序取n为一百万,k为2到21,循环地用单线程计算。

    为了估计总体中某个比例\(p\)的置信区间, 调查了一组样本, 在\(n\)个受访者中选“是”的比例为\(\hat p\)。 令\(\lambda\)为标准正态分布的双侧\(\alpha\)分位数, 参数\(p\)的近似\(1-\alpha\)置信区间为 \frac{\hat p + \frac{\lambda^2}{2n}}{1 + \frac{\lambda^2}{n}} \frac{\lambda}{\sqrt{n}} \frac{\sqrt{\hat p (1 - \hat p) + \frac{\lambda^2}{4n}}} {1 + \frac{\lambda^2}{n}} 称为Wilson置信区间。

    假设要估计不同\(1-\alpha\), \(n\), \(p\)情况下, 置信区间的覆盖率(即置信区间包含真实参数\(p\)的概率)。 可以将这些参数组合定义成一个列表, 列表中每一项是一种参数组合, 对每一组合分别进行随机模拟,估计覆盖率。 因为不同参数组合之间没有互相依赖的关系, 随机数序列完全可以使用同一个序列。

    不并行计算的程序示例:

    大量的耗时的统计计算是随机模拟, 有时需要并行计算的部分必须使用独立的随机数序列。 比如,需要进行一千万次重复模拟,每次使用不同的随机数序列, 可以将其分解为10组模拟,每组模拟一百万次, 这就要求这10组模拟使用的随机数序列不重复。

    R中实现了L'Ecuyer的多步迭代复合随机数发生器, 此随机数发生器周期很长, 而且很容易将发生器的状态前进指定的步数。 parallel包的nextRNGStream()函数可以将该发生器前进到下一段的开始, 每一段都足够长, 可以用于一个节点。

    以Wilson置信区间的模拟为例。 设\(n=30\), \(p=0.01\), \(1-\alpha=0.95\), 取重复模拟次数为1千万次,估计Wilson置信区间的覆盖率。 单线程版本为: