# Importamos las librerías necesarias.
# pacman las instala con las dependencias si es necesario.
# El paquete datos se instala desde git:
# remotes::install_github("cienciadedatos/datos")
rm(list = ls())
pacman::p_load(tidyverse,
janitor,
pdftools,
datos,
devtools)
Repositorio del taller aquí
Regex + Tidyverse
Manera que tenemos de pedirle a la computadora que busque un patrón, pensar las expresiones regulares como una lengua especial.
Nos permiten ir de lo literal o abstracto a lo general. Por ejemplo encontrar un número en cualquier parte del texto.
Podemos indicarlo con: \d
ó [:digit:]
ó [0-9]
. Existen muchas más categorías, podemos revisar la hoja de referencia de stringr:
Ejemplos
\d
cualquier dígito\w
cualquier caracter de palabra\s
espacio en blanco\b
límite de palabra\D
cualuier NO dígito\W
cualquier NO caracter de palabra\S
no espacios en blanco.
cualquier caractér saltos de líneaPor ejemplo \d{4}
nos permite cuantificar y encontrar patrones de 4 dígitos.
?
0 o 1 vez+
1 o más*
0 o más{n}
exactamente nQuiero encontrar una secuencia de cuatro números que estén l final de una cadena de texto: \d{4}$
utilizando el ancla:
^
al inicio del string$
al final del stringPor ejemplo, quiero encontrar la palabra programación con o sin tilde en la o:
programac[o|ó]n
( )
para crear gruposSupongamos que tenemos: "Stark, Arya"
yo puedo encerrar en paréntesis y separar en grupos "(Stark), (Arya)"
donde \1 corresponde a Stark y \2 corresponde a Arya
.
En R debemos de usar una doble barra \\d
para que signifique \d
, o bien \\?
para que signifique \?
. No es el caso cuando utilizamos la notación: [:digit:]
.
# Importamos desde el repositorio de Github de @rivaquiroga
animales <-
read_csv("https://raw.githubusercontent.com/rivaquiroga/latinr-taller-regex/master/datos/animales.csv")
camarones <-
read_delim("https://raw.githubusercontent.com/rivaquiroga/latinr-taller-regex/master/datos/casen_camarones.csv",";")
telefonos <-
read_csv("https://raw.githubusercontent.com/rivaquiroga/latinr-taller-regex/master/datos/telefonos.csv")
Veremos las posibilidades que existen con la función filter()
Podemos filtrar con str_detect para buscar de manera más flexible en la base de datos, por ejemplo para encontrar el string “Corea” en nuestra columna de paises:
Para buscar México con y sin acento en nuestra base de datos podemos usar [ | ]
con str_detect
dentro de filter
.
Observemos nuestra base:
Notar que no hay homogeneidad en la forma en que las personas escribieron sus datos, algunos utilizaron coma para los nombres, la ciudad con letra mayúscula, el número de teléfono con clave internacional etc.
Esto lo podemos resolver con las herramientas de regex.
Nos muestra las observaciones distintas para cada categoría. Nos permite observar las diferencias en las categorías.
A continuación queremos identificar las observaciones de Quilpué con y sin acento:
Ahora buscamos Valparaíso en todas las formas posibles:
str_detect
nos permite hacer las modificaciones necesarias para encontrar los distintos elementos.
¿Cómo podemos arreglar? Con la función case_when
de Tidyverse que nos permite modificar una variable basado en ciertas condiciones:
case_when
va lo que queremos encontrar (la condición) y del lado derecho a lo que queremos convertir. Con la función mutate()
creamos la nueva columna ciudad_limpia para observar nuestras modificaciones.telefonos %>%
mutate(ciudad_limpia=case_when(
str_detect(ciudad,"[V|v]alpara[i|í]so") ~ "Valparaíso",
TRUE ~ as.character(ciudad)
))
# Le estoy diciendo que para todas las observaciones que cumplan la condición las convierta en Valparaíso, y para todo lo demás, lo deje como caracter.
Notar que ahora todas las observaciones de Valparaíso están uniformes en mayúsculas y con tilde.
Agregemos más condiciones para corregir el resto de ciudades y sobreescribimos nuestra base:
telefonos <- telefonos %>%
mutate(ciudad_limpia=case_when(
str_detect(ciudad,"[V|v]alpara[i|í]so") ~ "Valparaíso",
str_detect(ciudad,"quilpu[e|é]") ~ "Quilpué",
str_detect(ciudad,"Serena") ~ "La Serena",
TRUE ~ as.character(ciudad)
))
peliculas <- read_csv("https://raw.githubusercontent.com/cienciadedatos/datos-de-miercoles/master/datos/2020/2020-02-19/ranking_imdb.csv")
head(peliculas,4)
Notar que en la columna género tenemos un género principal y los géneros secundarios después de la coma, entonces podemos agrupar.
Utilizamos la función separate
que requiere la columna principal y las columnas en las que queremos separar.
pelis_sep <- peliculas %>%
separate(genero, into=c("genero_principal","genero_secundario"),sep = ", ")
Notar que estamos perdiendo información para las películas que tienen más de dos géneros secundarios. Podemos ayudarnos del argumento remove = T,F
que nos permite quitar la columna objetivo, la fijamos en Falso para darnos cuenta de la pérdida de datos.
pelis_sep <- peliculas %>%
separate(genero, into=c("genero_principal","genero_secundario"),sep = ", ", remove = F)
El argumento extra
nos permite controlar cuando hay más de dos “piezas”, por defecto viene en “warn” que nos avisa cuando elimina todos los valores extra, con “merge” junta todo lo que sobra.
pelis_sep <- peliculas %>%
separate(genero, into=c("genero_principal","genero_secundario"),sep = ", ", remove = F, extra = "merge")
Ahora tenemos todos los géneros secundarios en nuestra columna de genero_secundario.
Podemos separar nuestras observaciones de acuerdo a una característica repitiendo todas las demás variables.
Observamos que género se transformó y ahora tenemos una observación para cada género que tiene una película.
Debemos tener cuidado con la codificación de nuestra base de datos (ASCII, UTF-8,)
Notar el problema que tenemos para algunas observaciones como guanaco donde la variable s1 para año y mes tiene distintos datos:
animales_limpio <- animales %>%
pivot_longer(starts_with("s"),
names_pattern="(.*)_monitoreo(.*)_(.*)",
names_to=c("sitio","año","mes")) %>%
separate_rows(value)
Latin R, R-Ladies↩︎
El Colegio de México, diego.lopez@colmex.mx↩︎