Maestría en Hidrología
Universidad de Cuenca
http://www.ucuenca.edu.ec/maestria-ecohidrologia/

Johanna Orellana-Alvear (MSc)
johanna.orellana@ucuenca.edu.ec

Curso completo en: http://rpubs.com/Johanna_Orellana_Alvear/MHidro_indice_2018



En esta lección aprenderás a:
- Utilizar el debug de Rstudio
- Insertar breakpoints e inspeccionarlos
- El uso de funciones apply para subconjuntos de datos
- El uso de la funcion aggregate

Temario

A- Debug
B- Aplicación de funciones en conjuntos

Debug

“Finding your bug is a process of confirming the many things that you believe are true — until you find one which is not true.” —Norm Matloff

Durante la ejecución de un programa es posible que existan tres tipos de alertas por parte de R.

  • Errores fatales que se derivan de la ejecución de stop() y obligan a R a terminar el programa.

  • Warnings o alertas que son generadas por warning() y son usados para despelagar potenciales problemas.Por ejemplo cuando los valores de un vector de entrada a una función son inválidos,como log(-1:2).

  • Mensajes que son generados por message() y son usados con un fin informativos.

Proceso de depuración

El proceso de depuración en tres simples pasos:

  • Correr el código
  • Parar el código en el punto donde se sospecha que existe un problema, y
  • Inspeccionar a través del código, paso a paso en este punto.

Componentes de depuración en la pantalla de RStudio

  1. Console En la consola aparece una nueva barra de opciones con los botones: Next, Continue, Stop.
Debug console

Debug console

  1. Traceback En la parte derecha de RStudio, entre los paneles superior e inferior aparece un nuevo panel denominado Traceback (aquí se indica el camino de llamadas de funciones anidadas)
Debug traceback

Debug traceback

  1. Environment El panel superior del lado derecho (la pestaña de Environment) toma los valores de la función. Cuando el modo de depuración no está activo aquí usualmente se presentan las variables globales, es decir aquellas que se usan en el programa principal.
Debug environment

Debug environment

  1. Highlighting Como ventaja de la depuración visual (asistida a través de una interfaz) aquí se va resaltando la línea de ejecución (depuración) actual en cada paso.
Debug highligh

Debug highligh

Nota: Normalemente en depuración se usa la estrategia de “Divide y vencerás”, es decir una búsqueda binaria. En ocasiones no se conoce donde está el error del código y en estos casos hacer una búsqueda exhaustiva del problema puede ser muy demorado. Por lo tanto, lo mejor es dividir el código en dos repetidamente hasta que se encuentre el problema. De esta manera se reduce radicalmente la cantidad de código fuente sobre la que se tiene que inspeccionar.

Para trabajar con el tema de hoy crearemos una función llamada potencias y guardaremos el código fuente en el script debug_example.R.

potencias <- function (unVector){
  resultado <- c()
  cont <- 0
  for (i in unVector){
    cont <- cont + 1
    resultado[cont] <- i * (i^cont) 
  }
  return(resultado)
}

Pasos para ejecutar depuración en R

  • Cargar la función en memoria a través del comando source
source("debug_example.R")
  • Hacer la llamada para activar el modo de depuración a través del comando debugonce(nombreFuncion)
debugonce(potencias)

Hacer la llamada a la función con los argumentos.

Debug console

Debug console

Una vez que se ha terminado la ejecución del debug, la función regresa a su forma normal de ejecución. Por ejemplo, al ejecutar la línea siguiente vemos que el resultado de la función se visualiza inmediatamente.

potencias(c(1,3,5,7,9))
## [1] "salida del bucle"
## [1] "segundo breakpoint"
## [1]      1     27    625  16807 531441

Ahora probemos utilizando el comando debug()

debug(potencias)

Al terminar la ejecución y hacer la llamada nuevamente a potencias(c(1,3,5,7,9)) vemos que la función se ejecuta nuevamente en modo “depuración”. Para correr nuevamente cualquier función o script es necesario salir del modo de depuración utilizando el comando undebug. En general se recomienda utilizar el comando debugonce

undebug(potencias)

El ejemplo ilustrado es muy corto y podemos correrlo paso a paso. Sin embargo, ¿Qué pasaría si el el vector tuviera 100 elementos o más?, o si el script tuviera dos bucles diferentes y estamos seguros de que el problema se encuentra en el segundo. Pues bien, la solución sería indicarle a R donde queremos que empiece la depuración (es decir que ejecute rápidamente las líneas que no son de interés).

Para ello, se señala a través de “breakpoints” (puntos rojos) donde se desea que R haga una pausa en la ejecución. Basta con colocarse en la línea deseada y hacer click al borde izquierdo de la numeración. Para desactivar el breakpoint haga click en el mismo lugar.

Debug breakpoint

Debug breakpoint

Ahora, cuando entramos en modo depuración nuevamente el programa y presionamos el botón Continue,

Debug opciones

Debug opciones

R ejecuta rápidamente las líneas previas al breakpoint y hace una pausa en este punto esperando una nueva indicación.

Debug breakpoint

Debug breakpoint

Para terminar el modo de depuración, cortar la ejecución del proceso abruptamente puede hacer uso del botón stop o la letra Q. Nótese que los breakpoints se almacenan el momento de la llamada source. Además en caso de que el código mantenga breakpoints entrará automáticamente en modo de depuración. Si desea correr normalmente su programa debe asegurarse de borrar todos los breakpoints.

Aplicación de funciones en conjuntos

Existen mecanimos más eficientes de ejecutar ciertas funciones sobre fragmentos de una estructura (vector, matriz, data frame, etc) que a través de los bucles. De cierta manera estas funciones mismas incorporan una lógica de bucle de repetición. Es conveniente empezar respondiendo estas preguntas para identificar si la solución que se desea implementar se aplica a estos casos.

  1. ¿De qué clase son mis datos de entrada, los datos sobre los cuales quiero aplicar un proceso? - vector, matriz, data frame…).
  2. ¿Sobre qué subconjunto (subset) de datos se desea aplicar la función ? – filas, columnas, todos los valores…
  3. ¿Qué clase retornará la función? ¿Cómo se ha transformado la estructura original?

Existe una familia de comandos que permite aplicar funciones a varios elementos (subconjuntos de datos) de una estructura o clase simulando un proceso repetitivo más eficiente. Estos comandos son: apply, lapply , sapply, vapply, mapply, rapply, and tapply. En esta sesión ilustratemos algunos ejemplos de ellos y los que no se abordan aquí, se sugieren como revisión al lector.

apply

La sintaxis que se describe a continuación se aplica a todas las funciones de la familia apply.

apply(X, MARGIN, FUN, ...)

donde:

  • X es un array o matriz;

  • MARGIN es una variable que determina si la función se aplica sobre filas (MARGIN=1), columnas (MARGIN=2), or ambas (MARGIN=c(1,2));

  • FUN es la función a ser aplicada.

Ejemplo 1: Retornar el producto de cada fila
m<-matrix(c(seq(from=-98,to=100,by=2)),nrow=10,ncol=10)
apply(m,1,prod)
##  [1] -2.849130e+15 -5.344148e+15 -7.282577e+15 -8.510121e+15 -8.930250e+15
##  [6] -8.510121e+15 -7.282577e+15 -5.344148e+15 -2.849130e+15  0.000000e+00
Ejemplo 2: Retornar la suma de cada columna
apply(m,2,sum)
##  [1] -890 -690 -490 -290  -90  110  310  510  710  910
Ejemplo 3: Retornar una nueva matriz cuyos valores son ‘m’ modulo 10
apply(m,c(1,2),function(x) x%%10) 
##       [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
##  [1,]    2    2    2    2    2    2    2    2    2     2
##  [2,]    4    4    4    4    4    4    4    4    4     4
##  [3,]    6    6    6    6    6    6    6    6    6     6
##  [4,]    8    8    8    8    8    8    8    8    8     8
##  [5,]    0    0    0    0    0    0    0    0    0     0
##  [6,]    2    2    2    2    2    2    2    2    2     2
##  [7,]    4    4    4    4    4    4    4    4    4     4
##  [8,]    6    6    6    6    6    6    6    6    6     6
##  [9,]    8    8    8    8    8    8    8    8    8     8
## [10,]    0    0    0    0    0    0    0    0    0     0

lapply

Descripción: lapply retorna una lista de la misma longitud de X, donde cada elemento corresponde al resultado de aplicar FUN a su respectivo elemento de X.

A<-matrix(1:9, 3,3)
B<-matrix(4:15, 4,3)
C<-matrix(8:10, 3,2)
MyList<-list(A,B,C) # display the list
Extraer la segunda columna de la lista de matrices

Para aplicar este ejemplo se usa el operador de selección “[”.

lapply(MyList,"[", , 2)
## [[1]]
## [1] 4 5 6
## 
## [[2]]
## [1]  8  9 10 11
## 
## [[3]]
## [1]  8  9 10

sapply

Descripción: sapply es una versión amigable de lapply que por defecto retorna un vector o matriz según el caso. Nótese que el primero devuelve una lista, y el segundo un vector.

lapply(MyList,"[", 2,1 )
## [[1]]
## [1] 2
## 
## [[2]]
## [1] 5
## 
## [[3]]
## [1] 9
sapply(MyList,"[", 2,1 )
## [1] 2 5 9

Ahora aplciaremos la función unlist. ¿Qué produce la aplicación de esta función sobre el resultado de lapply?

unlist(lapply(MyList,"[", 2,1 ))
## [1] 2 5 9

aggregate

Esta función, a pesar de no pertenecer a la familia apply, mantiene una lógica similar de aplicación de una función a un subconjunto de datos. ¿Cuál es el objetivo y el resultado final del código, qué clase de objeto produce?

setwd("~/Documents/R_WORKSPACE/Maestria_Hidrologia_2018")
df.observaciones <- read.table("observaciones_2003.csv", header = TRUE, stringsAsFactors = FALSE)
sd_VALOR_monthly <- aggregate(VALOR ~ month, data = df.observaciones, sd)
sd_VALOR_monthly
##    month     VALOR
## 1      1  4.793814
## 2      2  7.401479
## 3      3 10.284249
## 4      4  8.289255
## 5      5  6.885316
## 6      6  4.416878
## 7      7  3.150891
## 8      8  2.220939
## 9      9  2.862725
## 10    10  3.130080
## 11    11  4.156379
## 12    12  6.350809