2012-01-06 36 views
19

我正在瀏覽一個利用該包的包和腳本,並希望識別外部依賴關係。目標是修改腳本以指定library(pkgName)並修改程序包中的函數以使用require(pkgName),這樣以後這些依賴關係將更加明顯。識別R函數和腳本的依賴關係

我正在修改代碼以解釋每個外部依賴包。作爲一個例子,雖然它不是確定性的,但我現在發現很難確定依賴於data.table的代碼。我可以Matrixggplot2bigmemoryplyr,或許多其他包代替data.table,所以隨時與基於其他包的例子來回答。

這個搜索並不是特別容易。到目前爲止,我已經試過的方法主要有:

  • 搜索代碼爲libraryrequire聲明
  • 搜索提到的data.table(例如library(data.table)
  • 嘗試運行codetools::checkUsage,以確定可能存在一些問題。對於腳本,我的程序將腳本插入到本地函數中,並將checkUsage應用於該函數。否則,我使用checkUsagePackage作爲包裝。
  • 查找陳述,有些獨特的data.table,如:=
  • 查找那裏對象的類可以通過匈牙利命名法來識別,如DT

我搜索的本質是發現:

裝載 data.table
  • 對象與名稱表明它們是data.table對象,
  • 似乎是data.table的方法 - 特定

這樣做的唯一一件容易的似乎是找到所在的包被加載。不幸的是,並不是所有的函數都可能顯式加載或需要外部包 - 這些可能會認爲它已經被加載。這是一個不好的做法,我正在努力解決它。但是,搜索對象和方法似乎具有挑戰性。

這(data.table)只是其中的一個包,一個什麼似乎是有限的,有點獨特的用法。假設我想尋找的ggplot功能用途,其中的選項也越來越廣泛,而且語法的文字是不是特質(即+頻繁使用不是特質,而:=好像是)。

我不認爲靜態分析會給出完美的答案,例如,可以將一個參數傳遞給一個函數,該函數指定要加載的包。儘管如此:是否有任何核心工具或軟件包可以通過靜態或動態分析來改進這種強力方法?

對於它的價值,只tools::pkgDepends在封裝級,而不是函數或腳本的水平,這是我在工作層面解決的依賴。


更新1:一個動態的分析工具,應該工作的一個例子是一個,報告哪些包代碼執行期間被加載。但我不知道R中是否有這樣的能力 - 它會像Rprof報告search()的輸出而不是代碼堆棧。

+3

你可以嘗試包'mvbutils''' foodweb'嗎?我自己沒有經驗,但對我來說似乎很有前景(除了我不知道它搜索到多深)。就像'foodweb(where ='package:data.table',prune ='function_youre_examining')''? – 2012-01-07 01:00:37

+0

@ mathematical.coffee這非常有趣。它看起來是非常有用的內部包裝;我還不清楚它可以做什麼,但我會給它一個旋轉,謝謝! – Iterator 2012-01-07 04:00:18

+0

@ mathematical.coffee這非常有趣。我正在進一步阻止它。你可以發表你的評論作爲答案?我可以幫助將它編輯成解決方案,假設我能夠實現它。我以前評論說,它似乎並沒有跨軟件包工作,但這是不正確的。 「where」參數似乎在管理搜索空間方面起到了訣竅的作用。順便說一下,對於changed.funs的幫助幾乎和我最近的一些經歷一樣。 :) – Iterator 2012-01-07 04:41:47

回答

13

首先,感謝@ mathematicalcoffee讓我走上了使用Mark Bravington的mvbutils包的道路。 foodweb功能更令人滿意。回顧一下,我想知道關於檢查一個軟件包,比如說myPackage與另一個軟件包比較,比如說externalPackage,以及關於檢查腳本與externalPackage。我將演示如何做每個。在這種情況下,外部包是data.table

1:對於myPackagedata.table,以下命令足夠了:

library(mvbutils) 
library(myPackage) 
library(data.table) 
ixWhere <- match(c("myPackage","data.table"), search()) 
foodweb(where = ixWhere, prune = ls("package:data.table"), descendents = FALSE) 

這產生優異的曲線圖,其功能取決於功能data.table。儘管該圖包含data.table範圍內的相關性,但它並不過於繁瑣:我可以輕鬆查看哪些函數取決於data.table以及它們使用哪些函數,如as.data.tabledata.table:=,key等。在這一點上,可以說包依賴問題已經解決,但foodweb提供了更多,所以讓我們來看看。很酷的部分是依賴矩陣。

depMat <- foodweb(where = ixWhere, prune = ls("package:data.table"), descendents = FALSE, plotting = FALSE) 
ix_sel <- grep("^myPackage.",rownames(depMat)) 
depMat <- depMat[ix_sel,] 
depMat <- depMat[,-ix_sel] 
ix_drop <- which(colSums(depMat) == 0) 
depMat <- depMat[,-ix_drop] 
ix_drop <- which(rowSums(depMat) == 0) 
depMat <- depMat[-ix_drop,] 

這很酷:它現在顯示函數在我的包中的依賴關係,其中我使用了冗長的名稱,例如, myPackage.cleanData,功能不是 在我的包中,即功能在data.table,並且它消除了沒有依賴關係的行和列。這很簡潔,可以讓我快速調查依賴關係,並且通過處理rownames(depMat),我也可以輕鬆地爲我的功能找到補充集。

注意:plotting = FALSE似乎並不妨礙創建繪圖設備,至少第一次在調用序列中調用foodweb。這很煩人,但並不可怕。也許我做錯了什麼。

2:對於腳本與data.table,這會變得更有趣一些。對於每個腳本,我需要創建一個臨時函數,然後檢查依賴關係。我在下面有一個小功能,就是這麼做的。

listFiles <- dir(pattern = "myScript*.r") 
checkScriptDependencies <- function(fname){ 
    require(mvbutils) 
    rawCode <- readLines(fname) 
    toParse <- paste("localFunc <- function(){", paste(rawCode, sep = "\n", collapse = "\n"), "}", sep = "\n", collapse = "") 
    newFunc <- eval(parse(text = toParse)) 
    ix  <- match("data.table",search()) 
    vecPrune <- c("localFunc", ls("package:data.table")) 
    tmpRes <- foodweb(where = c(environment(),ix), prune = vecPrune, plotting = FALSE) 
    tmpMat <- tmpRes$funmat 
    tmpVec <- tmpMat["localFunc",] 
    return(tmpVec) 
} 

listDeps <- list() 
for(selFile in listFiles){ 
    listDeps[[selFile]] <- checkScriptDependencies(selFile) 
} 

現在,我只需要看看listDeps,和我有同樣的,我從上面的depMat有精彩的小見解。我從其他代碼修改了checkScriptDependencies,這些代碼發送了要由codetools::checkUsage分析的腳本;有這樣一個小功能來分析獨立代碼是很好的。感謝@Spacedman@Tommy的洞察力,改善了對foodweb的調用,使用environment()

(真正的hungaRians會注意到我與名稱和類型的順序不一致 - tooBad。:)有更長的理由,但這不完全是我使用的代碼。)


雖然我還沒有張貼foodweb我的代碼生成的圖形的圖片,你可以在http://web.archive.org/web/20120413190726/http://www.sigmafield.org/2010/09/21/r-function-of-the-day-foodweb看到一些很好的例子。在我的情況下,其輸出明確捕獲了數據表的使用:=J,以及標準的命名函數,如keyas.data.table。它似乎消除了我的文本搜索,並且在幾個方面有所改進(例如,查找我忽略的功能)。

總而言之,foodweb是一個很好的工具,我鼓勵其他人去探索mvbutils包和一些Mark Bravington的其他不錯的包,比如debug。如果你確實安裝了mvbutils,只需要檢查?changed.funs,如果你認爲只有你努力管理不斷髮展的R代碼。 :)