2010-07-27 4 views
8

Una pregunta muy simple:caché operaciones costosas en I

estoy escribiendo y pasando mis guiones R usando un editor de texto para que sean reproducibles, como ha sido sugerido por varios miembros del SO.

Este enfoque está funcionando muy bien para mí, pero a veces tienen que realizar operaciones costosas (por ejemplo read.csv o reshape en bases de datos 2M fila) que será mejor que la memoria caché en el entorno R en lugar de volver a ejecutar cada vez que ejecute el script (que generalmente es muchas veces a medida que avanzo y pruebo las nuevas líneas de código).

¿Hay alguna manera de almacenar en caché lo que hace un script hasta cierto punto, por lo que cada vez que ejecuto las líneas de código incrementales (igual que haría ejecutando R de forma interactiva)?

Gracias.

Respuesta

9
## load the file from disk only if it 
## hasn't already been read into a variable 
if(!(exists("mytable")){ 
    mytable=read.csv(...) 
} 

Editar: fija error tipográfico - gracias a Dirk.

+0

gracias chris, pero ¿cómo me aseguro de que la tabla se mantenga en el espacio de trabajo en TextMate (u otro editor)? – Roberto

+3

si está ejecutando de forma no interactiva, use el comando save.image (file = "mydata.Rdata") y guarde su área de trabajo. A continuación, cargue el espacio de trabajo con load() al comienzo de cada ejecución. Todavía habrá algo de molienda involucrado, ya que R necesita volver a poner todos esos datos en la memoria, pero le ahorrará los costosos pasos computacionales. – chrisamiller

+0

Además, considere dejar abierta una sesión R, edite las secuencias de comandos en texto mate, guárdelas y luego cargue el nuevo código en R como lo siguiente: source ("~/pathto/myRscript.R") De esta manera no tiene que recarga datos cada vez. Combine con algunas declaraciones de exists() y acelerará las cosas considerablemente. – chrisamiller

3

Quiero hacer esto también cuando estoy usando Sweave. Sugeriría poner todas sus costosas funciones (cargar y remodelar datos) al comienzo de su código. Ejecute ese código, luego guarde el espacio de trabajo. Luego, comente las costosas funciones y cargue el archivo del área de trabajo con load(). Esto es, por supuesto, más arriesgado si realiza cambios no deseados en el archivo de espacio de trabajo, pero en ese caso, todavía tiene el código en comentarios si desea volver a empezar desde cero.

+0

Jo, gracias por la respuesta. ¿Sabes cómo guardar el espacio de trabajo con TextMate? – Roberto

+0

, pero ¿y si no trabajo en Sweave? – Roberto

+0

el enfoque load() es bueno para usar y no depende de Sweave. –

8

Algunas formas sencillas son factibles con algunas combinaciones de

  • exists("foo") para probar si una variable existe, de lo contrario re-carga o re-cálculo
  • file.info("foo.Rd")$ctime que se puede comparar a Sys.time() y ver si es más nuevo que una cantidad de tiempo dada que puede cargar, de lo contrario volver a calcular.

También hay paquetes de caché en CRAN que pueden ser útiles.

+0

Dirk, pero, ¿no es necesario volver a crear todos los objetos de todos modos cada vez que se vuelve a ejecutar el script? Entonces foo nunca existirá y siempre será recalculado, ¿verdad? – Roberto

+0

Depende. A veces, uno obtiene datos de, por ejemplo, una base de datos que puede ser extensa. Luego puede almacenar esto en un archivo y usar la marca de tiempo (como describí) para ver si necesita o no un nuevo acceso de acceso a Internet. Todo depende de los detalles de su situación. –

3

Sin entrar en demasiados detalles, por lo general siguen uno de tres enfoques:

  1. Uso assign para asignar un nombre único para cada objeto importante a través de mi ejecución. Luego, incluya un if(exists(...)) get(...) en la parte superior de cada función para obtener el valor o, de lo contrario, vuelva a calcularlo. (al igual que la sugerencia de Dirk)
  2. Utilice cacheSweave con mis documentos Sweave. Esto hace todo el trabajo por usted de los cálculos en caché y los recupera automáticamente. Es realmente trivial de usar: simplemente use el controlador cacheSweave y agregue este indicador a cada bloque: <<..., cache=true>>=
  3. Use save y load para guardar el entorno en momentos cruciales, asegurándose de que todos los nombres sean únicos.
4

Después de hacer algo que descubre que es costoso, guarde los resultados de ese costoso paso en un archivo de datos R.

Por ejemplo, si ha cargado un archivo CSV en una trama de datos llamado myVeryLargeDataFrame y luego creó estadísticas de resumen de esa trama de datos en un df llamados VLDFSummary entonces se podría hacer esto:

save(c(myVeryLargeDataFrame, VLDFSummary), 
    file="~/myProject/cachedData/VLDF.RData", 
    compress="bzip2") 

La opción de compresión no es opcional y para ser utilizado si desea comprimir el archivo que se está escribiendo en el disco. Vea ?save para más detalles.

Después de guardar el archivo que rdata puede comentar las etapas de carga de datos y resumen lentos, así como el paso de guardar y cargar simplemente los datos como estos:

load("~/myProject/cachedData/VLDF.RData") 

Esta respuesta no depende del editor. Funciona igual para Emacs, TextMate, etc. Puede guardar en cualquier ubicación de su computadora. Sin embargo, recomiendo mantener el código lento en su archivo de script R, para que siempre pueda saber de dónde proviene su archivo RData y poder recrearlo a partir de los datos de origen si es necesario.

4

(respuesta tardía, pero empecé a usar por lo que un año después de esta pregunta fue publicada.)

Ésta es la idea básica detrás de memoization (o memoisation). Tengo una larga lista de sugerencias, especialmente los paquetes memoise y R.cache, in this query.

También puede aprovechar el punto de control, que también se aborda como parte de esa misma lista.

Creo que su caso de uso refleja mi segundo: "Memorización de cálculos monstruosos". :)

Otro truco que uso es hacer muchos archivos mapeados en memoria, que uso mucho, para almacenar datos. Lo bueno de esto es que múltiples instancias R pueden acceder a datos compartidos, por lo que puedo tener muchas instancias tratando de resolver el mismo problema.

+1

Estoy de acuerdo. Memoization/caching (con persistencia opcional) es la respuesta aquí, no un código ad hoc. – Sim