R

R

Tutorial R: dplyr para filtrado y selección

Aprende a usar dplyr en R para filtrar y seleccionar datos con filter(), select() y el operador pipe para análisis eficiente.

Aprende R y certifícate

filter() para subconjuntos por condición

La función filter() es una de las herramientas más útiles del paquete dplyr, diseñada específicamente para extraer subconjuntos de filas de un dataframe que cumplan con una o varias condiciones lógicas. A diferencia del método tradicional de indexación en R base, filter() ofrece una sintaxis más intuitiva y legible.

Funcionamiento básico

La función filter() evalúa cada fila de un dataframe y conserva únicamente aquellas que cumplen con las condiciones especificadas. Su sintaxis general es:

filter(dataframe, condición1, condición2, ...)

Donde cada condición es una expresión que devuelve un valor lógico (TRUE o FALSE). Veamos un ejemplo sencillo utilizando el dataset mtcars que viene incluido en R:

# Cargar la librería dplyr
library(dplyr)

# Filtrar coches con más de 100 caballos de potencia
coches_potentes <- filter(mtcars, hp > 100)

# Mostrar las primeras filas del resultado
head(coches_potentes)

En este ejemplo, filter() evalúa la condición hp > 100 para cada fila y conserva solo aquellas donde esta condición es verdadera.

Operadores de comparación

Para crear condiciones efectivas, podemos utilizar los operadores de comparación estándar de R:

  • > (mayor que)
  • >= (mayor o igual que)
  • < (menor que)
  • <= (menor o igual que)
  • == (igual a)
  • != (distinto de)

Por ejemplo, para filtrar coches con un consumo de combustible específico:

# Filtrar coches con exactamente 21 millas por galón
coches_21mpg <- filter(mtcars, mpg == 21)

# Ver el resultado
coches_21mpg

Combinando múltiples condiciones

Una de las ventajas de filter() es la facilidad para combinar múltiples condiciones. Cuando pasamos varias condiciones separadas por comas, estas se combinan con el operador lógico AND (&), lo que significa que todas deben cumplirse:

# Filtrar coches con más de 100 caballos y menos de 3000 libras de peso
coches_filtrados <- filter(mtcars, hp > 100, wt < 3)

# Ver el resultado
head(coches_filtrados)

Para utilizar condiciones OR (|), AND (&) o NOT (!), podemos incluirlas explícitamente:

# Coches muy potentes O muy ligeros
coches_especiales <- filter(mtcars, hp > 200 | wt < 2.5)

# Coches que NO son automáticos (am = 0 significa transmisión manual)
coches_manuales <- filter(mtcars, !am == 0)

Trabajando con valores NA

Al filtrar datos, es importante considerar cómo manejar los valores NA (datos faltantes). Por defecto, filter() excluye las filas donde la condición evalúa a NA. Para incluir explícitamente o excluir valores NA, podemos usar la función is.na():

# Crear un dataframe de ejemplo con algunos NA
df <- data.frame(
  x = c(1, 2, NA, 4, 5),
  y = c("a", "b", "c", NA, "e")
)

# Filtrar filas donde x no es NA
filter(df, !is.na(x))

# Filtrar filas donde y es NA
filter(df, is.na(y))

Filtrado con operadores %in%

El operador %in% es extremadamente útil cuando queremos filtrar filas donde una columna coincida con cualquier valor de un conjunto:

# Crear un dataframe de ejemplo
empleados <- data.frame(
  nombre = c("Ana", "Carlos", "Elena", "David", "Beatriz"),
  departamento = c("Ventas", "IT", "Marketing", "IT", "Ventas"),
  edad = c(28, 35, 42, 31, 29)
)

# Filtrar empleados de departamentos específicos
it_marketing <- filter(empleados, departamento %in% c("IT", "Marketing"))

# Ver el resultado
it_marketing

Filtrado por patrones de texto

Para filtrar basándonos en patrones de texto, podemos combinar filter() con funciones de manipulación de strings como grepl() o str_detect() del paquete stringr:

# Filtrar nombres que empiezan con la letra A
nombres_con_a <- filter(empleados, grepl("^A", nombre))

# Con stringr sería:
# library(stringr)
# nombres_con_a <- filter(empleados, str_detect(nombre, "^A"))

# Ver el resultado
nombres_con_a

Filtrado por rangos

Para filtrar valores dentro de un rango, podemos usar el operador between() que proporciona dplyr:

# Filtrar empleados con edades entre 30 y 40 años
edad_media <- filter(empleados, between(edad, 30, 40))

# Equivalente a:
# edad_media <- filter(empleados, edad >= 30 & edad <= 40)

# Ver el resultado
edad_media

Ejemplo práctico con un dataset real

Veamos un ejemplo más completo utilizando el dataset iris, que contiene medidas de diferentes especies de flores:

# Cargar dplyr
library(dplyr)

# Filtrar flores de la especie setosa con ancho de sépalo mayor a 4
setosa_grandes <- filter(iris, 
                         Species == "setosa", 
                         Sepal.Width > 4)

# Ver el resultado
setosa_grandes

# Filtrar flores que no son virginica y tienen longitud de pétalo entre 4 y 5
flores_seleccionadas <- filter(iris,
                              Species != "virginica",
                              between(Petal.Length, 4, 5))

# Ver cuántas filas cumplen estas condiciones
nrow(flores_seleccionadas)

La función filter() es una herramienta fundamental para la exploración y limpieza de datos en R. Su sintaxis clara y su capacidad para combinar múltiples condiciones la convierten en una opción superior a los métodos tradicionales de indexación para muchas tareas de análisis de datos.

select() y helpers para elegir columnas

Mientras que filter() nos permite trabajar con filas, la función select() de dplyr nos proporciona una forma elegante y eficiente de seleccionar columnas específicas de un dataframe. Esta función resulta especialmente útil cuando trabajamos con conjuntos de datos que contienen numerosas variables y solo necesitamos un subconjunto de ellas.

La sintaxis básica de select() es muy intuitiva:

select(dataframe, columna1, columna2, ...)

Veamos un ejemplo sencillo utilizando el dataset iris:

library(dplyr)

# Seleccionar solo las columnas de longitud
iris_longitud <- select(iris, Sepal.Length, Petal.Length)

# Mostrar las primeras filas
head(iris_longitud)

Este código crea un nuevo dataframe que contiene únicamente las columnas de longitud del sépalo y del pétalo, descartando las demás variables.

Selección por posición y nombre

Podemos seleccionar columnas tanto por su nombre como por su posición:

# Por nombre
especies_y_sepalo <- select(iris, Species, Sepal.Length)

# Por posición
primeras_tres <- select(iris, 1:3)

# Combinando ambos métodos
mix_seleccion <- select(iris, Species, 1:2)

Excluyendo columnas

Para excluir columnas específicas en lugar de seleccionarlas, podemos utilizar el signo menos (-):

# Seleccionar todas las columnas excepto Species
sin_especies <- select(iris, -Species)

# Excluir múltiples columnas
solo_petalos <- select(iris, -Sepal.Length, -Sepal.Width)

# Excluir un rango de columnas
sin_sepalo <- select(iris, -(1:2))

Reordenando columnas

La función select() también nos permite reordenar las columnas de un dataframe:

# Colocar Species al principio
especies_primero <- select(iris, Species, everything())

# Reordenar completamente
reordenado <- select(iris, Petal.Length, Petal.Width, Sepal.Length, Sepal.Width, Species)

Funciones helper para select()

Dplyr proporciona varias funciones auxiliares (helpers) que hacen que la selección de columnas sea aún más potente y flexible. Estas funciones están diseñadas para trabajar específicamente con select():

1. starts_with(), ends_with() y contains()

Estas funciones nos permiten seleccionar columnas basándonos en patrones en sus nombres:

# Seleccionar columnas que empiezan con "Sepal"
solo_sepalo <- select(iris, starts_with("Sepal"))

# Seleccionar columnas que terminan con "Width"
anchuras <- select(iris, ends_with("Width"))

# Seleccionar columnas que contienen "etal"
variables_petal <- select(iris, contains("etal"))

2. matches()

Permite seleccionar columnas cuyos nombres coinciden con una expresión regular:

# Seleccionar columnas que contienen "al"
con_al <- select(iris, matches("al"))

# Seleccionar columnas que empiezan con S o P
sp_cols <- select(iris, matches("^[SP]"))

3. everything()

Esta función selecciona todas las columnas restantes, lo que resulta útil para reordenar columnas:

# Mover Species al principio y mantener el resto en el mismo orden
especies_primero <- select(iris, Species, everything())

4. num_range()

Permite seleccionar columnas con nombres que siguen un patrón numérico:

# Crear un dataframe de ejemplo con columnas numeradas
df_numerado <- data.frame(
  x1 = 1:3,
  x2 = 4:6,
  x3 = 7:9,
  y = c("a", "b", "c")
)

# Seleccionar columnas x1, x2 y x3
solo_x <- select(df_numerado, num_range("x", 1:3))

5. one_of()

Selecciona columnas cuyos nombres están en un vector de caracteres:

variables <- c("Sepal.Length", "Petal.Length", "Species")
longitudes_y_especie <- select(iris, one_of(variables))

6. where()

Permite seleccionar columnas basándose en una función predicado:

# Seleccionar solo columnas numéricas
numericas <- select(iris, where(is.numeric))

# Seleccionar columnas con valores únicos > 10
muchos_valores <- select(iris, where(~length(unique(.)) > 10))

Renombrando columnas con select()

Podemos renombrar columnas al mismo tiempo que las seleccionamos utilizando la sintaxis nuevo_nombre = viejo_nombre:

# Renombrar columnas de longitud
renombrado <- select(iris, 
                    longitud_sepalo = Sepal.Length,
                    longitud_petalo = Petal.Length)

# Renombrar algunas y mantener otras
mix_renombrado <- select(iris,
                        longitud_sepalo = Sepal.Length,
                        Sepal.Width,
                        longitud_petalo = Petal.Length,
                        Petal.Width,
                        especie = Species)

Ejemplo práctico con un dataset real

Veamos un ejemplo más completo utilizando el dataset mtcars:

# Cargar dplyr
library(dplyr)

# Seleccionar variables relacionadas con el rendimiento
rendimiento <- select(mtcars, mpg, hp, qsec)

# Seleccionar variables de tamaño y renombrarlas
dimensiones <- select(mtcars, 
                     peso = wt,
                     cilindrada = disp,
                     starts_with("c"))

# Reorganizar las columnas: primero el nombre del coche, luego rendimiento, después el resto
mtcars_reorganizado <- mtcars %>%
  # Convertir los nombres de fila a una columna llamada "coche"
  rownames_to_column("coche") %>%
  select(coche, mpg, hp, everything())

# Ver el resultado
head(mtcars_reorganizado)

La función select() y sus helpers nos permiten manipular las columnas de nuestros dataframes de manera eficiente y expresiva, facilitando enormemente el trabajo con conjuntos de datos complejos. Combinada con otras funciones de dplyr, nos proporciona un conjunto de herramientas poderoso para la manipulación de datos en R.

Operaciones encadenadas con pipe

El operador pipe (%>%) es una de las innovaciones más importantes en el ecosistema de R, especialmente dentro del tidyverse. Este operador, proporcionado por el paquete magrittr e incorporado en dplyr, permite encadenar múltiples operaciones de manera secuencial y legible, transformando radicalmente la forma en que escribimos código para análisis de datos.

El pipe toma el resultado de una expresión y lo pasa como primer argumento a la siguiente función. Su sintaxis básica es:

datos %>% funcion()

Que equivale a:

funcion(datos)

Aunque esta equivalencia parece trivial en operaciones simples, el verdadero poder del pipe se revela cuando encadenamos múltiples operaciones.

Ventajas del pipe en la manipulación de datos

Trabajar con el pipe ofrece varias ventajas significativas:

  • Legibilidad: El código fluye de izquierda a derecha y de arriba a abajo, siguiendo el orden natural de lectura.
  • Mantenimiento: Evita la creación de variables intermedias o la anidación excesiva de funciones.
  • Modularidad: Facilita añadir, eliminar o reordenar pasos en el análisis.

Veamos un ejemplo comparativo. Sin usar pipe, podríamos escribir:

# Sin pipe: anidación de funciones (difícil de leer)
head(select(filter(iris, Sepal.Length > 7), Species, Sepal.Length))

# Sin pipe: usando variables intermedias (código más largo)
iris_filtrado <- filter(iris, Sepal.Length > 7)
iris_seleccionado <- select(iris_filtrado, Species, Sepal.Length)
head(iris_seleccionado)

Con el pipe, el mismo código se transforma en:

# Con pipe: flujo natural y legible
iris %>% 
  filter(Sepal.Length > 7) %>%
  select(Species, Sepal.Length) %>%
  head()

Combinando filter() y select() con pipe

La combinación de filter() y select() mediante pipes es uno de los patrones más comunes en el análisis de datos con dplyr. Veamos algunos ejemplos prácticos:

library(dplyr)

# Filtrar y luego seleccionar columnas
iris %>%
  filter(Species == "virginica") %>%
  select(starts_with("Petal"))

# Seleccionar primero y luego filtrar
iris %>%
  select(Species, contains("Length")) %>%
  filter(Sepal.Length > 6.5)

El orden de las operaciones es importante. Si filtramos primero, podemos reducir significativamente el número de filas antes de seleccionar columnas. Si seleccionamos primero, podemos trabajar con un conjunto más pequeño de variables, lo que puede hacer que las condiciones de filtrado sean más manejables.

Encadenando múltiples operaciones

El pipe brilla especialmente cuando necesitamos realizar múltiples transformaciones secuenciales:

mtcars %>%
  # Convertir nombres de fila a columna
  rownames_to_column("modelo") %>%
  # Filtrar coches con buena eficiencia de combustible
  filter(mpg > 20) %>%
  # Seleccionar solo algunas columnas
  select(modelo, mpg, hp, wt) %>%
  # Ordenar por potencia (hp) descendente
  arrange(desc(hp)) %>%
  # Mostrar solo los primeros 5
  head(5)

Este código realiza cinco operaciones distintas de manera clara y concisa, sin necesidad de variables intermedias ni funciones anidadas.

Uso de pipe con funciones que no son de dplyr

El pipe no está limitado a funciones de dplyr; podemos usarlo con cualquier función de R donde los datos sean el primer argumento:

# Crear un gráfico con ggplot2 después de filtrar y seleccionar
library(ggplot2)

iris %>%
  filter(Species != "setosa") %>%
  select(Species, Sepal.Length, Petal.Length) %>%
  ggplot(aes(x = Sepal.Length, y = Petal.Length, color = Species)) +
  geom_point() +
  labs(title = "Relación entre longitudes de sépalo y pétalo")

Observa que después de ggplot() usamos + en lugar de %>%, ya que esa es la sintaxis específica de ggplot2 para añadir capas al gráfico.

Cuando el resultado no es el primer argumento

En ocasiones, necesitamos usar el resultado de una operación como un argumento que no es el primero en la siguiente función. Para estos casos, podemos usar el marcador de posición .:

iris %>%
  filter(Species == "versicolor") %>%
  # Usar el resultado como segundo argumento de cor()
  summarise(correlacion = cor(Sepal.Length, Petal.Length, data = .))

Sin embargo, en dplyr moderno, rara vez necesitamos usar este marcador, ya que las funciones están diseñadas para trabajar bien con el pipe.

Ejemplo práctico: análisis exploratorio básico

Veamos un ejemplo más completo que muestra cómo el pipe facilita un flujo de trabajo exploratorio:

library(dplyr)

# Análisis exploratorio del dataset mtcars
mtcars %>%
  # Añadir nombres de coche como columna
  rownames_to_column("coche") %>%
  # Filtrar coches con transmisión automática (am = 0)
  filter(am == 0) %>%
  # Seleccionar variables relevantes
  select(coche, mpg, hp, wt, cyl) %>%
  # Ordenar por eficiencia de combustible
  arrange(desc(mpg)) %>%
  # Agrupar por número de cilindros
  group_by(cyl) %>%
  # Calcular promedios por grupo
  summarise(
    n_coches = n(),
    mpg_promedio = mean(mpg),
    hp_promedio = mean(hp),
    peso_promedio = mean(wt)
  ) %>%
  # Ordenar por número de cilindros
  arrange(cyl)

Este análisis completo se expresa como un flujo coherente de operaciones, fácil de leer y modificar.

Buenas prácticas al usar pipes

Para aprovechar al máximo el pipe, considera estas recomendaciones:

  • Coloca cada operación en una nueva línea e indenta consistentemente para mejorar la legibilidad.
  • Limita las cadenas de pipe a operaciones relacionadas; si el análisis cambia de dirección, considera iniciar una nueva cadena.
  • Añade comentarios antes de cada paso para documentar el propósito de cada operación.
  • Si una cadena se vuelve demasiado larga (más de 10 operaciones), considera dividirla en partes lógicas.
# Ejemplo de formato recomendado
datos_procesados <- datos_crudos %>%
  # Eliminar filas con valores faltantes
  filter(!is.na(variable_clave)) %>%
  # Seleccionar solo las variables necesarias
  select(id, starts_with("valor")) %>%
  # Ordenar por id
  arrange(id)

Alternativas al pipe de magrittr

En versiones recientes de R (≥ 4.1.0), se introdujo el operador pipe nativo |> que funciona de manera similar al %>% de magrittr:

# Pipe nativo de R (R ≥ 4.1.0)
iris |>
  filter(Species == "setosa") |>
  select(starts_with("Petal"))

La principal diferencia es que el pipe nativo no admite el marcador de posición . para usos avanzados, aunque para la mayoría de los casos de uso con dplyr, ambos operadores funcionan de manera equivalente.

El pipe ha transformado la forma en que escribimos código en R, haciendo que las operaciones secuenciales sean más intuitivas y legibles. Combinado con las funciones de dplyr como filter() y select(), proporciona una forma poderosa y expresiva de manipular datos, permitiéndonos concentrarnos en el análisis en lugar de en la sintaxis.

Aprende R online

Otros ejercicios de programación de R

Evalúa tus conocimientos de esta lección dplyr para filtrado y selección con nuestros retos de programación de tipo Test, Puzzle, Código y Proyecto con VSCode, guiados por IA.

Todas las lecciones de R

Accede a todas las lecciones de R y aprende con ejemplos prácticos de código y ejercicios de programación con IDE web sin instalar nada.

Instalación De R Y Rstudio

R

Introducción Y Entorno

Introducción A R

R

Introducción Y Entorno

Operadores

R

Sintaxis

Estructuras De Datos

R

Sintaxis

Funciones

R

Sintaxis

Estructuras De Control Iterativo

R

Sintaxis

Scopes Y Closures

R

Sintaxis

Estructuras De Control Condicional

R

Sintaxis

Funciones Anónimas

R

Sintaxis

Tipos De Datos Y Variables

R

Sintaxis

Sistema R6: Clases Referenciales Y Encapsulamiento

R

Programación Orientada A Objetos

Sistema S4: Clases Formales Y Validación

R

Programación Orientada A Objetos

Herencia Y Polimorfismo En R

R

Programación Orientada A Objetos

Sistemas De Oop En R

R

Programación Orientada A Objetos

Sistema S3: Clases Implícitas Y Métodos Genéricos

R

Programación Orientada A Objetos

Tidyverse Para Transformación De Datos

R

Manipulación De Datos

Lubridate Para Fechas Y Tiempo

R

Manipulación De Datos

Group_by Y Summarize Para Agrupación Y Resumen

R

Manipulación De Datos

Stringr Para Expresiones Regulares

R

Manipulación De Datos

Tidyr Para Limpieza De Valores Faltantes

R

Manipulación De Datos

Joins En R Para Combinación Y Relaciones De Tablas

R

Manipulación De Datos

Pivot_longer Y Pivot_wider Para Reestructuración

R

Manipulación De Datos

Mutate Y Transmute Para Transformación

R

Manipulación De Datos

Dplyr Para Filtrado Y Selección

R

Manipulación De Datos

Readr Y Read.csv Para Importar Datos

R

Manipulación De Datos

Gráficos Bivariantes En R

R

Visualización De Datos

Gráficos Univariantes En R

R

Visualización De Datos

Facetas En Ggplot2

R

Visualización De Datos

Personalización Y Temas

R

Visualización De Datos

Ggplot2 Para Visualización De Datos

R

Visualización De Datos

Gráficos Multivariantes En R

R

Visualización De Datos

Correlación En R

R

Estadística

Regresión Lineal En R

R

Estadística

Pruebas De Hipótesis En R

R

Estadística

Anova En R

R

Estadística

Estadística Descriptiva En R

R

Estadística

Accede GRATIS a R y certifícate

En esta lección

Objetivos de aprendizaje de esta lección

  • Comprender el uso de filter() para extraer subconjuntos de filas según condiciones lógicas.
  • Aprender a seleccionar columnas específicas con select() y sus funciones auxiliares.
  • Manejar combinaciones de condiciones lógicas y valores NA en el filtrado.
  • Aplicar el operador pipe (%>%) para encadenar operaciones de manera clara y modular.
  • Realizar análisis exploratorios básicos combinando filter(), select() y pipes en datasets reales.