2011-06-22 22 views
22

me encuentro en la situación de haber completado una gran parte de análisis y ahora tienen que repetir el análisis con un poco diferentes supuestos de entrada.Estrategias para repetir gran parte del análisis

El análisis, en este caso, implica el análisis cluster, el trazado de varios gráficos, y la exportación de los identificadores de racimo y otras variables de interés. El punto clave es que es un análisis extenso, y debe repetirse y compararse solo dos veces.

que considera:

  • Creación de una función. Esto no es ideal, porque entonces tengo que modificar mi código para saber si estoy evaluando en la función o en los entornos principales. Este esfuerzo adicional parece excesivo, hace que sea más difícil de depurar y puede presentar efectos secundarios.
  • Envuélvalo en un bucle. De nuevo, no es ideal, porque entonces tengo que crear variables de indexación, que también pueden presentar efectos secundarios.
  • Creación de un código de preámbulo, envolviendo el análisis en un archivo separado y se source. Esto funciona, pero parece muy feo y subóptimo.

El objetivo del análisis es terminar con un conjunto de objetos (en una lista, o en archivos de salida separados) que puedo analizar más a fondo para las diferencias.

¿Cuál es una buena estrategia para hacer frente a este tipo de problemas?

Respuesta

17

Haciendo código reutilizable lleva algún tiempo, esfuerzo y mantiene unos retos adicionales como se menciona a sí mismo.

La cuestión de si invertir es probablemente la cuestión clave en informática (si no en muchos otros campos): ¿escribo un script para cambiar el nombre de 50 archivos de manera similar o sigo adelante y los cambio de nombre manualmente .

La respuesta, creo, es muy personal e incluso entonces, caso diferente por caso. Si eres fácil en la programación, es posible que antes decidas ir a la ruta de reutilización, ya que el esfuerzo será relativamente bajo (e incluso entonces, a los programadores normalmente les gusta aprender nuevos trucos, por lo que es una motivación oculta, a menudo contraproducente).

Dicho esto, en su caso particular: yo iría con la opción de abastecimiento: ya que planea reutilizar el código solo 2 veces más, un esfuerzo mayor probablemente se desperdicie (indica que el análisis es bastante extenso) . Entonces, ¿qué pasa si no es una solución elegante? Nadie va a ver que lo hagas, y todos estarán felices con los rápidos resultados.

Si resulta que en un año o así que la reutilización es mayor de lo esperado, puede entonces todavía invertir. Y para entonces, también tendrá (al menos) tres casos para los cuales puede comparar los resultados de la versión reutilizable reescrita y funky de su código con sus resultados actuales.

Si/cuando sé por adelantado que voy a volver a utilizar el código, trato de tener esto en cuenta mientras lo desarrollo. De cualquier forma, casi nunca escribo código que no esté en una función (bueno, salvo los de dos líneas para SO y otros análisis listos para usar): me parece que esto me facilita estructurar mis pensamientos.

+0

+1 porque solo lo hará dos veces más. La respuesta también depende de cuánto va a cambiar cada vez que realiza el análisis, solo unos pocos parámetros, datos de entrada,? Encuentro que a menudo hay una transición bastante suave entre (1) extraer los parámetros clave y definirlos en la parte superior del código [o ponerlos en un archivo separado y 'fuente()' ing del cuerpo del análisis] y (2) envolviendo el cuerpo del código en una función. No está claro para mí cuáles son las diferencias entre tu padre y tu entorno funcional. –

+0

+1 Esto es más o menos lo que hice al final. Envolví todo el parámetro que cambió para cada ejecución en una lista. Luego creó diferentes listas (con la misma estructura) que contienen los valores de entrada para cada ejecución.Para cada iteración, copié las listas necesarias y guardé las variables resultantes en listas de salida. En otras palabras, un poco de envoltura de código en un preámbulo y limpieza, y trabajo hecho. Funciona. Está bien si es feo ... – Andrie

3

Me gusta trabajar con la combinación de un pequeño script de shell, un programa de recorte de pdf y Sweave en esos casos. Eso te devuelve buenos informes y te alienta a que te fuente. Normalmente trabajo con varios archivos, casi como crear un paquete (al menos creo que se siente así :).Tengo un archivo separado para el malabarismo de datos y archivos separados para diferentes tipos de análisis, como descriptiveStats.R, regressions.R, por ejemplo.

por cierto aquí es mi pequeño script de shell,

#!/bin/sh 
R CMD Sweave docSweave.Rnw 
for file in `ls pdfs`; 
do pdfcrop pdfs/"$file" pdfs/"$file" 
done 
pdflatex docSweave.tex 
open docSweave.pdf 

El archivo Sweave normalmente fuentes de los archivos R mencionadas anteriormente cuando sea necesario. No estoy seguro de si eso es lo que estás buscando, pero esa es mi estrategia hasta ahora. Al menos creo que crear informes transparentes y reproducibles es lo que ayuda a seguir al menos una estrategia.

+0

+1 Tendré que explorar los guiones del intérprete de comandos más - tiendo a no usarlos con R. Esto parece equivalente, o al menos análogo, al uso de 'fuente'. – Andrie

+0

Todo depende un poco del sistema operativo. Todavía no estoy seguro de si python, scripts de shell o Apple Script se ajustan mejor a mis necesidades, pero, por lo que puedo juzgar, las secuencias de comandos shell con R realmente merecen una visita, en particular para los informes automatizados. –

10

Si es posible, configure los parámetros que difieren entre series/ejecuciones/experimentos en un archivo de parámetros externo. Luego, puede obtener el código, llamar a una función e incluso utilizar un paquete, pero las operaciones están determinadas por un pequeño conjunto de parámetros definidos externamente.

Por ejemplo, JSON funciona muy bien para esto y los paquetes RJSONIO y rjson le permiten cargar el archivo en una lista. Supongamos que lo carga en una lista llamada parametersNN.json. Un ejemplo es el siguiente:

{ 
"Version": "20110701a", 
"Initialization": 
{ 
    "indices": [1,2,3,4,5,6,7,8,9,10], 
    "step_size": 0.05 
}, 
"Stopping": 
{ 
    "tolerance": 0.01, 
    "iterations": 100 
} 
} 

Guardar como que "parameters01.json" y la carga como:

library(RJSONIO) 
Params <- fromJSON("parameters.json") 

y ya está fuera de funcionamiento. (NB: me gusta usar #s de versiones únicas dentro de mis archivos de parámetros, solo para poder identificar el conjunto más tarde, si estoy mirando la lista de "parámetros" dentro de R.) Simplemente llame a su script y apunte a los parámetros archivo, por ejemplo:

Rscript --vanilla MyScript.R parameters01.json 

entonces, dentro del programa, identificar el archivo de parámetros de la función commandArgs().

Más adelante, puede dividir el código en funciones y paquetes, pero esta es probablemente la forma más fácil de generalizar un script de vanilla a corto plazo, y es una buena práctica a largo plazo, ya que el código debe separarse a partir de la especificación de los parámetros run/dataset/experiment-dependent.

Editar: para ser más precisos, incluso podría especificar directorios de entrada y salida o archivos (o nombres de patrones/prefijos) en el JSON. Esto deja muy claro cómo un conjunto de parámetros condujo a un determinado conjunto de resultados. Todo en el medio es solo código que se ejecuta con una parametrización dada, pero el código no debería cambiar mucho, ¿o sí?


Actualización: tres meses, y muchos miles de pistas, más sabia que mi respuesta anterior, yo diría que el almacenamiento externo de los parámetros en JSON es útil para 1-1000 carreras diferentes. Cuando los parámetros o configuraciones se cuentan por miles y más, es mejor cambiar a usar una base de datos para la administración de la configuración. Cada configuración puede originarse en un JSON (o XML), pero ser capaz de lidiar con diferentes diseños de parámetros requiere una solución de mayor escala, para lo cual una base de datos como SQLite (a través de RSQLite) es una buena solución.

Me doy cuenta de que esta respuesta es excesiva para la pregunta original: cómo repetir el trabajo solo un par de veces, con algunos cambios de parámetros, pero al escalar cientos o miles de cambios de parámetros en la investigación en curso, necesario. :)

+0

Esta fue una respuesta muy útil para mí. Ni siquiera fui hasta 'JSON', sino que usé una pequeña secuencia de comandos' .R' en un directorio de configuración. El motor de cuadrícula establece una variable de entorno con el nombre del trabajo en ella, por lo que puedo leer eso y hacer que extraiga el archivo de configuración del mismo nombre para esa ejecución. Funciona bien para mis necesidades; ¡parece que los tuyos son mucho más sustanciales! –

+1

@ AriB.Friedman contento de ayudar! El enfoque DB parece funcionar bien para miles y más. Si nada más, puede pensar en configuraciones de parámetros análogas al diseño experimental: el almacenamiento de los parámetros del diseño es escalable en un DB y, en última instancia, queremos saber por qué diferentes ejecuciones tuvieron diferentes resultados. – Iterator

1

Tiendo a llevar tales resultados a una lista global. Uso Common Lisp pero luego R no es tan diferente.

+1

+1 Sí, esto es lo que hice al final. Cree una lista de variables que deben cambiar y otra lista con resultados. Luego, cambie las variables locales dentro y fuera de la lista. – Andrie

1

Demasiado tarde para ti aquí, pero utilizo Sweave mucho, y probablemente usaría un archivo Sweave desde el principio (por ejemplo, si sé que el producto final debe ser algún tipo de informe).

para repetir partes del análisis una segunda y tercera vez, hay entonces dos opciones:

  • Si los resultados son más bien "independiente" (es decir, debe producir 3 informes, la comparación se entiende los informes son inspeccionados uno al lado del otro), y la entrada modificada viene en forma de nuevos archivos de datos, que entran en su propio directorio junto con una copia del archivo Sweave y creo informes separados (similares a los de origen, pero se siente más natural para Sweave que para fuente simple).

  • si prefiero hacer exactamente lo mismo una o dos veces dentro de un archivo Sweave, consideraría reutilizar fragmentos de código. Esto es similar al feo for-loop.

    La razón es que, por supuesto, los resultados están juntos para la comparación, que sería la última parte del informe.

  • Si es claro desde el principio que habrá algunos conjuntos de parámetros y una comparación, escribo el código de manera que tan pronto como estoy satisfecho con cada parte del análisis, se envuelve en una función (es decir, estoy escribiendo la función en la ventana del editor, pero evalúo las líneas directamente en el espacio de trabajo mientras escribo la función).

Teniendo en cuenta que se encuentra en la situación descrita, estoy de acuerdo con Nick - nada malo con source y todo lo demás significa un esfuerzo mucho mayor ahora que ya lo tienes como guión.

2

Su tercera opción no es tan mala. Hago esto en muchos casos. Puede construir un poco más de estructura al poner los resultados de su código de preamplificación en entornos y adjuntar el que desea utilizar para un análisis posterior. Un ejemplo:

setup1 <- local({ 
      x <- rnorm(50, mean=2.0) 
      y <- rnorm(50, mean=1.0) 
      environment() 
      # ... 
     }) 

    setup2 <- local({ 
      x <- rnorm(50, mean=1.8) 
      y <- rnorm(50, mean=1.5) 
      environment() 
      # ... 
     }) 

attach(setup1) y RUN/fuente de código de su análisis

plot(x, y) 
t.test(x, y, paired = T, var.equal = T) 
... 

Cuando haya terminado, detach(setup1) y adjuntar el segundo.

Ahora, al menos puede cambiar fácilmente entre las configuraciones. Me ayudó un par de veces.

+0

+1 Este enfoque es realmente interesante. Por lo general, trato de evitar el uso de 'adjuntar' pero me gusta la idea de crear entornos para evitar este problema. Voy a explorar esto más. – Andrie

+0

También me gusta este, con la misma precaución de usar 'adjuntar' como ha mencionado Andrie. Lo bueno de esto es que es más general que solo listas de parámetros, y puede incluir cálculos. – Iterator

Cuestiones relacionadas