Capítulo 4. Flujo de trabajo: Estilo de código

Este trabajo se ha traducido utilizando IA. Agradecemos tus opiniones y comentarios: translation-feedback@oreilly.com

Un buen estilo de codificación es como una correcta puntuación: puedes arreglártelas sin él, pero seguro que facilita la lectura. Incluso siendo un programador novato, es una buena idea trabajar en el estilo de tu código. Utilizar un estilo coherente facilita a los demás (¡incluido tu futuro!) la lectura de tu trabajo y es especialmente importante si necesitas la ayuda de otra persona. Este capítulo presentará los puntos más importantes de la guía de estilo tidyverse, que se utiliza a lo largo de este libro.

Estilizar tu código te parecerá un poco tedioso al principio, pero si lo practicas, pronto se convertirá en algo natural. Además, existen algunas herramientas estupendas para cambiar rápidamente el estilo del código existente, como el paquete styler de Lorenz Walthert. Una vez que lo hayas instalado con install.packages("styler"), una forma fácil de utilizarlo es a través de la paleta de comandos de RStudio. La paleta de comandos te permite utilizar cualquier comando integrado de RStudio y muchos complementos proporcionados por paquetes. Abre la paleta pulsando Cmd/Ctrl+Mayús+P y escribe styler para ver todos los atajos que ofrece styler. La Figura 4-1 muestra los resultados.

A screenshot showing the command palette after typing "styler", showing the four styling tool provided by the package.

Figura 4-1. La paleta de comandos de RStudio facilita el acceso a todos los comandos de RStudio utilizando sólo el teclado.

Utilizaremos los paquetes tidyverse y nycflights13 para los ejemplos de código de este capítulo.

library(tidyverse)
library(nycflights13)

Nombres

Ya hablamos brevemente de los nombres en "¿Qué hay en un nombre?". Recuerda que los nombres de las variables (las creadas por <- y las creadas por mutate()) deben utilizar sólo letras minúsculas, números y _. Utiliza _ para separar las palabras dentro de un nombre.

# Strive for:
short_flights <- flights |> filter(air_time < 60)

# Avoid:
SHORTFLIGHTS <- flights |> filter(air_time < 60)

Como regla general, es mejor preferir nombres largos y descriptivos que sean fáciles de entender que nombres concisos que sean rápidos de escribir. Los nombres cortos ahorran relativamente poco tiempo al escribir código (sobre todo porque la función de autocompletar te ayudará a terminar de escribirlos), pero pueden consumir mucho tiempo cuando vuelvas a un código antiguo y te veas obligado a descifrar una abreviatura críptica.

Si tienes un montón de nombres para cosas relacionadas, haz lo posible por ser coherente. Es fácil que surjan incoherencias cuando olvidas una convención anterior, así que no te sientas mal si tienes que volver atrás y renombrar cosas. En general, si tienes un montón de variables que son una variación sobre un tema, es mejor que les des un prefijo común en lugar de un sufijo común, porque autocompletar funciona mejor al principio de una variable.

Espacios

Pon espacios a ambos lados de los operadores matemáticos aparte de ^ (es decir, +, -, ==, <, ...) y alrededor del operador de asignación (<-).

# Strive for
z <- (a + b)^2 / d

# Avoid
z<-( a + b ) ^ 2/d

No pongas espacios dentro o fuera de los paréntesis en las llamadas a funciones normales. Pon siempre un espacio después de una coma, como en el inglés estándar.

# Strive for
mean(x, na.rm = TRUE)

# Avoid
mean (x ,na.rm=TRUE)

Está bien añadir espacios extra si mejora la alineación. Por ejemplo, si estás creando múltiples variables en mutate()puedes añadir espacios para que todas las = queden alineadas.1 Así será más fácil hojear el código.

flights |> 
  mutate(
    speed      = distance / air_time,
    dep_hour   = dep_time %/% 100,
    dep_minute = dep_time %%  100
  )

Tuberías

|> siempre debe ir precedido de un espacio y, por lo general, debe ser el último elemento de la línea. Esto facilita añadir nuevos pasos, reorganizar pasos existentes, modificar elementos dentro de un paso y obtener una visión de 10.000 pies hojeando los verbos de la parte izquierda.

# Strive for 
flights |>  
  filter(!is.na(arr_delay), !is.na(tailnum)) |> 
  count(dest)

# Avoid
flights|>filter(!is.na(arr_delay), !is.na(tailnum))|>count(dest)

Si la función que estás canalizando tiene argumentos con nombre (como mutate() o summarize()), coloca cada argumento en una línea nueva. Si la función no tiene argumentos con nombre (como select() o filter()), mantenlo todo en una línea a menos que no quepa, en cuyo caso debes poner cada argumento en su propia línea.

# Strive for
flights |>  
  group_by(tailnum) |> 
  summarize(
    delay = mean(arr_delay, na.rm = TRUE),
    n = n()
  )

# Avoid
flights |>
  group_by(
    tailnum
  ) |> 
  summarize(delay = mean(arr_delay, na.rm = TRUE), n = n())

Después del primer paso de la cadena, aplica dos espacios de sangría a cada línea. RStudio coloca automáticamente los espacios por ti tras un salto de línea después de |>. Si colocas cada argumento en su propia línea, añade dos espacios más. Asegúrate de que ) está en su propia línea y sin sangría para que coincida con la posición horizontal del nombre de la función.

# Strive for 
flights |>  
  group_by(tailnum) |> 
  summarize(
    delay = mean(arr_delay, na.rm = TRUE),
    n = n()
  )

# Avoid
flights|>
  group_by(tailnum) |> 
  summarize(
             delay = mean(arr_delay, na.rm = TRUE), 
             n = n()
           )

# Avoid
flights|>
  group_by(tailnum) |> 
  summarize(
  delay = mean(arr_delay, na.rm = TRUE), 
  n = n()
  )

Está bien eludir algunas de estas reglas si tu fragmento cabe fácilmente en una línea. Pero, según nuestra experiencia colectiva, es habitual que los fragmentos cortos se alarguen, por lo que normalmente ahorrarás tiempo a largo plazo si empiezas con todo el espacio vertical que necesites.

# This fits compactly on one line
df |> mutate(y = x + 1)

# While this takes up 4x as many lines, it's easily extended to 
# more variables and more steps in the future
df |> 
  mutate(
    y = x + 1
  )

Por último, desconfía de escribir tuberías muy largas, digamos de más de 10-15 líneas. Intenta dividirlas en subtareas más pequeñas, dando a cada tarea un nombre informativo. Los nombres ayudarán al lector a saber qué está ocurriendo y le facilitarán la comprobación de que los resultados intermedios son los esperados. Siempre que puedas dar a algo un nombre informativo, deberías hacerlo, por ejemplo, cuando cambies fundamentalmente la estructura de los datos, por ejemplo, después de pivotar o resumir. ¡No esperes hacerlo bien a la primera! Esto significa romper largas cadenas si hay estados intermedios que pueden recibir buenos nombres.

ggplot2

Las mismas reglas básicas que se aplican a la tubería también se aplican a ggplot2; sólo tienes que tratar + del mismo modo que |>:

flights |> 
  group_by(month) |> 
  summarize(
    delay = mean(arr_delay, na.rm = TRUE)
  ) |> 
  ggplot(aes(x = month, y = delay)) +
  geom_point() + 
  geom_line()

De nuevo, si no caben todos los argumentos de una función en una sola línea, pon cada argumento en su propia línea:

flights |> 
  group_by(dest) |> 
  summarize(
    distance = mean(distance),
    speed = mean(distance / air_time, na.rm = TRUE)
  ) |> 
  ggplot(aes(x = distance, y = speed)) +
  geom_smooth(
    method = "loess",
    span = 0.5,
    se = FALSE, 
    color = "white", 
    linewidth = 4
  ) +
  geom_point()

Observa la transición de |> a +. Desearíamos que esta transición no fuera necesaria, pero por desgracia, ggplot2 se escribió antes de que se descubriera la tubería.

Seccionamiento Comentarios

Cuando tus guiones sean más largos, puedes utilizar comentarios de sección para dividir el archivo en partes manejables:

# Load data --------------------------------------

# Plot data --------------------------------------

RStudio proporciona un atajo de teclado para crear estas cabeceras (Cmd/Ctrl+Mayús+R) y las mostrará en el desplegable de navegación por el código, en la parte inferior izquierda del editor, como se muestra en la Figura 4-2.

Figura 4-2. Después de añadir comentarios de seccionamiento a tu script, puedes navegar fácilmente hasta ellos utilizando la herramienta de navegación de código situada en la parte inferior izquierda del editor de script.

Ejercicios

  1. Modifica el estilo de las siguientes tuberías siguiendo las pautas anteriores:

    flights|>filter(dest=="IAH")|>group_by(year,month,day)|>summarize(n=n(),
    delay=mean(arr_delay,na.rm=TRUE))|>filter(n>10)
    
    flights|>filter(carrier=="UA",dest%in%c("IAH","HOU"),sched_dep_time>
    0900,sched_arr_time<2000)|>group_by(flight)|>summarize(delay=mean(
    arr_delay,na.rm=TRUE),cancelled=sum(is.na(arr_delay)),n=n())|>filter(n>10)

Resumen

En este capítulo has aprendido los principios más importantes del estilo de código. Al principio pueden parecer un conjunto de reglas arbitrarias (¡porque lo son!), pero con el tiempo, a medida que escribas más código y compartas código con más gente, verás lo importante que es un estilo coherente. Y no te olvides del paquete estilizador: es una forma estupenda de mejorar rápidamente la calidad de un código mal estilizado.

En el siguiente capítulo, volvemos a las herramientas de la ciencia de datos, aprendiendo sobre los datos ordenados. Los datos ordenados son una forma coherente de organizar tus marcos de datos que se utiliza en todo el tidyverse. Esta coherencia te facilita la vida, porque una vez que tienes datos ordenados, simplemente funcionan con la gran mayoría de las funciones del tidyverse. Por supuesto, la vida nunca es fácil, y la mayoría de los conjuntos de datos que encuentres en la naturaleza no estarán ya ordenados. Así que también te enseñaremos a utilizar el paquete tidyr para ordenar tus datos desordenados.

1 Como dep_time está en formato HMM o HHMM, utilizamos la división entera (%/%) para obtener la hora y el resto (también conocido como módulo, %%) para obtener el minuto.

Get R para la Ciencia de Datos, 2ª Edición now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.