```{r include=FALSE}
library(tidyverse)
library(tidytext)
```

La idea de "datos ordenados" o _tidy data_ es una forma de manejar de forma efectiva y eso aplica también para el caso de los datos textuales. Según [Hadley Wickham (2004)](https://vita.had.co.nz/papers/tidy-data.pdf) los datos "tidy" tiene tres características:

- Cada variable (o atributo) es una columna
- Cada unidad (u observación) es una fila
- Cada tipo de unidad observacional es una tabla

(Si en esta definición les resuena aquello que en las materias de Metodología de la Investigación se llamaba "estructura tripartita del dato" o lo que Juan Samaja llamaba "estructura cuatripartita del dato" están bien encaminades).

En el contexto de NLP, los datos ordenados van a tener la siguente estructura: un **token** por fila. Un **token** es una unidad conceptual y/o analíticamente signifactivas con las que dividimos un documento. Un **token** puede ser una palabra (ese será el caso más frecuente en este curso) pero también podrían ser [n-gramas](https://es.wikipedia.org/wiki/N-grama), oraciones e incluso párrafos. De hecho, un primer paso en el preprocesamiento de texto es dividir el corpus en **tokens**. Para lo cual, es necesario, entonces, definir qué va a ser un **token**.

Como puede verse esta estructura difiere de otras formas de almacenar el texto crudo

- Cadena: el texto puede, por supuesto, almacenarse como cadenas, es decir, vectores de caracteres, dentro de R y, a menudo, los datos de texto se leen primero en la memoria de esta forma.
- Corpus: estos tipos de objetos suelen contener cadenas sin procesar anotadas con metadatos y detalles adicionales.
- Matriz documento-término: esta es una matriz dispersa que describe una colección (es decir, un corpus) de documentos con una fila para cada documento y una columna para cada término. El valor de la matriz suele ser el recuento de palabras o tf-idf.

Como iremos viendo, va a ser muy fácil pasar del texto en formato tidy a otros formatos. Particularmente, vamos a estar yendo y viniendo entre textos en formato tidy y no-tidy para diferentes tareas. Así, cuando nos toque construir modelos seguramento vamos a tener que pasar a un  formato Matrix-documento-término (TFM). Pero cuando querramos generar gráficos o métricas que nos permitan interpretar ese modelo, seguramente vamos a tener que volver a formato tidy.

## Primer ejemplo
Vamos a empezar con un ejemplo mínimo: un párrafo de Marx. En el famoso "Prólogo a la Contribución a la Crítica de la Economía Política" de 1859 escribió el siguiente párrafo que ha generado infinitas interpretaciones y polémicas. Vamos a guardarlo en un objeto `character` que se va a llamar `marx`.

```{r}
marx <- c("El conjunto de estas relaciones de producción forma la estructura económica de la sociedad, la base real sobre la que se levanta la superestructura jurídica y política y a la que corresponden determinadas formas de conciencia social. El modo de producción de la vida material condiciona el proceso de la vida social política y espiritual en general. No es la conciencia del hombre la que determina su ser sino, por el contrario, el ser social es lo que determina su conciencia. Al llegar a una fase determinada de desarrollo las fuerzas productivas materiales de la sociedad entran en contradicción con las relaciones de producción existentes o, lo que no es más que la expresión jurídica de esto, con las relaciones de propiedad dentro de las cuales se han desenvuelto hasta allí. De formas de desarrollo de las fuerzas productivas, estas relaciones se convierten en trabas suyas, y se abre así una época de revolución social. Al cambiar la base económica se transforma, más o menos rápidamente, toda la inmensa superestructura erigida sobre ella.")

marx
```

¿Qué formato de los que vimos hasta aquí sería este?

Para poder analizarlo como datos tidy, primero tenemos que llevarlo a un dataframe.

```{r}
marx_df <- tibble(line = 1, text = marx)
marx_df
```
¿Qué significa que este dataframe se ha impreso como una "tibble"? Una tibble es una clase de dataframe más "moderna" dentro de R, disponible en los paquetes `dplyr` y `tibble`. Las tibbles tienen un método de impresión conveniente para lo que queremos hacer: no convierten a las cadenas/strings en factores de forma automática y no usa nombres de fila (`ronames``). Las tibbles son ideales para usar con herramientas tidy.

Sin embargo, tengamos en cuenta que este dataframe que contiene texto aún no es compatible con un análisis de texto `tidy`. No podemos filtrar las palabras ni contar las que ocurren con mayor frecuencia, ya que cada fila está formada por varias palabras combinadas. Necesitamos convertir esto para que tenga un **token** por documento por fila.

¿Cuántos documentos tenemos en este ejemplo?

Dentro de nuestro dataframe de texto ordenado, necesitamos dividir el texto en **tokens** individuales (un proceso llamado tokenización) y transformarlo en una estructura de datos ordenada. Para hacer esto, usamos la función `unnest_tokens()` de `tidytext`.

```{r}
library(tidytext)

marx_df %>%
  unnest_tokens(output=word, input=text)
```

Usamos aquí dos argumentos básicos:

- el nombre de la columna de salida que se creará cuando el texto no esté anidado (palabra, en este caso), y luego 
- la columna de entrada de la que proviene el texto (texto, en este caso). 

¿Qué formato tiene ahora nuestro párrafo?

---

**Otros tokens**
Es importante recordar que `marx_df` arriba tiene una columna llamada `text` que contiene los datos de interés. A su vez `unnest_tokens()` realiza la tokenización por defecto usando palabras. Esto puede cambiarse sin problemas, cambiando el parámetro `token`. Por ejemplo,

```{r}
marx_df %>%
  unnest_tokens(word, text, token='sentences')
```

Ahora, tenemos una tibble en la que cada línea es una oración ("sentence") y no una palabra.

A su vez, han pasado otras varias cosas al ejecutar `unnest_tokens` que es importante marcar:

- Se conservan otras columnas, como el número de línea de donde proviene cada palabra.
- Se ha eliminado la puntuación.
- De forma predeterminada, `unnest_tokens()` convierte los tokens a minúsculas, lo que los hace más fáciles de comparar o combinar con otros conjuntos de datos. (Esto puede modificarse utilizando el argumento `to_lower = FALSE`)

Un diagrama del flujo de trabajo puede verse a continuación:

![](https://www.tidytextmining.com/images/tmwr_0101.png)

## Ordenando algunos textos de Marx y Engels
Vamos a trabajar con un dataset que el capo de [Diego Kozlowski](https://sites.google.com/view/diego-kozlowski/home) escrapeó de la sección en español del [Marxist Internet Archive](https://www.marxists.org/espanol/). 

Cargamos los datos:
```{r}
marx_engels <- read_csv('../data/marx_engels.csv')
marx_engels
```

¿Qué estructura tiene este dataset?

Vamos a transformarlo en un formato `tidy`:

```{r}
marx_engels_tidy <- marx_engels %>%
        unnest_tokens(word, texto)
```


```{r}
marx_engels_tidy
```

## Eliminando stopwords
El siguiente paso es la eliminación de las llamadas **stopwords**. Se trata de palabras que o bien por su función sintáctica (pronombres, preposiciones, adverbios, etc.) o por su frecuencia (aparecen en gran frecuencia) aportan poca información semántica al texto.

En general, la forma estándar y más inmediata de lidiar con ellas es mediante su eliminación a través de una lista. La idea es matchear las palabras en nuestro corpus con las que estén en esa lista y eliminar las que coinciden. Carguemos la lista con las **stopwords**, al mismo tiempo, vamos a eliminar los acentos de esta tabla.

```{r}
stop_words <- read_csv('https://raw.githubusercontent.com/Alir3z4/stop-words/master/spanish.txt', col_names=FALSE) %>%
        rename(word = X1) %>%
        mutate(word = stringi::stri_trans_general(word, "Latin-ASCII"))
```

Ahora sí, podemos removerlas usando la funcion `anti_join`:

```{r}
marx_engels_tidy <- marx_engels_tidy %>%
  anti_join(stop_words)
```

Fíjense cómo pasamos de aprimadamente 1.000.000 de palabras a 529.000 luego de eliminar las stop_words.

Ahora bien, ¿cuáles son las palabras más usadas por Marx y Engels?

```{r}
marx_engels_tidy %>%
        count(word, sort=TRUE)
```

-------

### Actividad

Escribir el código para replicar la tabla anterior usando los comandos del `tidyverse`

```{r}
###
```

-------

Debido a que hemos estado usando herramientas del estilo tidy, nuestros recuentos de palabras se almacenan en una tibble en ese formato (tidy data). Esto nos permite pasar casi sin mediaciones a nuestro viejo amigo `ggplot2`, por ejemplo, para crear una visualización de las palabras más comunes:

```{r}
marx_engels_tidy %>%
        count(word, sort=TRUE) %>%
        filter(n > 600) %>%
        mutate(word = reorder(word, n)) %>%
        ggplot(aes(n, word)) +
                geom_col() +
                labs(y = NULL)
```

Podríamos evaluar ahora si Marx y Engels usan diferentes palabras en las cargas y notas y en sus libros. Para ello vamos a tener que procesar un poco el campo de `titulo`:

```{r}
marx_engels_tidy <- marx_engels_tidy %>%
        mutate(tipo = case_when(
                str_detect(titulo, 'Carta') ~ 'cartas',
                TRUE ~ tipo
        )) 
```

Utilizamos la función `str_detect` del paquete `stringr` para testear si cierto patrón está en un determinado texto. Más precisamente, en este caso buscamos para cada fila si la palabra `Carta` aparece en las filas de `título`. 

Combinamos esta función con `case_when` y `mutate` para modificar la columna `tipo` y agregar una categoría de cartas.

A partir de ahora podemos utilizar las herramientas del tidyverse para contar y manipular palabras.

```{r}
freqs <- marx_engels_tidy %>%
        mutate(word = str_extract(word, "[a-z']+")) %>% #Nos quedamos con las letras
        group_by(tipo, word) %>% #Agrupamos por tipo y word
        summarise(n = n()) %>%
        mutate(
                total = sum(n),
                prop = n/total*100
                ) %>%
        ungroup() %>%
        select(tipo, word, prop) %>%
        pivot_wider(names_from = tipo, values_from = prop) 

freqs
```

Y ahora podemos hacer un gráfico en el que comparamos la frecuencia de uso de las diferentes palabras en los libros y las notas: 

```{r}
freqs %>%
ggplot( aes(notas, libros)) +
  geom_jitter(alpha = 0.05, size = 2.5, width = 0.25, height = 0.25) +
  geom_text(aes(label = word), check_overlap = TRUE, vjust = 1.5) +
  scale_x_log10() +
  scale_y_log10() +
  geom_abline(color = "red") +
  theme_minimal()
```

Las palabras que están cerca de la línea en estos gráficos tienen frecuencias similares en ambos conjuntos de textos, por ejemplo, tanto en los libros de Marx y Engels como en las aparecen con frecuencias simialres: burguesa, acción, campesinos, abolición, comuna, producción, clase. En cambio, en los libros parecen aparecer palabras como autoconciencia, during, espípirtu, matemática. En las notas periodísitcas aparecen palabras ligadas a la acción política: congreso, consejo, estatutos, conferencia, etc.

-------

### Actividad
Repetir el ejercicio comparando las cartas con los libros

```{r}
###
```

-------



