Ir al contenido principal

Recorridos con apply (una perspectiva diferente a los ciclos tradicionales)

Siempre tiende uno a buscar símiles entre un lenguaje de programación y otro, y siempre o casi siempre funciona  con aquellos lenguajes que toman como inspiración al lenguaje C, y que para ser honestos viene del antiguo y primitivo mundo de los lenguajes procedimentales (aunque C evolucionó a C++ para participar y ser en gran medida uno de los principales protagonistas del boom de la programación orientada a objetos).

Sin embargo, y otra vez siendo honestos, en principio el código de R me parecía escritura del alfabeto chino, había cosas únicas que no había visto en otros lenguajes de programación.

Es por eso que escribo el siguiente artículo que tiene que ver con los recorridos que se hacen a estructuras de datos, los llamados ciclos (for, while, do-while, repeat, do loop, etc,).

Ya llevo algunos años con R y me complacía programar soluciones usando ciclos ya que era la forma que me enseñaron desde la preparatoria, sin embargo con ánimo de hacer el código más eficiente di un vistazo a la familia de instrucciones apply y aunque en principio mi idea era buscar algún for-each que facilita el recorrido de colecciones, reflexioné e identifiqué que la forma de iterar en R adicional a los ciclos es como ya mencioné la familia de los apply.

Vagando por la Intenet encontré un curso en video muy interesante parece ser de la plataforma LinkedIn Learning y que por extraña razón me dejó verlo sin registrarme, en este caso el tema de apply corresponde al curso llamado "R para Big Data esencial". Además para evitarme desempolvar mis clases que crean datos aleatorios, encontré el conjunto de datos (dataset) que se usa en el video en el sitio "Harvard Metaverse" que es una plataforma gratuita para el intercambio de información.

Este conjunto de datos contiene información  de vuelos (llegadas y salidas) de los Estados Unidos desde el año de 1987 a abril del 2008, en este ejercicio tomaremos los del año de 2008 y se puede descargar desde aquí.

Retomo el ejercicio y lo trato de explicar un poco con mis palabras y en cierto modo desde la perspectiva de las personas que nos dedicamos a las TICs y no entendemos a profundidad tanto el dominio del lenguaje de programación así como los fundamentos matemáticos y de la ahora "ciencia de datos".

Este primer código es para ver la velocidad de un método (usando un for) y el otro (usando un apply) y la idea es comparar el tiempo que lleva para sacar la media aritmética de las filas de las dos formas.

Una de las cosas que me topé para replicar el ejemplo fue el uso de read_csv, que parece pertenece a la librería tidyverse, se instaló aunque manda unas advertencias que muestro a continuación.


Sin embargo el ejemplo funcionó.

Lo primero que vamos a hacer es leer el archivo que se descargo y vamos a seleccionar solo las columnas que necesitamos, que son las que tiene que ver con tiempos de retraso del vuelo  (por esta ocasión comparto código como texto debido a que vamos a explicar el mismo).

library(tidyverse)

df <- as.data.frame(read_csv("ruta/2008.csv",n_max = 100000))

df <- df[,c("CarrierDelay","WeatherDelay", "NASDelay", "SecurityDelay", "LateAircraftDelay")]

Aquí quizás una  duda es que se pueda sustituir la función read_csv por read.csv la novedad es que podemos definir cuantas líneas queremos importar, además usamos as.data.frame para convertir la información en un dataframe. Luego con la selección usando los corchetes ([]) el primer subíndice que queda en blanco significa que traeremos todas las filas (que en la lectura delimitamos en 100000) y las columnas que se describen y hagan match con el vector definido con c. (yo hubiera hecho un select :)).

#Vamos a sacar la media aritmética usando un bucle#

start <- Sys.time()

forma_for <- rep(0, nrow(df))

for(i in 1:nrow(df)){
  forma_for[i] = mean(as.numeric(df[i,]), na.rm = TRUE)
}

print(Sys.time() - start)

Creamos un arreglo (vector) forma_for para obtener la media de cada renglón y lo rellenamos con cero es por eso la función rep pone 0 a cada elemento del arreglo de los 100000 registros (rep(0, nrow(df))). Después hacemos un ciclo de 1 hasta el total de renglones, y se aplica la función mean antes convirtiendo el elemento a número y referenciado por el renglón i de todas las columnas y evitando los valores NA (mean(as.numeric(df[i,]), na.rm = TRUE). En mi equipo registra un total de 5.51 segundos para esta operación.

start <- Sys.time()

forma_apply <- apply(X = df, MARGIN = 1, FUN = mean, na.rm = TRUE)

print(Sys.time() - start)

Aquí se usa apply donde el parámetro X es para definir el conjunto de datos, MARGIN para especificar si son renglones o columnas y por último el parámetro na.rm con el valor TRUE es para omitir los valores NA. Después de ejecutar estas líneas nos damos cuenta que esta operación lleva apenas 0.544 segundos, claro ejemplo donde podemos tomar una decisión sobre que método usar.

#Comparación de los dos vectores de resultados

all(forma_for == forma_apply, na.rm = TRUE)

Esta última instrucción nos indica como ambos vectores de resultados son iguales, usando la instrucción all.

Para finalizar este post, tenemos el resultado de la ejecución del script.

Hasta el próximo post.

Miguel Araujo.








Comentarios

Entradas populares de este blog

Posit Cloud - como instalar librerías de Python en el entorno de R

 Ahora que estamos tomando una maestría buscando que siga "girando la ardilla" por unos años más en la materia de "Cómputo Estadístico" nos ha sugerido usar la versión gratuita de Posit en la nube. En su página definen este producto como "es una solución basada en la nube que permite acceder al poderoso conjunto de herramientas de ciencia de datos de Posit directamente en el navegador web  - sin requerir instalación o configuraciones complejas". Para los usuarios que han utilizado Posit RStudio en primera instancia verán el entorno muy similar a Posit Cloud con algunas pequeñas diferencias, para empezar necesitamos un usuario o contraseña aunque es posible autenticarse usando alguna cuenta existente como es el caso de Google. Con el tiempo y trabajando en desarrollo de software, vamos entendiendo que quizás el nombre queda muy grande a los pequeños ejemplos, pero es muy recomendable el uso de proyectos siempre. A continuación vemos el entorno Posit Clo...

REDATAM en Ubuntu (Linux)

 En un blog alterno, escribí sobre como migraba un "viejo" Intel i5 al sistema operativo Ubuntu en su versión más actual. Me comunique con mi gran colega Lenin de la CELADE en Chile, después de mucho tiempo, y le pedí me diera un pequeño resumen del "estado del arte" de REDATAM me dijo que todo marchaba bien, y pues ahora creo que tengo que actualizarme en contenedores pues el web server se encuentra ahí. Nos pusimos manos a la obra, el instalable desde la página no tiene ninguna extensión de archivo, asumí que era un ejecutable para Linux, no se si la página sufra ataques constantes ya que después quise volver a descargar sin éxito, la página estaba caida, sin embargo rescate el ejecutable anteriormente descargado. Últimamente primero hago y después documento, ya que con todo y mi compañero Deep,  no todo sale a la primera ni como lo dictan sus sugerencias, sobre todo en Linux y MacOS.  Por lo que, les muestro solo el resultado final de esta primera exploración, im...

El problema del gallo - otra vertiente de usar Python en RMarkdown con Posit RStudio

Cuando pensamos que ya se había cruzado el río, el buen gallo - mi amigo el Dany  Lara- no podía insertar código de Python  en un documento de RMarkdown  usando la versión de escritorio de Posit RStudio a pesar de las soluciones como instalar el Python y direccionarlo desde R con la biblioteca reticulate . Si bien se podía ejecutar código del interprete base, al querer correr usando módulos y con ello intentando instalar dichos módulos mandaba el siguiente mensaje: > py_install('matplotlib') Using virtual environment "D:/tu_usuario/Documents/.virtualenvs/r-reticulate" ... WARNING: Retrying (Retry(total=4, connect=None, read=None, redirect=None, status=None)) after connection broken by 'SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1006)'))': /simple/matplotlib/ WARNING: Retrying (Retry(total=3, connect=None, read=None, redirect=None, status=None)) a...