studio programming org language itam r function r-faq

programming - r studio



¿Cómo puedo ver el código fuente de una función? (9)

Además de las otras respuestas a esta pregunta y sus duplicados, aquí hay una buena manera de obtener el código fuente para una función de paquete sin necesidad de saber en qué paquete se encuentra. Por ejemplo, si queremos la fuente para randomForest::rfcv() :

Para verlo / editarlo en una ventana emergente:

edit(getAnywhere(''rfcv''), file=''source_rfcv.r'')

Para redirigir a un archivo separado :

capture.output(getAnywhere(''rfcv''), file=''source_rfcv.r'')

Quiero ver el código fuente de una función para ver cómo funciona. Sé que puedo imprimir una función escribiendo su nombre en el indicador:

> t function (x) UseMethod("t") <bytecode: 0x2332948> <environment: namespace:base>

En este caso, ¿qué significa UseMethod("t") ? ¿Cómo puedo encontrar el código fuente que realmente está utilizando, por ejemplo: t(1:10) ?

¿Hay una diferencia entre cuando veo UseMethod y cuando veo standardGeneric y showMethods , como with ?

> with standardGeneric for "with" defined from package "base" function (data, expr, ...) standardGeneric("with") <bytecode: 0x102fb3fc0> <environment: 0x102fab988> Methods may be defined for arguments: data Use showMethods("with") for currently available ones.

En otros casos, puedo ver que se están llamando las funciones R, pero no puedo encontrar el código fuente de esas funciones.

> ts.union function (..., dframe = FALSE) .cbind.ts(list(...), .makeNamesTs(...), dframe = dframe, union = TRUE) <bytecode: 0x36fbf88> <environment: namespace:stats> > .cbindts Error: object ''.cbindts'' not found > .makeNamesTs Error: object ''.makeNamesTs'' not found

¿Cómo encuentro funciones como .cbindts y .makeNamesTs ?

En otros casos, hay un poco de código R, pero la mayor parte del trabajo parece realizarse en otro lugar.

> matrix function (data = NA, nrow = 1, ncol = 1, byrow = FALSE, dimnames = NULL) { if (is.object(data) || !is.atomic(data)) data <- as.vector(data) .Internal(matrix(data, nrow, ncol, byrow, dimnames, missing(nrow), missing(ncol))) } <bytecode: 0x134bd10> <environment: namespace:base> > .Internal function (call) .Primitive(".Internal") > .Primitive function (name) .Primitive(".Primitive")

¿Cómo puedo saber qué hace la función .Primitive ? De manera similar, algunas funciones llaman .C , .Call , .Fortran , .External o .Internal . ¿Cómo puedo encontrar el código fuente de esos?


Hay una función muy útil en la edit R

new_optim <- edit(optim)

optim el código fuente de optim utilizando el editor especificado en las options de R, y luego podrá editarlo y asignar la función modificada a new_optim . Me gusta mucho esta función para ver el código o para depurar el código, por ejemplo, imprimir algunos mensajes o variables o incluso asignarlos a una variable global para una mayor investigación (por supuesto, puede usar la debug ).

Si solo desea ver el código fuente y no quiere que se imprima el código fuente largo y molesto en su consola, puede usar

invisible(edit(optim))

Claramente, esto no se puede usar para ver el código fuente de C / C ++ o Fortran.

Por cierto, la edit puede abrir otros objetos como lista, matriz, etc., que luego muestra la estructura de datos con atributos también. La función de puede usarse para abrir un editor de Excel (si la GUI lo admite) para modificar la matriz o el marco de datos y devolver el nuevo. Esto es útil a veces, pero debe evitarse en el caso habitual, especialmente cuando la matriz es grande.


No vi cómo esto encajaba en el flujo de la respuesta principal, pero me dejó perplejo por un tiempo, así que lo estoy agregando aquí:

Operadores Infix

Para ver el código fuente de algunos operadores de infijo base (por ejemplo, %% , %*% , %in% ), use getAnywhere , por ejemplo:

getAnywhere("%%") # A single object matching ‘%%’ was found # It was found in the following places # package:base # namespace:base # with value # # function (e1, e2) .Primitive("%%")

La respuesta principal cubre cómo usar espejos para profundizar.


Para funciones no primitivas, R base incluye una función llamada body() que devuelve el cuerpo de función. Por ejemplo, la fuente de la función print.Date() se puede ver:

body(print.Date)

producirá esto:

{ if (is.null(max)) max <- getOption("max.print", 9999L) if (max < length(x)) { print(format(x[seq_len(max)]), max = max, ...) cat(" [ reached getOption(/"max.print/") -- omitted", length(x) - max, "entries ]/n") } else print(format(x), max = max, ...) invisible(x) }

Si está trabajando en un script y desea el código de función como un vector de caracteres, puede obtenerlo.

capture.output(print(body(print.Date)))

te conseguirá:

[1] "{" [2] " if (is.null(max)) " [3] " max <- getOption(/"max.print/", 9999L)" [4] " if (max < length(x)) {" [5] " print(format(x[seq_len(max)]), max = max, ...)" [6] " cat(/" [ reached getOption(///"max.print///") -- omitted/", " [7] " length(x) - max, /"entries ]//n/")" [8] " }" [9] " else print(format(x), max = max, ...)" [10] " invisible(x)" [11] "}"

¿Por qué querría hacer tal cosa? Estaba creando un objeto S3 personalizado ( x , donde class(x) = "foo" ) basado en una lista. Uno de los miembros de la lista (llamado "fun") era una función y quería que print.foo() mostrara el código fuente de la función, con sangría. Así que terminé con el siguiente fragmento en print.foo() :

sourceVector = capture.output(print(body(x[["fun"]]))) cat(paste0(" ", sourceVector, "/n"))

que sangra y muestra el código asociado con x[["fun"]] .


Se revela cuando se depura utilizando la función debug (). Supongamos que desea ver el código subyacente en la función de transposición t (). Simplemente escribiendo ''t'', no revela mucho.

>t function (x) UseMethod("t") <bytecode: 0x000000003085c010> <environment: namespace:base>

Pero, utilizando el ''debug (functionName)'', revela el código subyacente, sans los internos.

> debug(t) > t(co2) debugging in: t(co2) debug: UseMethod("t") Browse[2]> debugging in: t.ts(co2) debug: { cl <- oldClass(x) other <- !(cl %in% c("ts", "mts")) class(x) <- if (any(other)) cl[other] attr(x, "tsp") <- NULL t(x) } Browse[3]> debug: cl <- oldClass(x) Browse[3]> debug: other <- !(cl %in% c("ts", "mts")) Browse[3]> debug: class(x) <- if (any(other)) cl[other] Browse[3]> debug: attr(x, "tsp") <- NULL Browse[3]> debug: t(x)

EDIT: debugonce () logra lo mismo sin tener que usar undebug ()


Siempre que la función esté escrita en R puro no C / C ++ / Fortran, se puede usar lo siguiente. De lo contrario, la mejor manera es depurar y usar " saltar a ":

> functionBody(functionName)


También puede intentar usar print.function() , que es genérico de S3, para obtener la función de escritura en la consola.


UseMethod("t") le dice que t() es una función genérica ( S3 ) que tiene métodos para diferentes clases de objetos.

El sistema de despacho del método S3.

Para las clases S3, puede usar la función de methods para enumerar los métodos para una función o clase genérica particular.

> methods(t) [1] t.data.frame t.default t.ts* Non-visible functions are asterisked > methods(class="ts") [1] aggregate.ts as.data.frame.ts cbind.ts* cycle.ts* [5] diffinv.ts* diff.ts kernapply.ts* lines.ts [9] monthplot.ts* na.omit.ts* Ops.ts* plot.ts [13] print.ts time.ts* [<-.ts* [.ts* [17] t.ts* window<-.ts* window.ts* Non-visible functions are asterisked

"Las funciones no visibles tienen un asterisco" significa que la función no se exporta desde el espacio de nombres de su paquete. Aún puede ver su código fuente a través de la función ::: (es decir, stats:::t.ts ), o usando getAnywhere() . getAnywhere() es útil porque no tienes que saber de qué paquete proviene la función.

> getAnywhere(t.ts) A single object matching ‘t.ts’ was found It was found in the following places registered S3 method for t from namespace stats namespace:stats with value function (x) { cl <- oldClass(x) other <- !(cl %in% c("ts", "mts")) class(x) <- if (any(other)) cl[other] attr(x, "tsp") <- NULL t(x) } <bytecode: 0x294e410> <environment: namespace:stats>

El sistema de despacho del método S4.

El sistema S4 es un sistema de envío de métodos más nuevo y es una alternativa al sistema S3. Aquí hay un ejemplo de una función S4:

> library(Matrix) Loading required package: lattice > chol2inv standardGeneric for "chol2inv" defined from package "base" function (x, ...) standardGeneric("chol2inv") <bytecode: 0x000000000eafd790> <environment: 0x000000000eb06f10> Methods may be defined for arguments: x Use showMethods("chol2inv") for currently available ones.

La salida ya ofrece mucha información. standardGeneric es un indicador de una función S4. El método para ver métodos S4 definidos se ofrece de manera útil:

> showMethods(chol2inv) Function: chol2inv (package base) x="ANY" x="CHMfactor" x="denseMatrix" x="diagonalMatrix" x="dtrMatrix" x="sparseMatrix"

getMethod puede usar getMethod para ver el código fuente de uno de los métodos:

> getMethod("chol2inv", "diagonalMatrix") Method Definition: function (x, ...) { chk.s(...) tcrossprod(solve(x)) } <bytecode: 0x000000000ea2cc70> <environment: namespace:Matrix> Signatures: x target "diagonalMatrix" defined "diagonalMatrix"

También hay métodos con firmas más complejas para cada método, por ejemplo

require(raster) showMethods(extract) Function: extract (package raster) x="Raster", y="data.frame" x="Raster", y="Extent" x="Raster", y="matrix" x="Raster", y="SpatialLines" x="Raster", y="SpatialPoints" x="Raster", y="SpatialPolygons" x="Raster", y="vector"

Para ver el código fuente de uno de estos métodos, se debe proporcionar la firma completa, por ejemplo,

getMethod("extract" , signature = c( x = "Raster" , y = "SpatialPolygons") )

No bastará con suministrar la firma parcial.

getMethod("extract",signature="SpatialPolygons") #Error in getMethod("extract", signature = "SpatialPolygons") : # No method found for function "extract" and signature SpatialPolygons

Funciones que llaman funciones no exportadas.

En el caso de ts.union , .cbindts y .makeNamesTs son funciones no .makeNamesTs desde el espacio de nombres de las stats . Puede ver el código fuente de las funciones no getAnywhere utilizando el operador ::: o getAnywhere .

> stats:::.makeNamesTs function (...) { l <- as.list(substitute(list(...)))[-1L] nm <- names(l) fixup <- if (is.null(nm)) seq_along(l) else nm == "" dep <- sapply(l[fixup], function(x) deparse(x)[1L]) if (is.null(nm)) return(dep) if (any(fixup)) nm[fixup] <- dep nm } <bytecode: 0x38140d0> <environment: namespace:stats>

Funciones que llaman código compilado.

Tenga en cuenta que "compilado" no hace referencia al código R compilado en bytes creado por el paquete del compilador . La línea <bytecode: 0x294e410> en la salida anterior indica que la función está compilada en bytes, y aún puede ver la fuente desde la línea de comando R.

Las funciones que llaman a .C , .Call , .Fortran , .External , .Internal o .Primitive están invocando puntos de entrada en el código compilado, por lo que tendrá que mirar las fuentes del código compilado si desea entender completamente la función. This espejo GitHub del código fuente R es un lugar decente para comenzar. La función pryr::show_c_source puede ser una herramienta útil, ya que lo llevará directamente a una página de GitHub para las llamadas .Internal y .Primitive . Los paquetes pueden usar .C , .Call , .Fortran y .External ; pero no .Internal o .Primitive , porque se usan para llamar a las funciones integradas en el intérprete R.

Las llamadas a algunas de las funciones anteriores pueden usar un objeto en lugar de una cadena de caracteres para hacer referencia a la función compilada. En esos casos, el objeto es de la clase "NativeSymbolInfo" , "RegisteredNativeSymbol" , o "NativeSymbol" ; y la impresión del objeto produce información útil. Por ejemplo, optim llama a .External2(C_optimhess, res$par, fn1, gr1, con) (note que es C_optimhess , no "C_optimhess" ). optim está en el paquete de estadísticas, por lo que puede escribir stats:::C_optimhess para ver información sobre la función compilada que se está llamando.

Código compilado en un paquete

Si desea ver el código compilado en un paquete, deberá descargar / descomprimir la fuente del paquete. Los binarios instalados no son suficientes. El código fuente de un paquete está disponible en el mismo repositorio CRAN (o compatible con CRAN) desde el cual se instaló originalmente el paquete. La función download.packages() puede obtener el origen del paquete para usted.

download.packages(pkgs = "Matrix", destdir = ".", type = "source")

Esto descargará la versión de origen del paquete Matrix y guardará el archivo .tar.gz correspondiente en el directorio actual. El código fuente para las funciones compiladas se puede encontrar en el directorio src del archivo sin comprimir y sin tarar. El paso de descomprimir y descomprimir se puede realizar fuera de R , o desde dentro de R usando la función untar() . Es posible combinar el paso de descarga y expansión en una sola llamada (tenga en cuenta que solo un paquete a la vez se puede descargar y descomprimir de esta manera):

untar(download.packages(pkgs = "Matrix", destdir = ".", type = "source")[,2])

Alternativamente, si el desarrollo del paquete se aloja públicamente (por ejemplo, a través de GitHub , R-Forge o RForge.net ), probablemente pueda buscar el código fuente en línea.

Código compilado en un paquete base

Ciertos paquetes se consideran paquetes "base". Estos paquetes se envían con R y su versión está bloqueada a la versión de R. Los ejemplos incluyen base , compiler , stats y utils . Como tales, no están disponibles como paquetes descargables por separado en CRAN como se describe anteriormente. Más bien, forman parte del árbol de origen R en los directorios de paquetes individuales en /src/library/ . La forma de acceder a la fuente R se describe en la siguiente sección.

Código compilado integrado en el intérprete R

Si desea ver el código integrado en el intérprete de R, deberá descargar / descomprimir las fuentes de R; o puede ver las fuentes en línea a través del repositorio R Subversion o el espejo Github de Winston Chang .

El artículo de noticias R de Uwe Ligges (PDF) (pág. 43) es una buena referencia general sobre cómo ver el código fuente de las funciones .Internal y .Primitive . Los pasos básicos son buscar primero el nombre de la función en src/main/names.c y luego buscar el nombre de "entrada C" en los archivos en src/main/* .


View([function_name]) - por ejemplo. View(mean) Asegúrese de usar mayúsculas [V]. El código de solo lectura se abrirá en el editor.