在r中看函數源代碼:
在R中,代碼能夠分爲以下幾個級別:
首先,是你輸入了函數對象名稱,你能夠直接看到代碼的,如要得到函數對象fivenum的代碼,就只須要在Console中鍵入函數對象名稱fivenum就能夠獲得以下結果:
function (x, na.rm = TRUE)
{
xna <- is.na(x)
if (na.rm)
x <- x[!xna]
else if (any(xna))
return(rep.int(NA, 5))
x <- sort(x)
n <- length(x)
if (n == 0)
rep.int(NA, 5)
else {
n4 <- floor((n + 3)/2)/2
d <- c(1, n4, (n + 1)/2, n + 1 - n4, n)
0.5 * (x[floor(d)] + x[ceiling(d)])
}
}
<environment: namespace:stats>
從上面的例子能夠看出,這類函數對象的代碼是最容易看到的,也是咱們學習的最好的材料了,而R中最大多數的函數對象是以這種方式出現的。
其次,咱們在輸入mean這類函數名次的時候,會出現以下結果:
function (x, ...)
UseMethod("mean")
<environment: namespace:base>
這表示函數做者把函數「封」起來了。這個時候咱們能夠先試一試methods(mean),利用methods函數看看mean這個函數都有哪些類型的,咱們獲得的結果以下:
[1] mean.data.frame mean.Date mean.default mean.difftime mean.POSIXct mean.POSIXlt
其實對此能夠有一個簡單的理解,雖然不夠精確。由於在R中,mean函數能夠求得屬於不一樣類型對象的平均值,而不一樣類型對象平均值的求法仍是有一些小小差 異的,好比說求一個向量的平均值和求一個數據框的平均值就有所差別,就要編寫多個mean函數,而後「封」起來,以一個統一的mean出現,方便咱們使 用。這正好也反映了R有一種相似泛型編程語言的性質。
既然咱們已經知道mean中還有這麼多種類,咱們能夠輸入mean.default試一試就能夠獲得:
function (x, trim = 0, na.rm = FALSE, ...)
{
if (!is.numeric(x) && !is.complex(x) && !is.logical(x)) {
warning("argument is not numeric or logical: returning NA")
return(as.numeric(NA))
}
if (na.rm)
x <- x[!is.na(x)]
trim <- trim[1]
n <- length(x)
if (trim > 0 && n > 0) {
if (is.complex(x))
stop("trimmed means are not defined for complex data")
if (trim >= 0.5)
return(stats::median(x, na.rm = FALSE))
lo <- floor(n * trim) + 1
hi <- n + 1 - lo
x <- sort.int(x, partial = unique(c(lo, hi)))[lo:hi]
n <- hi - lo + 1
}
.Internal(mean(x))
}
<environment: namespace:base>
一樣就能夠獲得mean.data.frame、mean.Date、mean.difftime、mean.POSIXct、mean.POSIXlt 的具體內容了。值得注意的是,在R中,出現有多個一樣近似功能的函數封裝爲一個函數的時候(這時候在函數中多半會出現相似UseMethod函數使用的情 況),咱們不妨先輸入mean.default試一試。這種形式的函數在R中通常做爲默認的函數表示。
第三,這是一種特殊的狀況,有人認爲應該和第二種是一類,可是我仍是要提出來單獨歸類。在這種狀況也和第二種的緣由有些相似,但並非徹底一致。
也許咱們你們都很熟悉plot函數了吧,輸入函數名plot的時候,咱們會獲得以下結果:
function (x, y, ...)
{
if (is.null(attr(x, "class")) && is.function(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)
plot.function(x, y, ...)
else plot.function(x, y, ylab = paste(deparse(substitute(x)),
"(x)"), ...)
}
else UseMethod("plot")
}
<environment: namespace:graphics>
請注意plot函數中也出現了UseMethod這個函數,可是和mean不一樣的是,前面有至關多的語句用於處理其餘一些事情。這個時候,咱們也使用methods(plot)來看看,獲得以下結果:
plot.acf* plot.data.frame* plot.Date* plot.decomposed.ts* plot.default
plot.dendrogram* plot.density plot.ecdf plot.factor* plot.formula*
plot.hclust* plot.histogram* plot.HoltWinters* plot.isoreg* plot.lm
plot.medpolish* plot.mlm plot.POSIXct* plot.POSIXlt* plot.ppr*
plot.prcomp* plot.princomp* plot.profile.nls* plot.spec plot.spec.coherency
plot.spec.phase plot.stepfun plot.stl* plot.table* plot.ts
plot.tskernel* plot.TukeyHSD
不看不知道,一看嚇一跳,還覺得咱們輸入plot的輸出就是函數自己,結果也許不是如此。可能有人已經理解了,其實最後的UseMethod函數實在默認 的調用plot.default函數,趕快再看看plot.default函數吧,發現它再調用plot.xy函數,再看看plot.xy函數,再 plot.xy函數中調用了一個.Internal(plot.xy(xy, type, pch, lty, col, bg, cex, lwd, ...))函數,也許這就是真正起做用的函數了吧。思路基本上就是如此了,是否這個時候您能夠得到一些閱讀查找R函數內容的樂趣。
除了直接輸入FUN.default形式外,還可使用getS3method(FUN,"default")來得到代碼。這樣就解決了絕大多數函數代碼查看的工做了。
在第二種狀況種,咱們說了通常能夠經過FUN.default得到想要的結果。可是隻有稱爲generic的函數纔有這種「特權」。而lm等則沒有,不過咱們也能夠嘗試使用methods(lm)來看看結果如何,發現:
[1] lm.fit lm.fit.null lm.influence lm.wfit lm.wfit.null
Warning message:
function 'lm' appears not to be generic in: methods(lm)
出現了警告信息,表示說lm不是泛型函數,可是仍是給出告終果lm.fit等,大體上能夠當作是和lm相關的系列函數吧。這樣子就出現了有趣的局面,好比說既有plot.ts,也有ts.plot。
依照第三種狀況,咱們發現居然有的函數用星號標識了的,好比plot.stl*等,當咱們輸入plot.stl,甚至是plot.stl*的時候都會給出 要麼找不到這個對象,要麼乾脆是代碼錯誤的信息。原來凡是用了*標識的函數,都是隱藏起來的函數,估計是怕被人看見(其實這是玩笑話)!咱們要看這些函數 的代碼,咱們該怎麼辦呢?其實也很容易,使用功能強大的getAnywhere(FUN),看看這個函數的名稱,就能夠猜測到它的功能估計是很強大的, Anywhere的內容均可以找到!getAnywhere(plot.stl)的結果以下:
A single object matching 'plot.stl' 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), set.pars = list(mar = c(0,
6, 0, 6), oma = c(6, 0, 4, 0), tck = -0.01, mfrow = c(nplot,
1)), main = NULL, range.bars = TRUE, ..., col.range = "light gray")
{
sers <- x$time.series
ncomp <- ncol(sers)
data <- drop(sers %*% rep(1, ncomp))
X <- cbind(data, sers)
colnames(X) <- c("data", colnames(sers))
nplot <- ncomp + 1
if (range.bars)
mx <- min(apply(rx <- apply(X, 2, range), 2, diff))
if (length(set.pars)) {
oldpar <- do.call("par", as.list(names(set.pars)))
on.exit(par(oldpar))
do.call("par", set.pars)
}
for (i in 1:nplot) {
plot(X[, i], type = if (i < nplot)
"l"
else "h", xlab = "", ylab = "", axes = FALSE, ...)
if (range.bars) {
dx <- 1/64 * diff(ux <- par("usr")[1:2])
y <- mean(rx[, i])
rect(ux[2] - dx, y + mx/2, ux[2] - 0.4 * dx, y -
mx/2, col = col.range, xpd = TRUE)
}
if (i == 1 && !is.null(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,看看都有些什麼內容。算是一個比較「霸道」的函數。
在上面plot.xy函數中,咱們還能夠看到.Internal這個函數,相似的也許還能夠看到.Primitive、.External、.Call等 函數這就和R系統內部工做方式和與外部接口的定義有關了,若是對這些函數有興趣的話,就要學習組成R系統的源代碼了。
最後,若是真的想閱讀組成R系統自己的源代碼,在各個CRAN中均有下載。你能夠獲得組成R系統所須要的材料。其中不少C語言(還有就是F)的源代碼,均 是精心挑選過的算法,哪怕就是想學從頭至尾編寫具體的算法,也是學習的好材料。同時,你能夠看到R系統內部是如何構成的,理解了這些對於高效使用R有相當 重要的做用。這個範疇的材料就要着重看一看R-Lang和R-inits了。
至此,R中閱讀代碼的內容就依照個人理解介紹了一下。隨後將有一些R代碼示例的分析註解、語言自己、R應用的和行業使用的材料翻譯和具體例子說明。歡迎你們多多和我交流,一塊兒進步。 編程