作者celestialgod (天)
看板R_Language
标题Re: [问题] 使用套件中的指令时,能看到原始码吗?
时间Thu Oct 15 17:33:47 2015
回一篇有点久的文章
我最近在advanced R 看到pryr的使用 可以看到c source code
就想说分享一下,刚好有这篇,就直接在这篇上延伸了
1. 找function对应的套件以及source code
getAnywhere 可以帮助你把很多东西找到
像是 我输入 getAnywhere('lm')
会跑出这样的讯息:
A single object matching ‘lm’ was found
It was found in the following places
package:stats
namespace:stats
with value
function (formula, data, subset, weights, na.action, method = "qr",
model = TRUE, x = FALSE, y = FALSE, qr = TRUE, singular.ok = TRUE,
contrasts = NULL, offset, ...)
{
blah blah
我就可以直接在里面看到程式了
但是在里头的子程式呢?
一样透过getAnywhere可以办到
像是你可以在lm的source code看到
lm.fit(x, y, offset = offset, singular.ok = singular.ok, ...)
或是
lm.wfit(x, y, w, offset = offset, singular.ok = singular.ok, ...)
这时候 你一样输入 getAnywhere('lm.wfit')
你就可以看到对应的code了
你可以会想说很多人都会教我直接打function name
那样不是比较快,不用多记一个函数
但是有些函数 你没有输入对应的namespace从里面找是不会跑出来的
举例来说:
library(plyr)
splitter_d # you will get nothing
getAnywhere('splitter_d') # you will see the following information
A single object matching ‘splitter_d’ was found
It was found in the following places
namespace:plyr
with value
function (data, .variables = NULL, drop = TRUE)
{
blah blah
在多数情况下,这种方式比较简单方便
你也不用去查说你要找的函数在哪一个package里头
提到同名含数於不同package的情况
就还要提到getAnywhere的好处
有用dplyr的人 都知道在载入dplyr时会跑出这个
Attaching package: ‘dplyr’
The following objects are masked from ‘package:stats’:
filter, lag
The following objects are masked from ‘package:base’:
intersect, setdiff, setequal, union
这意思就是 package:stats里头有函数也叫做filter跟lag (下面那行同理)
dplyr的载入,会把同名函数盖过去
这时候dplyr:::lag就取代了stats:::lag
你在使用时,除非你特别注明是用stats:::lag
否则都会使用dplyr:::lag
有点离题,回到getAnywhere
我们透过getAnywhere还可以查到不同package的同名函数有哪些
输入 getAnywhere('lag') 会看到下列讯息
2 differing objects matching ‘lag’ were found
in the following places
package:dplyr
package:stats
你就知道lag有两个套件同时都有
而且你如果要看source code可以透过 []来看
getAnywhere('lag')[1]会跳出 dplyr的
而 getAnywhere('lag')[2]会跳出 stats的
顺序就跟你getAnywhere出现的一样
2. .C, .Call, .Fortran那些是什麽
如果常看source code的话
会发现R function里面 会出现
.C, .Call, .Fortran, .External, .Internal, or .Primitive
这几种,这些都是已经被编译(compile)过了,然後直接载入到R session中
而透过 pryr:::show_c_source 你可以看到 .Internal, or .Primitive
例如,输入 getAnywhere('+')
你会得到下列资讯
A single object matching ‘+’ was found
It was found in the following places
package:base
namespace:base
with value
function (e1, e2) .Primitive("+")
这时候用pryr就可以看到 "+"的c source code
library(pryr)
show_c_source(.Primitive("+"))
然後会跳出 + is implemented by do_arith with op = PLUSOP
告诉你 + 是透过do_arith执行的
同时连到一个github的网站
然後给你两个搜寻结果
1. wch/r-source – arithmetic.c
2. wch/r-source – names.c
你可以看到在第一个里面会看到 do_arith这个关键字被反白了
点arithmetic.c进去看看 就可以找到下面这个:
(快一点的方法就直接CTRL+F 输入do_arith <- 你可以再R视窗里面看到这个名字)
SEXP attribute_hidden do_arith(SEXP call, SEXP op, SEXP args, SEXP env)
{
SEXP ans, arg1, arg2;
int argc;
if (args == R_NilValue)
argc = 0;
else if (CDR(args) == R_NilValue)
argc = 1;
else if (CDDR(args) == R_NilValue)
argc = 2;
else
argc = length(args);
arg1 = CAR(args);
arg2 = CADR(args);
blah blah
让我们再换一个例子
输入 getAnywhere('table')
在最後几行的地方,你会看到
y <- array(tabulate(bin, pd), dims, dimnames = dn)
我们在一次 getAnywhere('tabulate')
就会发现 我们找到 .Internal了
在最後一行的地方 .Internal(tabulate(bin, nbins))
透过pryr的show_c_source(.Internal(tabulate(bin, nbins)))
一样会连到一个网页
给你两个搜寻结果
1. wch/r-source – util.c
2. wch/r-source – names.c
你可以在第一个结果里面看到 do_tabulate 被反白了
所以你可以点进去 然後CTRL+F搜寻 do_tabulate
(记得点util.c 点前面是连到该套件的github位置)
就可以跟我一样看到
SEXP attribute_hidden do_tabulate(SEXP call, SEXP op, SEXP args, SEXP rho)
{
checkArity(op, args);
SEXP in = CAR(args), nbin = CADR(args);
if (TYPEOF(in) != INTSXP) error("invalid input");
R_xlen_t n = XLENGTH(in);
/* FIXME: could in principle be a long vector */
int nb = asInteger(nbin);
if (nb == NA_INTEGER || nb < 0)
error(_("invalid '%s' argument"), "nbin");
SEXP ans = allocVector(INTSXP, nb);
int *x = INTEGER(in), *y = INTEGER(ans);
if (nb) memset(y, 0, nb * sizeof(int));
for(R_xlen_t i = 0 ; i < n ; i++)
if (x[i] != NA_INTEGER && x[i] > 0 && x[i] <= nb) y[x[i] - 1]++;
return ans;
}
3. UseMethods是什麽
你可以在getAnywhere('predict')中发现它
提到methods,就会比较复杂一点了,在耐着点性子看完吧~~
R也有所谓的object-oriented system (以下简称 OO system)
OO应该很多人会在C++里面看到
就是我可以定义 class (类别)
然後去定义 对应的 methods (方法)
在透过 class 创立 objects 去使用这些方法
这样可以达到code 重新再利用的功能
也可以避免过多的输入判定的问题 以及
要重复创见各种不同名字的function以对应不同的情况
(OO的好处 我只有大概的概念,更详细可能请其他大大补充)
可以直接透过对应的class
举例来说 predict可以用在各式各样的model结果
就是透过class来决定input是谁
getAnywhere('predict') 会出现 UseMethod("predict")
我们可以来看看lm出来物件的class是什麽
x <- rnorm(100)
y <- 1 + 2 * x + rnorm(100)
fit <- lm(y ~ x)
class(fit) # 透过这个check fit的class
# [1] "lm"
你就会看到fit具有lm class
这时候就可以看predict运用於lm时的方法了
用 function name 然後 加上一个 . 再加上class的名字通常就可以看到source code
其他情况,我等等在补充
输入 getAnywhere('predict.lm') 就会看到下列资讯
A single object matching ‘predict.lm’ was found
It was found in the following places
package:stats
registered S3 method for predict from namespace stats
namespace:stats
with value
function (object, newdata, se.fit = FALSE, scale = NULL, df = Inf,
interval = c("none", "confidence", "prediction"), level = 0.95,
type = c("response", "terms"), terms = NULL, na.action = na.pass,
pred.var = res.var/weights, weights = 1, ...)
{
blah blah
同理可证,试试看找出glm出来的物件class然後再找predict看看
再来,我们试试看 fitted这个函数
输入 getAnywhere('fitted')
你会看到他一样有 UseMethod
A single object matching ‘fitted’ was found
It was found in the following places
package:stats
namespace:stats
with value
function (object, ...)
UseMethod("fitted")
<bytecode: 0x0000000014eea978>
<environment: namespace:stats>
你输入getAnywhere('fitted.lm')
会得到no object named ‘fitted.lm’ was found
那这样是不是就看不到fitted.lm的source code了?
答案:不是,其实有时候他会有预设方法
可以让很多东西都透过预设方法就好
我就不用独立写一个对应的方法了
因此,你可以先用methods来确定他是不是有预设方法
输入 methods('fitted') 会看到就有fitted.default了
然後没有对应lm的方法,因此fitted(fit)就会用default的方法了
methods('fitted')
[1] fitted.default* fitted.isoreg* fitted.kmeans*
fitted.nls* fitted.smooth.spline*
最後输入 getAnywhere('fitted.default')
就可以看到fitted怎麽样把lm的fitted value叫出来
A single object matching ‘fitted.default’ was found
It was found in the following places
registered S3 method for fitted from namespace stats
namespace:stats
with value
function (object, ...)
{
xx <- if ("fitted.values" %in% names(object))
object$fitted.values
else object$fitted
napredict(object$na.action, xx)
}
<bytecode: 0x0000000017242a58>
<environment: namespace:stats>
然後,R的OO system不只有我们看到的这个
我们现在看到的是所谓的S3,其他还有S4, Reference classes (RC)等
那S4跟RC就请移驾到advanced R的网站一窥究竟吧
连结:
http://adv-r.had.co.nz/OO-essentials.html
S4跟RC都有对应找方法的函数也可以透过getAnywhere去看source code
像是最常看到的S4就是Matrix这个套件
你也同样可以getAnywhere('Matrix') 看到下列资讯
A single object matching ‘Matrix’ was found
It was found in the following places
package:Matrix
namespace:Matrix
with value
function (data = NA, nrow = 1, ncol = 1, byrow = FALSE, dimnames = NULL,
sparse = NULL, doDiag = TRUE, forceCheck = FALSE)
{
blah blah
然後
没了
谢谢您的欣赏XDD
: [问题叙述]:
: 各位前辈好,之前有在版上询问过如何透过R产生作假的答题反应。
: 这次问的感觉是一个更没有sense的问题,就是如标题所示:
: 我们在启用package中的指令,帮我们估计时,
: 有办法看到当初开法者所撰写的语法吗?如估算的公式是怎麽写的.....
: 有问过系上的学长,他说套件的网址通常都会有相关资讯,
: 但无奈不晓得是我眼残,就是找不到。
: 之所以想知道,是想了解公式这麽写的,以及有时候会需要适当修改。
: 麻烦前辈提供相关资讯了,谢谢~
--
※ 发信站: 批踢踢实业坊(ptt.cc), 来自: 140.109.73.190
※ 文章网址: https://webptt.com/cn.aspx?n=bbs/R_Language/M.1444901630.A.479.html
1F:推 cywhale: pryr is amazing.. Very useful~ Thanks for sharing ^^ 10/15 21:46