所謂:操千曲而后曉聲,觀千劍而后識(shí)器。
作為一個(gè)開源軟件,R的一個(gè)非常大的優(yōu)點(diǎn)就是我們可以隨意查看所有算法的源代碼,在對這些源代碼進(jìn)行分析的過程中不僅可以加深對算法的認(rèn)識(shí),而且可以大步提高對R語言的掌握程度。如果可以也能根據(jù)自己的需求,對算法進(jìn)行改進(jìn)。不管是從理論的學(xué)習(xí)角度還是實(shí)用的角度,善于閱讀和利用源代碼,能讓我們事半功倍。
當(dāng)然,在開始的開始,你需要知道R函數(shù)是怎樣的一個(gè)結(jié)構(gòu)。也就是說你至少要有一點(diǎn)R的基礎(chǔ),最少吧,你需要一顆上勁的心。本文的末尾給出了R函數(shù)的文章,基本上看看就會(huì)了。我們就不從最基本的什么是函數(shù)這種問題開始了。
- 最直接的方法當(dāng)然是直接鍵入函數(shù)(不加括號(hào)),大部分函數(shù)源代碼就可以直接顯現(xiàn)出來。我以PerformanceAnalytics包中的函數(shù)chart.Correlation()為例。
#install.packages("PerformanceAnalytics") 沒有安裝的安裝一下。
> library(PerformanceAnalytics)
> chart.Correlation
function (R, histogram = TRUE, method = c("pearson", "kendall",
"spearman"), ...)
{
x = checkData(R, method = "matrix")
if (missing(method))
method = method[1]
panel.cor <- function(x, y, digits = 2, prefix = "", use = "pairwise.complete.obs",
method = "pearson", cex.cor, ...) {
usr <- par("usr")
on.exit(par(usr))
par(usr = c(0, 1, 0, 1))
r <- cor(x, y, use = use, method = method)
txt <- format(c(r, 0.123456789), digits = digits)[1]
txt <- paste(prefix, txt, sep = "")
if (missing(cex.cor))
cex <- 0.8/strwidth(txt)
test <- cor.test(as.numeric(x), as.numeric(y), method = method)
Signif <- symnum(test$p.value, corr = FALSE, na = FALSE,
cutpoints = c(0, 0.001, 0.01, 0.05, 0.1, 1), symbols = c("***",
"**", "*", ".", " "))
text(0.5, 0.5, txt, cex = cex * (abs(r) + 0.3)/1.3)
text(0.8, 0.8, Signif, cex = cex, col = 2)
}
f <- function(t) {
dnorm(t, mean = mean(x), sd = sd.xts(x))
}
dotargs <- list(...)
dotargs$method <- NULL
rm(method)
hist.panel = function(x, ... = NULL) {
par(new = TRUE)
hist(x, col = "light gray", probability = TRUE, axes = FALSE,
main = "", breaks = "FD")
lines(density(x, na.rm = TRUE), col = "red", lwd = 1)
rug(x)
}
if (histogram)
pairs(x, gap = 0, lower.panel = panel.smooth, upper.panel = panel.cor,
diag.panel = hist.panel)
else pairs(x, gap = 0, lower.panel = panel.smooth, upper.panel = panel.cor)
}
<bytecode: 0x000000000813e4f0>
<environment: namespace:PerformanceAnalytics>
當(dāng)然呢,在Rstudio里面,我們可以把光標(biāo)放在函數(shù)名上按F2,Rstudio會(huì)打開一個(gè)新的窗口來顯示這個(gè)函數(shù):

優(yōu)點(diǎn):直接簡單。
缺點(diǎn):并非所有的函數(shù)都能通過此方法得到。
原因:R是面向?qū)ο笤O(shè)計(jì)的程序語言。
- 2 用函數(shù)page(),不過,結(jié)果在另一個(gè)窗口顯示,選擇電腦上的程序打開,我的是Notepad++。
> page(chart.Correlation)

- 3 與方法二類似,用函數(shù)edit()。這個(gè)函數(shù)一看就很有喜感,明顯他是允許我們來修改函數(shù)的,這才是開源的真諦啊。修改了直接用。還是以我們這個(gè)函數(shù)為例。我們這個(gè)函數(shù)chart.Correlation是用來展示相關(guān)性的。但是她的參數(shù)很少,滿足不了我的需求。
data(managers)
chart.Correlation(managers[,1:8], histogram=T,pch="+",col="black")
做出來的圖是這樣的:

但是我想把相關(guān)系數(shù)的字體都搞成一致,然后小圓圈的空心點(diǎn)變成“+”,但是pch=這個(gè)參數(shù)不頂用。怎么辦?查看了幫助文檔help(chart.Correlation)也沒有參數(shù)可調(diào),看來修改函數(shù)是一個(gè)不錯(cuò)的選擇了。
于是我就:
> mychart.Correlation<-edit(chart.Correlation)

我把它設(shè)置字體的部分和調(diào)整散點(diǎn)圖形狀的部分稍作了修改,點(diǎn)擊Save,這樣一個(gè)新的函數(shù)mychart.Correlation就生成了?,F(xiàn)在,我用同樣的數(shù)據(jù)和參數(shù)來繪制這個(gè)圖,達(dá)到了我的要求:
data(managers)
mychart.Correlation(managers[,1:8], histogram=T,pch="+",col="black")

修改后的函數(shù)是這樣的:

函數(shù)edit()不僅可以修改包中的函數(shù)作為急用,也可以用來修改自己正在寫的函數(shù),可以說很實(shí)用了在我們寫函數(shù)的時(shí)候。
- 對于計(jì)算方法不同的函數(shù),要用methods()來定義具體的查看對象,如查看函數(shù)mean代碼,用方法一只能查到:
> mean
function (x, ...)
UseMethod("mean")
<bytecode: 0x0000000008c88590>
<environment: namespace:base>
此時(shí)要有methods()來查找mean具體的對象:
methods(mean)
[1] mean.Date mean.default mean.difftime mean.geometric mean.LCL mean.POSIXct mean.POSIXlt mean.stderr mean.UCL
[10] mean.yearmon* mean.yearqtr* mean.zoo*
see '?methods' for accessing help and source code
要查看具體名稱,如mean.default的代碼,直接用代碼
> 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(NA_real_)
}
if (na.rm)
x <- x[!is.na(x)]
if (!is.numeric(trim) || length(trim) != 1L)
stop("'trim' must be numeric of length one")
n <- length(x)
if (trim > 0 && n) {
if (is.complex(x))
stop("trimmed means are not defined for complex data")
if (anyNA(x))
return(NA_real_)
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]
}
.Internal(mean(x))
}
<bytecode: 0x000000000ec0bbc8>
<environment: namespace:base>
- 對于程序包里的函數(shù),需要先調(diào)用函數(shù)所在的包。
2.對于methods()得出的類函數(shù)中帶星號(hào)標(biāo)注的源代碼是看不到的。
3.對于非類函數(shù),不能用此方法。
如chart.Correlation()就不能用這方法:
> methods(chart.Correlation)
no methods found
> chart.Correlation.default
Error: object 'chart.Correlation.default' not found
- methods()得出的類函數(shù)中帶星號(hào)標(biāo)注的源代碼,用函數(shù)getAnywhere(),如查找predict函數(shù)的源代碼。
> methods(predict)
[1] predict.ar* predict.Arima* predict.arima0* predict.glm predict.HoltWinters*
[6] predict.lm predict.loess* predict.mlm* predict.nls* predict.poly*
[11] predict.ppr* predict.prcomp* predict.princomp* predict.smooth.spline* predict.smooth.spline.fit*
[16] predict.StructTS*
see '?methods' for accessing help and source code
> getAnywhere(predict.Arima)
A single object matching ‘predict.Arima’ was found
It was found in the following places
registered S3 method for predict from namespace stats
namespace:stats
with value
function (object, n.ahead = 1L, newxreg = NULL, se.fit = TRUE,
...)
{
myNCOL <- function(x) if (is.null(x))
0
else NCOL(x)
rsd <- object$residuals
xr <- object$call$xreg
xreg <- if (!is.null(xr))
eval.parent(xr)
else NULL
ncxreg <- myNCOL(xreg)
if (myNCOL(newxreg) != ncxreg)
stop("'xreg' and 'newxreg' have different numbers of columns")
class(xreg) <- NULL
xtsp <- tsp(rsd)
n <- length(rsd)
arma <- object$arma
coefs <- object$coef
narma <- sum(arma[1L:4L])
if (length(coefs) > narma) {
if (names(coefs)[narma + 1L] == "intercept") {
xreg <- cbind(intercept = rep(1, n), xreg)
newxreg <- cbind(intercept = rep(1, n.ahead), newxreg)
ncxreg <- ncxreg + 1L
}
xm <- if (narma == 0)
drop(as.matrix(newxreg) %*% coefs)
else drop(as.matrix(newxreg) %*% coefs[-(1L:narma)])
}
else xm <- 0
if (arma[2L] > 0L) {
ma <- coefs[arma[1L] + 1L:arma[2L]]
if (any(Mod(polyroot(c(1, ma))) < 1))
warning("MA part of model is not invertible")
}
if (arma[4L] > 0L) {
ma <- coefs[sum(arma[1L:3L]) + 1L:arma[4L]]
if (any(Mod(polyroot(c(1, ma))) < 1))
warning("seasonal MA part of model is not invertible")
}
z <- KalmanForecast(n.ahead, object$model)
pred <- ts(z[[1L]] + xm, start = xtsp[2L] + deltat(rsd),
frequency = xtsp[3L])
if (se.fit) {
se <- ts(sqrt(z[[2L]] * object$sigma2), start = xtsp[2L] +
deltat(rsd), frequency = xtsp[3L])
list(pred = pred, se = se)
}
else pred
}
<bytecode: 0x0000000016ba2238>
<environment: namespace:stats>
- 直接上CRAN 下載源代碼包
流程如下:
- 直接上CRAN 下載源代碼包
- 登入R主頁 http://www.r-project.org/ ,點(diǎn)擊 Download 下的CRAN;
- 選擇一個(gè)鏡像;
- 里面的Source Code for all Platforms下有各種源碼了,對于程序包,點(diǎn)packages;
- 點(diǎn)選擇項(xiàng)Table of available packages, sorted by name;
- 找到你你想要的包,點(diǎn)擊看Package source這一項(xiàng),用tar.gz封裝的,下載解壓后就能看見源代碼了。
再復(fù)雜的包也是由基本的R函數(shù)構(gòu)成的,所以從基礎(chǔ)學(xué)起總是不錯(cuò)的?;A(chǔ)決定高度。有了這六個(gè)查看R函數(shù)的方法,是不是清楚了很多呢。函數(shù)是完成某項(xiàng)具體任務(wù)的程序,能看R函數(shù),學(xué)習(xí)R就不再是到處粘代碼了也不再是只會(huì)調(diào)參數(shù)了,可以自己定義參數(shù),自己來寫函數(shù)了。
參考:
查看R源代碼的六種方法
怎么才能查看R語言某個(gè)包某函數(shù)源碼?
R查看各函數(shù)的源代碼
查看R函數(shù)源代碼
R語言-函數(shù)源代碼查看
【r<-高級(jí)|理論】R的函數(shù)
第五節(jié) R語言函數(shù)function