La sección práctica de la tercera clase del curso consistió en dar ejemplos para introducir el concepto de expresiones regulares. El código puede descargarse aquí.
A partir de dicho código, realice un tutorial explicando al menos tres de los ejemplos ahí presentados.
Si existiera un tibble con fechas que no coinciden en formato, las funciones de los paquetes stringr y rebus pueden ayudarnos a homologarlas. Estos son los pasos para consegurlo.
Antes que todo hay que asegurarse que estén instalados los paquetes necesarios:
#Instalar paquetes
library(rebus)
library(tidyverse)
library(readxl)
library(rtweet)
A continuación mostarmos un ejemplo de tibble con el que trabajaremos
#Generamos un tibble (ejemplo)
fechas <- tribble(~Fechas,
"01-01-2001",
"Primero de Enero del 2001",
"01/01/2001",
"01 01 2001",
"01@01@2001",
"01_01_2001",
"01-Ene-2001")
Gracias a regex en rebus podemos ver que las fechas no están homologadas.
Primero vamos a capturar nuestra expresión regular creando un patrón, que agregaremos a un objeto llamado pat. Esto lo logramos atrapando los espacios entre palabras con SPC.
#Selección de espacios, de y del usando`%R%` (coloquialmente lo llamamos pegamento) para atrapar las palabras. Luego, invertimos el proceso: `%R%` `SPC`.
pat <- SPC %R% or1(c("de", "del")) %R% SPC
str_view_all(fechas$Fechas,
pattern = pat)
#Ejectutar el patrón que remplazará todo por guiones
fechas$Fechas <- str_replace_all(fechas$Fechas,
pattern = pat,
replacement = "-")
El siguiente paso será utilizar un objeto en rebus llamado char_class, una funciónque sirve para definir un conjunto de caracteres que van a formar parte del patron. Es decir, todo los caracteres que contenga entre paréntesis van a ser seleccionados en el nuevo patrón.
Para ello debemos introducir los caracteres “-/@_” en dicha función y luego reemplazarlos por un guión “-”
#Función char_class
pat <- or1(char_class("-/@_", SPC))
str_view_all(fechas$Fechas,
pattern = pat)
#Ejecutar patrón que reemplazará todo por guiones
fechas$Fechas <- str_replace_all(fechas$Fechas,
pattern = pat,
replacement = "-")
fechas$Fechas
## [1] "01-01-2001" "Primero-Enero-2001" "01-01-2001"
## [4] "01-01-2001" "01-01-2001" "01-01-2001"
## [7] "01-Ene-2001"
En este último paso debemos utilizar una función de stringr str_remplace_all para reemplazar todas las palabras que falten por el mes que necesitamos (en este ejemplo “Enero” y “Primero” serán sustituidos por 01).
Nota: los cambios son escalonados, por lo cual, en el ejemplo “Enero” debe ir antes de “Ene”, de otra manera, “Ene” se sustuituirá como “01”, y “Enero” se convertirá en “01ro”, por lo cual no se realizaría el cambio esperado.
str_replace_all(fechas$Fechas, c("Primero" = "01",
"Enero" = "01",
"Ene" = "01"))
## [1] "01-01-2001" "01-01-2001" "01-01-2001" "01-01-2001" "01-01-2001"
## [6] "01-01-2001" "01-01-2001"
“No olvides que los formatos de fecha son diferentes dependiendo de la región…”
Es un paquete de la familia Tidyverse para trabajar cadenas de texto, que son las variables tipo character. Posee características importantes que nos permiten crear patrones y modificar las cadenas de muchas formas.
Las cadenas no son componentes glamorosos y de alto perfil de R, pero juegan un papel importante en muchas tareas de limpieza y preparación de datos. El paquete stringr proporciona un conjunto cohesivo de funciones diseñadas para hacer que trabajar con cadenas sea lo más fácil posible. – Sitio web de stringr
En programación, no sólo R si no otros algunos lenguajes de programación, contamos con una herramienta muy poderosa conocida como redex (regular expressions) o expresiones regulares
Son secuencias de caracteres para definir un patrón de búsqueda. Las expresiones regulares sirven tanto para quedarnos con palabras/frases importantes, así como para deshacernos de ellas.
Son como la “navaja suiza” para trabajar con datos de texto, es una inversión de tiempo que todo analista tiene que hacer. – Juvenal Campos
En R existe este paquete que nos facilita el poder utilizar estas herramientas de captura de texto, ya que tiene una librería {rebus} que es como una interfaz que nos permite convertir texto un poco más legible a esas expresiones regulares. Más detalles
str_view() y str_view_all()? ¿Cuál es la diferencia entre ambas?str_view() Atrapa la primera ocurrencia del patrón. str_view_all() Atrapa todas las ocurrencias del patrón.
La diferencia es que str_vie wmuestra la primera coincidencia y str_view_allmuestra todas.
str_detect() ystr_detect_all()? ¿Cuál es la diferencia entre ambas?str_detect() Detecta cadenas de texto que incluyen un patrón en particular *Es muy útil para filtrar
str_detect_all() No vimos esta función en clase, pero en este sitio web dice que “devuelve un vector lógico con resultados de Stri_detect () para cada patrón en el segundo vector de caracteres de parámetros”.
str_replace() y str_replace_all()? ¿Cuál es la diferencia entre ambas?str_replace() Busca patrones que estan en una cadena de texto y los replaza por otro nuestro
str_replace_all() Reemplaza todos los patrones coincidentes en cada cadena de texto
str_remove() y str_remove_all()? ¿Cuál es la diferencia entre ambas?str_remove() Remueve la primera coincidencia de un patrón
str_remove_all() Remueve TODAS las coincidencias de un patrón
La primera funciona con la primera coincidencia y la segunda para todo el texto.
str_extract() y str_extract_all()? ¿Cuál es la diferencia entre ambas?str_extract() Extrae patrones de una cadena de texto str_extract_all() Extrae patrones de una cadena de texto de cada coincidencia del patrón
La primera función se detiene en la primera coincidencia y la segunda aplica a toda la cadena de texto.
Estas son las librerías que utilizaremos en la sección práctica. Cárgalas o instalalas en caso de que no las tengas instaladas en tu computadora.
# Librerias
library(tidyverse)
library(rebus)
library(htmltools)
Dados los siguientes numeros de telefono guardados en numeros, limpie los datos de tal forma que todos los numeros tengan el mismo formato. Para esto, utilice expresiones regulares y funciones de stringr.
(Sugerencia: El formato puede ser el que usted defina, pero el mas facil es que sean solo los numeros, sin símbolos raros).
numeros <- c("(595)107-3344",
"(890)-123-4465",
"999 107 5243",
"999_989-0756")
Vamos a limpiar el tibble numeros. Para ello crearemos nuestra expresión regular creando un patrón, que agregaremos a un objeto llamado telefono.
# 2. Generamos una regex que capture todos los numeros contenidos entre paréntesis, guiones bajos y cortos y Espacios
telefono <- char_class("-/_()", SPC)
str_view_all(numeros, pattern = telefono)
# Remover todos los elementos que señale el patrón que ya hicimos
numeros <- str_remove_all(string = numeros, pattern = telefono)
#Al reemplazar el objeto numeros, tenemos el resultado que queríamos.
#Comprobación:
numeros
## [1] "5951073344" "8901234465" "9991075243" "9999890756"
La siguiente base de datos contiene tweets publicados tras el estreno de la pelicula " Joker (2019)".
library(tidyverse)
library(rebus)
bd <-
read_csv("https://raw.githubusercontent.com/JuveCampos/miniProyectos/master/elJokerWordCloud/db.csv")
glimpse(bd)
## Rows: 1,028
## Columns: 12
## $ value <chr> "The Trend @thetrend___ 19m 19 minutes ago More \"So…
## $ nombre <chr> "The Trend", "Amir Alonso Pinardel", "Jaime", "Americ…
## $ usuario <chr> "@thetrend___", "@amiralonsopinar", "@blackjim7", "@A…
## $ fecha <chr> "2019-10-05", "2019-10-05", "2019-10-05", "2019-10-05…
## $ retweets <dbl> 3, NA, NA, 1, NA, NA, 1, NA, NA, NA, NA, NA, NA, NA, …
## $ like <dbl> 6, 1, 2, NA, NA, 1, 1, NA, 1, NA, NA, 1, NA, 2, 25, 3…
## $ replies <dbl> NA, 1, NA, NA, NA, NA, 1, NA, 1, NA, NA, NA, NA, 1, 3…
## $ texto <chr> "\"Solía pensar que mi vida era una tragedia, pero ah…
## $ hashtags <chr> "#Joker, #Guasón, #JokerMovie", "#Joker", "#JokerMovi…
## $ ctasMencionadas <chr> NA, "@jokermovie, @comicsarg", NA, "@AHSFX, @jokermov…
## $ nombres_propios <chr> "Solía, Joaquin, Phoenix, Joker, Guasón, JokerMovie",…
## $ fecha2 <date> 2019-10-05, 2019-10-05, 2019-10-05, 2019-10-05, 2019…
La tabla contiene 1,028 elementos con 12 columnas. Estas representan lo dicho en Twitter de la película Joker, desde el posteo en bruto y quién lo hizo (value), nombre de quien lo publicó (name), el usuario que tuiteó (usuario), la fecha, los retweets, me gusta, replies, texto ya filtrado (texto), hashtags, cuentas mencionadas, nombres propios y fecha enformato homologado (fecha2).
#Primero sugiero que convirtamos en minúsculas todas las palabras en la columna "texto", por si hubiera una que esté en mayúsculas. Podemos crear otra columna, acá la llamaré "texto2"
bd$texto2 <- str_to_lower(bd$texto)
#Ahora hay que crear el objeto "Bromas", detectando sólo los tuits que tengan el patrón "el bromas"
Bromas <- bd %>%
select(texto2) %>%
mutate(bromas_tweets = str_detect(string = texto2, pattern = "el bromas")) %>%
filter(bromas_tweets == TRUE)
#Por último, imprimimos los primeros 15 renglones con la función head
head(Bromas, 15)
## # A tibble: 15 x 2
## texto2 bromas_tweets
## <chr> <lgl>
## 1 "el nuevo guasón aka “el bromas” o “the joker” me recordó un b… TRUE
## 2 ". 🎬 🎥 🖤 🐾 🎼 📷 🎶joker / guason / el bromas @jokermovie… TRUE
## 3 "cuando te quieres burlar de los españoles inventando que a la… TRUE
## 4 "🇬🇹el bromas #jokermovie #jokerfilm #joker #guason" TRUE
## 5 "el guasón the joker el bromas lenín moreno #jokermovie" TRUE
## 6 ". zafra a. 🦇: the joker : el bromas : el guasón : el guaco … TRUE
## 7 "🃏ahora resulta que todos son fans del bromas! #jokermovie #j… TRUE
## 8 "el nombre en español debería ser \"el arlequin\", no el broma… TRUE
## 9 "¿es neta que en españa al \"joker\" alias el \"guasón\" le ll… TRUE
## 10 "\uf8ff the joker el guasón ¿el bromas? ¡no se pasen! #jo… TRUE
## 11 "a bailar al ritmo del peter y de 'el bromas' #spiderman #spi… TRUE
## 12 "el bromas estuvo bien cabrona. será que tenemos un segundo gu… TRUE
## 13 "esta con madre el promocional del \"el bromas\" #dc #guasón #… TRUE
## 14 "noticia de ultimo momento acaban de detener a \"el bromas\" … TRUE
## 15 "#joaquinphoenix #jokermovie guasón el bromas" TRUE
Tuve problemas para este ejercicio, así que recurrí a internet. Encontré esta solución temporal
# Creamos un patrón de las groserías que queremos eliminar
pat_gros <- c("puta", "hija de puta", "puto", "hijueputa", "cabronada", "estupido", "idiota", "mierda", "pinche", "chingªd@")
#Con la siguiete fórmula creamos el objeto bd_censurada, que eliminará todas los tuits que contienen malas palabras (los que ya habíamos seleccionado)
bd_censurada <- bd[ !grepl(paste(pat_gros, collapse="|"), bd$texto2),]
#Creamos ahora un patrón con las variables de Guaidó
Guaid <- c("-guaido","guaido","Guaidó", "Guaido")
# La siguente fórmula elimina los tuits que contienen estas variantes
bd_censurada <- bd_censurada[ !grepl(paste(Guaid, collapse="|"), bd_censurada$texto2),]
head(bd_censurada$texto2)
## [1] "\"solía pensar que mi vida era una tragedia, pero ahora me doy cuenta que es una comedia\"... joaquin phoenix, el actor que el mundo aclama en la gran película #joker #guasón #jokermovie"
## [2] "acabo de ver @jokermovie y debo decir que es una verdadera obra cinematográfica. sin duda este guason moviliza y nos pasea por diferentes estados. un #joker psicodélico y símbolo de un sistema injusto, corrompido. un auténtico agente del caos!!! @comicsarg"
## [3] "estoy sin palabras! joaquin maestro! #jokermovie #joker #guason #elbromas 11/10"
## [4] "la magistral frances conroy participa en la película del icónico personaje de dc comics joker (guasón) interpretando a la mamá del protagonista penny fleck. no se pierdan su excelente participación a la que nos tiene acostumbrados #ahs @ahsfx @jokermovie"
## [5] "“the worst part of having a mental illness is people expect you to behave as if you don't.” joker (2019) #jokermovie \"la peor parte de tener una enfermedad mental es que la gente espera que te comportes como si no la tuvieras\" guasón (2019)"
## [6] "#joker bate records en su primer día de proyecciones #jokermovie #jokerfilm #guason https://redlan.com.ar/index.php/2019/10/05/joker-bate-records-en-su-primer-dia-de-proyecciones/ …"
Hay que crear un diccionario de reemplazo de las palabras guasón y guason, para que sean joker.
remp <- c("guason" = "joker",
"guasón" = "joker")
Después hacemos el reemplazo, en este caso crearé una columna llamada “español” para hacer el comparativo con “texto2” (que era nuestro texto en minúsculas)
reemplazo <- bd %>%
select(texto2) %>%
mutate(español = str_replace_all(texto2, remp))
#Imprimir los primeros 15 resultados
head(reemplazo, 15)
## # A tibble: 15 x 2
## texto2 español
## <chr> <chr>
## 1 "\"solía pensar que mi vida era una t… "\"solía pensar que mi vida era una t…
## 2 "acabo de ver @jokermovie y debo deci… "acabo de ver @jokermovie y debo deci…
## 3 "estoy sin palabras! joaquin maestro!… "estoy sin palabras! joaquin maestro!…
## 4 "la magistral frances conroy particip… "la magistral frances conroy particip…
## 5 "“the worst part of having a mental i… "“the worst part of having a mental i…
## 6 "#joker bate records en su primer día… "#joker bate records en su primer día…
## 7 "\uf8ffviðarr odinson \uf8ff retweete… "\uf8ffviðarr odinson \uf8ff retweete…
## 8 "replying to @oswaldoriosm @jokermovi… "replying to @oswaldoriosm @jokermovi…
## 9 "cuando te enteras que el guasón y el… "cuando te enteras que el joker y el …
## 10 "replying to @warkentin @jokermovie s… "replying to @warkentin @jokermovie s…
## 11 "el nuevo guasón aka “el bromas” o “t… "el nuevo joker aka “el bromas” o “th…
## 12 ". 🎬 🎥 🖤 🐾 🎼 📷 🎶joker / guaso… ". 🎬 🎥 🖤 🐾 🎼 📷 🎶joker / joker…
## 13 "guasón / joker ★★★★★ @jokermovie" "joker / joker ★★★★★ @jokermovie"
## 14 "haciendo mi tarea para ver @jokermov… "haciendo mi tarea para ver @jokermov…
## 15 "¡intensa, hilarante y perturbadora! … "¡intensa, hilarante y perturbadora! …
En este caso, hay que extraer numéricamente los likes con arrange (el signo menos para que le de orden), elegí
top_npara ver los 10 con más likes, podemos ver que los primeros likes los tiene el mismo tuit, habría que analizar ese dato para ver si no está repetido. El de más likes es el de @pagusrendon, con 517 likes
bd %>%
arrange(-like) %>%
top_n(10, like) %>%
select(usuario, like, texto)
## # A tibble: 10 x 3
## usuario like texto
## <chr> <dbl> <chr>
## 1 @pagusrendon 517 EEUU Joker Italia Burlone México Guasón España El…
## 2 @warkentin 499 A mi me gustó @jokermovie. Mucho. Mucho mucho.
## 3 @DCcomicsMX 455 El Verdadero Origen del #Joker ¿Conoces The Man Who La…
## 4 @DCcomicsMX 453 El Verdadero Origen del #Joker ¿Conoces The Man Who La…
## 5 @DCcomicsMX 453 El Verdadero Origen del #Joker ¿Conoces The Man Who La…
## 6 @gioalicari 408 💎#Guason #JokerMovie imposible no pensar en heath ledger…
## 7 @SanCadilla 304 Ya fui a ver El Guasón y parece una película de héroes, …
## 8 @connieansal… 275 Totalmente en Shock con el Guason. Imposible no querer a…
## 9 @DCcomicsMX 243 SIN SPOILERS ¡YA VIMOS #JOKER Y QUEDAMOS IMPACTADOS! No…
## 10 @DCcomicsMX 176 Ya sea en cómic, animación o Live Action, todas las enca…
En el caso de los retuits, utilizaremos la misma fórmula sólo con la columna ‘retweets’. Veremos que de más retuits fue el de la cuenta @DCComicsMX, con 148, que también ocupa el segundo y tercer lugar con el mismo tuit.
bd %>%
arrange(-retweets) %>%
top_n(10, retweets) %>%
select(usuario, retweets, texto)
## # A tibble: 11 x 3
## usuario retweets texto
## <chr> <dbl> <chr>
## 1 @DCcomicsMX 148 El Verdadero Origen del #Joker ¿Conoces The Man Who L…
## 2 @DCcomicsMX 148 El Verdadero Origen del #Joker ¿Conoces The Man Who L…
## 3 @DCcomicsMX 147 El Verdadero Origen del #Joker ¿Conoces The Man Who L…
## 4 @gioalicari 74 💎#Guason #JokerMovie imposible no pensar en heath ledge…
## 5 @pagusrend… 65 EEUU Joker Italia Burlone México Guasón España E…
## 6 @DCcomicsMX 46 Ya sea en cómic, animación o Live Action, todas las enc…
## 7 @DCcomicsMX 45 Ya sea en cómic, animación o Live Action, todas las enc…
## 8 @DCcomicsMX 45 Ya sea en cómic, animación o Live Action, todas las enc…
## 9 @SanCadilla 44 Ya fui a ver El Guasón y parece una película de héroes,…
## 10 @El_Abogad 40 🐼 ⚖¿Qué obtienes cuándo mezclas a un enfermo mental y …
## 11 @Undiasoy 40 ♡Lo peor de tener una enfermedad mental es que la gente…
Para este resultado haremos uso de la función count y sort para que lo ordene. Podemos ver que el usuario que más tuiteó fue @DCComicsMX, 14 veces.
bd %>%
count(usuario, sort = TRUE) %>%
top_n(10)
## # A tibble: 10 x 2
## usuario n
## <chr> <int>
## 1 @DCcomicsMX 14
## 2 @FormerlyKnow 10
## 3 @guillemancandy 8
## 4 @elespectador 6
## 5 @VerGuason_2019 6
## 6 @altapeli 5
## 7 @JMRivaPalacio 5
## 8 @danitafashion 4
## 9 @edwin_digital 4
## 10 @InconformeSiem1 4
Se puede crear una gráfica desde un nuevo tibble para no alentar el equipo, pero si no, sólo hay que crear un nuevo objetoy graficarlo.
#Creamos el objeto Usuarios
Usuarios <- bd %>%
count(usuario, sort = TRUE) %>%
top_n(5)
#Hacemos la gráfica
library(ggplot2)
Usuarios %>%
ggplot(aes(x=n, y=usuario)) +
geom_bar(colour="black", fill="#DD8888", width=.8, stat="identity") +
geom_text(aes(label=n), hjust=2,color="black", size=4) +
guides(fill=FALSE) +
xlab("Número de tuits") + ylab("Usuario") +
ggtitle("¿Quién tuiteó más sobre la película Joker")
Me gusta mucho la idea de manejar bases de datos con lo que publican los usuarios en Twitter. El proyecto podría ser un análisis de lo publicado en determinado momento en redes sociales. También puede ser analizar discursos, sé que es retador pero sería muy bueno para mi carrera.