Re: [問題] 使用套件中的指令時,能看到原始碼嗎?

看板R_Language作者 (天)時間9年前 (2015/10/15 17:33), 編輯推噓1(100)
留言1則, 1人參與, 最新討論串3/3 (看更多)
回一篇有點久的文章 我最近在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
pryr is amazing.. Very useful~ Thanks for sharing ^^
10/15 21:46, 1F
文章代碼(AID): #1M7tB-Hv (R_Language)
文章代碼(AID): #1M7tB-Hv (R_Language)