Re: [問題] 使用套件中的指令時,能看到原始碼嗎?
回一篇有點久的文章
我最近在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://www.ptt.cc/bbs/R_Language/M.1444901630.A.479.html
推
10/15 21:46, , 1F
10/15 21:46, 1F
討論串 (同標題文章)
本文引述了以下文章的的內容:
完整討論串 (本文為第 3 之 3 篇):
R_Language 近期熱門文章
PTT數位生活區 即時熱門文章