r语言中怎样查看函数源代码

r语言中怎样查看函数源代码,第1张

在r中看函数源代码:

在R中,代码可以分为如下几个级别:

首先,是你输入了函数对象名称,你可以直接看到代码的,如要获得函数对象fivenum的代码,就只需要在Console中键入函数对象名称fivenum就可以得到如下结果:

function (x, narm = TRUE)

{

xna <- isna(x)

if (narm)

x <- x[!xna]

else if (any(xna))

return(repint(NA, 5))

x <- sort(x)

n <- length(x)

if (n == 0)

repint(NA, 5)

else {

n4 <- floor((n + 3)/2)/2

d <- c(1, n4, (n + 1)/2, n + 1 - n4, n)

05 (x[floor(d)] + x[ceiling(d)])

}

}

<environment: namespace:stats>

从上面的例子可以看出,这类函数对象的代码是最容易看到的,也是我们学习的最好的材料了,而R中最大多数的函数对象是以这种方式出现的。

其次,我们在输入mean这类函数名次的时候,会出现如下结果:

function (x, )

UseMethod("mean")

<environment: namespace:base>

这表示函数作者把函数“封”起来了。这个时候我们可以先试一试methods(mean),利用methods函数看看mean这个函数都有哪些类型的,我们得到的结果如下:

[1] meandataframe meanDate meandefault meandifftime meanPOSIXct meanPOSIXlt

其实对此可以有一个简单的理解,虽然不够精确。因为在R中,mean函数可以求得属于不同类型对象的平均值,而不同类型对象平均值的求法还是有一些小小差 异的,比如说求一个向量的平均值和求一个数据框的平均值就有所差异,就要编写多个mean函数,然后“封”起来,以一个统一的mean出现,方便我们使 用。这正好也反映了R有一种类似泛型编程语言的性质。

既然我们已经知道mean中还有这么多种类,我们可以输入meandefault试一试就可以得到:

function (x, trim = 0, narm = FALSE, )

{

if (!isnumeric(x) && !iscomplex(x) && !islogical(x)) {

warning("argument is not numeric or logical: returning NA")

return(asnumeric(NA))

}

if (narm)

x <- x[!isna(x)]

trim <- trim[1]

n <- length(x)

if (trim > 0 && n > 0) {

if (iscomplex(x))

stop("trimmed means are not defined for complex data")

if (trim >= 05)

return(stats::median(x, narm = FALSE))

lo <- floor(n trim) + 1

hi <- n + 1 - lo

x <- sortint(x, partial = unique(c(lo, hi)))[lo:hi]

n <- hi - lo + 1

}

Internal(mean(x))

}

<environment: namespace:base>

同样就可以得到meandataframe、meanDate、meandifftime、meanPOSIXct、meanPOSIXlt 的具体内容了。值得注意的是,在R中,出现有多个同样近似功能的函数封装为一个函数的时候(这时候在函数中多半会出现类似UseMethod函数使用的情 况),我们不妨先输入meandefault试一试。这种形式的函数在R中一般作为默认的函数表示。

第三,这是一种特殊的情况,有人认为应该和第二种是一类,但是我还是要提出来单独归类。在这种情况也和第二种的原因有些类似,但并不是完全一致。

也许我们大家都很熟悉plot函数了吧,输入函数名plot的时候,我们会得到如下结果:

function (x, y, )

{

if (isnull(attr(x, "class")) && isfunction(x)) {

nms <- names(list())

if (missing(y))

y <- {

if (!"from" %in% nms)

0

else if (!"to" %in% nms)

1

else if (!"xlim" %in% nms)

NULL

}

if ("ylab" %in% nms)

plotfunction(x, y, )

else plotfunction(x, y, ylab = paste(deparse(substitute(x)),

"(x)"), )

}

else UseMethod("plot")

}

<environment: namespace:graphics>

请注意plot函数中也出现了UseMethod这个函数,但是和mean不同的是,前面有相当多的语句用于处理其他一些事情。这个时候,我们也使用methods(plot)来看看,得到如下结果:

plotacf plotdataframe plotDate plotdecomposedts plotdefault

plotdendrogram plotdensity plotecdf plotfactor plotformula

plothclust plothistogram plotHoltWinters plotisoreg plotlm

plotmedpolish plotmlm plotPOSIXct plotPOSIXlt plotppr

plotprcomp plotprincomp plotprofilenls plotspec plotspeccoherency

plotspecphase plotstepfun plotstl plottable plotts

plottskernel plotTukeyHSD

不看不知道,一看吓一跳,还以为我们输入plot的输出就是函数本身,结果也许不是如此。可能有人已经理解了,其实最后的UseMethod函数实在默认的调用plotdefault函数,赶快再看看plotdefault函数吧,发现它再调用plotxy函数,再看看plotxy函数,再plotxy函数中调用了一个Internal(plotxy(xy, type, pch, lty, col, bg, cex, lwd, ))函数,也许这就是真正起作用的函数了吧。思路基本上就是如此了,是否这个时候您可以获得一些阅读查找R函数内容的乐趣。

除了直接输入FUNdefault形式外,还可以使用getS3method(FUN,"default")来获得代码。这样就解决了绝大多数函数代码查看的工作了。

在第二种情况种,我们说了一般可以通过FUNdefault获得想要的结果。但是只有称为generic的函数才有这种“特权”。而lm等则没有,不过我们也可以尝试使用methods(lm)来看看结果如何,发现:

[1] lmfit lmfitnull lminfluence lmwfit lmwfitnull

Warning message:

function 'lm' appears not to be generic in: methods(lm)

出现了警告信息,表示说lm不是泛型函数,但是还是给出了结果lmfit等,大致上可以看成是和lm相关的系列函数吧。这样子就出现了有趣的局面,比如说既有plotts,也有tsplot。

依照第三种情况,我们发现竟然有的函数用星号标识了的,比如plotstl等,当我们输入plotstl,甚至是plotstl的时候都会给出 要么找不到这个对象,要么干脆是代码错误的信息。原来凡是用了标识的函数,都是隐藏起来的函数,估计是怕被人看见(其实这是玩笑话)!我们要看这些函数 的代码,我们该怎么办呢?其实也很容易,使用功能强大的getAnywhere(FUN),看看这个函数的名称,就可以猜想到它的功能估计是很强大的, Anywhere的内容都可以找到!getAnywhere(plotstl)的结果如下:

A single object matching 'plotstl' was found

It was found in the following places

registered S3 method for plot from namespace stats

namespace:stats

with value

function (x, labels = colnames(X), setpars = list(mar = c(0,

6, 0, 6), oma = c(6, 0, 4, 0), tck = -001, mfrow = c(nplot,

1)), main = NULL, rangebars = TRUE, , colrange = "light gray")

{

sers <- x$timeseries

ncomp <- ncol(sers)

data <- drop(sers %% rep(1, ncomp))

X <- cbind(data, sers)

colnames(X) <- c("data", colnames(sers))

nplot <- ncomp + 1

if (rangebars)

mx <- min(apply(rx <- apply(X, 2, range), 2, diff))

if (length(setpars)) {

oldpar <- docall("par", aslist(names(setpars)))

onexit(par(oldpar))

docall("par", setpars)

}

for (i in 1:nplot) {

plot(X[, i], type = if (i < nplot)

"l"

else "h", xlab = "", ylab = "", axes = FALSE, )

if (rangebars) {

dx <- 1/64 diff(ux <- par("usr")[1:2])

y <- mean(rx[, i])

rect(ux[2] - dx, y + mx/2, ux[2] - 04 dx, y -

mx/2, col = colrange, xpd = TRUE)

}

if (i == 1 && !isnull(main))

title(main, line = 2, outer = par("oma")[3] > 0)

if (i == nplot)

abline(h = 0)

box()

right <- i%%2 == 0

axis(2, labels = !right)

axis(4, labels = right)

axis(1, labels = i == nplot)

mtext(labels[i], side = 2, 3)

}

mtext("time", side = 1, line = 3)

invisible()

}

<environment: namespace:stats>

注意到前面有一段解释型的语言,描述了我们要找的这个函数放在了什么地方等等。其实对任意我们可以在R中使用的函数,都可以先试一试getAnywhere,看看都有些什么内容。算是一个比较“霸道”的函数。

在上面plotxy函数中,我们还可以看到Internal这个函数,类似的也许还可以看到Primitive、External、Call等函数这就和R系统内部工作方式和与外部接口的定义有关了,如果对这些函数有兴趣的话,就要学习组成R系统的源代码了。

最后,如果真的想阅读组成R系统本身的源代码,在各个CRAN中均有下载。你可以得到组成R系统所需要的材料。其中很多C语言(还有就是F)的源代码,均 是精心挑选过的算法,哪怕就是想学从头到尾编写具体的算法,也是学习的好材料。同时,你可以看到R系统内部是如何构成的,理解了这些对于高效使用R有至关 重要的作用。这个范畴的材料就要着重看一看R-Lang和R-inits了。

至此,R中阅读代码的内容就依照我的理解介绍了一下。随后将有一些R代码示例的分析注解、语言本身、R应用的和行业使用的材料翻译和具体例子说明。欢迎大家多多和我交流,一起进步。

在R中,概率函数形如:

[dpqr]distribution_abbreviation

其中第一个字母表示其所指分布的某一方面:

d = 密度函数(density)

p = 分布函数(distribution function)

q = 分位数函数(quantile function)

r = 生成随机数(随机偏差)

以正态分布为例

1 什么是正态分布

正态分布也被称为高斯分布,是统计学中极为常见的连续型概率分布。正态曲线呈钟型,两头低,中间高,左右对称因其曲线呈钟形,因此人们又经常称之为钟形曲线。

2 正态分布的两个参数及图形

正态分布有两个参数,即均数和标准差。 1)概率密度曲线在均值处达到最大,并且对称; 2)一旦均值和标准差确定,正态分布曲线也就确定; 3)当X的取值向横轴左右两个方向无限延伸时,曲线的两个尾端也无限渐近横轴,理论上永远不会与之相交; 4)正态随机变量在特定区间上的取值概率由正态曲线下的面积给出,而且其曲线下的总面积等于1;

5)均值可取实数轴上的任意数值,决定正态曲线的具体位置;标准差决定曲线的“陡峭”或“扁平”程度:标准差越大,正态曲线越扁平;标准差越小,正态曲线越陡峭。这是因为,标准差越小,意味着大多数变量值离均数的距离越短,因此大多数值都紧密地聚集在均数周围,图形所能覆盖的变量值就少些,于是都挤在一块,图形上呈现瘦高型。相反,标准差越大,数据跨度就比较大,分散程度大,所覆盖的变量值就越多,图形呈现“矮胖型”。

3 标准正态分布

如果不指定一个均值和一个标准差,则函数将假定其为标准正态分布(均值为0,标准差为1)。

4 正态分布的概率函数

概率密度函数为dnorm(),分布函数pnorm(),分位函数qnorm(),随机数生成函数rnorm()。

dnorm(x, mean = 0, sd = 1, log = FALSE)

pnorm(q, mean = 0, sd = 1, lowertail = TRUE, logp = FALSE)

qnorm(p, mean = 0, sd = 1, lowertail = TRUE, logp = FALSE)

rnorm(n, mean = 0, sd = 1)

x - 是数字的向量。

p - 是概率向量。

n - 是观察次数(样本量)。

mean - 是样本数据的平均值,默认值为零。

sd - 是标准偏差,默认值为1。

pretty()创建美观的分割点。选取n+1等间距的取整数,将连续变量x分割为n个区间。pretty(x,n)

x:它被定义为矢量数据。

n:结果向量的长度。

返回:等长区间的数据向量。

设定随机数种子

setseed()

该函数是设定生成随机数的种子,种子是为了让结果具有重复性,保证你在执行和调试后,所创造的随机数保持不变。 24

runif(n, min = 0, max = 1)

该函数用于创建均匀分布的随机偏差。n表示观察次数,min和max分别为最小最大值。

其他概率分布见下表。

参考资料:

输入了函数对象名称,可以直接看到代码的,如要获得函数对象fivenum的代码,就只需要在Console中键入函数对象名称fivenum就可以得到如下结果:

function (x, narm = TRUE)

{

xna <- isna(x)

if (narm)

x <- x[!xna]

else if (any(xna))

return(repint(NA, 5))

x <- sort(x)

n <- length(x)

if (n == 0)

repint(NA, 5)

else {

n4 <- floor((n + 3)/2)/2

d <- c(1, n4, (n + 1)/2, n + 1 - n4, n)

05 (x[floor(d)] + x[ceiling(d)])

}

}

最简单但计算量最大的是泰勒公式:e=1+1/1!+1/2!+1/3!+1/4!+

下面是求e的R语言函数:

e_fun <- function(n) {

  etemp <- 1

  ni <- 1L

  for (i in 1:n) {

    etemp <- etemp + 1 / ni

    ni <- ni  (i + 1)

  }

  return(etemp)

}

不过你题目中要求的是求到精度为000001就停止,所以可以采用repeat循环:

i <- 1L

ni <- 1L

etemp <- 1

repeat {

  etemp1 <- etemp

  etemp <- etemp + 1 / ni

  ni <- ni  (i + 1)

  i <- i + 1

  if (etemp - etemp1 < 000001) break

}

i

etemp

在最后可以看到,求到i=10时,精度就已经达到要求了。

R语言实际上是函数的集合,用户可以使用base,stats等包中的基本函数,也可以自己编写函数完成一定的功能。但是初学者往往认为编写R函数十分困难,或者难以理解。这里对如何编写R函数进行简要的介绍。

函数是对一些程序语句的封装。换句话说,编写函数,可以减少人们对重复代码书写,从而让R脚本程序更为简洁,高效。同时也增加了可读性。一个函数往往完成一项特定的功能。例如,求标准差sd,求平均值,求生物多样性指数等。R数据分析,就是依靠调用各种函数来完成的。但是编写函数也不是轻而易举就能完成的,需要首先经过大量的编程训练。特别是对R中数据的类型,逻辑判别、下标、循环等内容有一定了解之后,才好开始编写函数。 对于初学者来说,最好的方法就是研究现有的R函数。因为R程序包都是开源的,所有代码可见。研究现有的R函数能够使编程水平迅速提高。

R函数无需首先声明变量的类型,大部分情况下不需要进行初始化。一个完整的R函数,需要包括函数名称,函数声明,函数参数以及函数体几部分。

1 函数名称,即要编写的函数名称,这一名称就作为将来调用R函数的依据。

2 函数声明,包括 <- function, 即声明该对象的类型为函数。

3 函数参数,这里是输入的数据,函数参数是一个虚拟出来的一个对象。函数参数所等于的数据,就是在函数体内部将要处理的值,或者对应的数据类型。 函数体内部的程序语句进行数据处理,就是对参数的值进行处理 ,这种处理只在调用函数的时候才会发生。函数的参数可以有多种类型。R help的界面对每个函数,及其参数的意义及所需的数据类型都进行了说明。

4 函数体

常常包括三部分

(1) 异常处理

输入的数据不能满足函数计算的要求,或者类型不符, 这时候一定要设计相应的机制告诉用户,输入的数据在什么地方有错误。 错误又分为两种。

第一种, 如果输入的数据错误不是很严重,可以经过转换,变为符合处理要求的数据时, 此时只需要给用户一个提醒,告知数据类型不符,但是函数本身已经 进行了相应的转换。

第二种,数据完全不符合要求,这种情况下,就 要终止函数的运行,而告知因为什么,函数不能运行。这样,用户在 使用函数的情况先才不至于茫然。

(2) 运算过程

包括具体的运算步骤。 运算过程和该函数要完成的功能有关。

R运算过程中,应该尽量减少循环的使用,特别是嵌套循环。R提供了 apply,replicate等一系列函数,来代替循环,应该尽量应用这些函数, 提高效率。 如果在R中实在太慢,那么核心部分只能依靠C或者Fortran 等语言编写,然后再用R调用这些编译好的模块,达到更高的效率。

运算过程中,需要大量用到if等条件作为判别的标准。if和while都是需要数据TRUE/FALSE这样的逻辑类型变量,这就意味着,if内部,往往是对条件的判别,例如 isna, ismatrix, isnumeric等等,或者对大小的比较,如,if(x > 0), if(x == 1), if(length(x)== 3)等等。if后面,如果是1行,则花括号可以省略,否则就必须要将所有的语句都放在花括号中。这和循环是一致的。

例子:

## if与条件判断

funtest <- function(a, b, method = "add"){

if(method == "add") { ## 如果if或者for/while;

res <- a + b ## 等后面的语句只有一行,则无需使用花括号。

}

if(method == "subtract"){

res <- a - b

}

return(res) ## 返回值

}

### 检验结果

funtest(a = 10, b = 8, method = "add")

funtest(a = 10, b = 8, method = "substract")

“+”标示语句没有闭合,比如在循环中,在分支中,或者写函数等,分多行都会有加号;

直接键盘按Esc键退出就可以把+号去掉,恢复正常的编辑状态。清屏用快捷键Ctrl+L 就可以清除所有编辑的语句。

例如;

td<-function(fx,a,b,r){ #(fx:是表达式,方程是fx=0,变量是dux;a,b,区间[a,b],r是精度。

x<-a;da<-eval(fx);

调用函数:

fx<-expression(xx-x-1);

a<-1;b<-2;r<-1e-5;

td(fx,a,b,r);

扩展资料:

R语言有程序的控制结构和函数function。尽管R语言是解释型语言,但是可以用编译的方式实现,调用方法是source(fileR)命令。R语言的软件包能在编程环境中,通过子菜单下载后安装,因此是无障碍的。

程序中加载软件包的命令,

>library(parallel) #并行计算软件包,单线程多核

查找软件包中所有函数,

>library(help=parallel)

>help(packet=parallel)

R语言和解释型语言一样,没有变量声明。R语言能编写c++程序,应用Rcpp软件包。

-R语言编程

function factorial(n){ return n > 1 n factorial(n-1) : 1;}factorial(5);//120 以上函数可以求简单的n的阶乘 由于使用的是原生的乘法,所以计算范围有限主要使用了递归的方式进行计算,是求阶乘的常用方法之一

最简单的方法就是每次引用时把写好的函数复制一下,到R console 中,然后写其他的。然后,编好的函数写成r 文件,下次直接使用命令 source(functionr)就能导入使用了。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/12163704.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-21
下一篇 2023-05-21

发表评论

登录后才能评论

评论列表(0条)

保存