PARTE 1

1. Aprendizaje supervisado: Problemas de clasificación

1.1. Definiciones necesarias para el análisis

Aprendizaje supervisado: Tenemos una variable dependiente (output) continua o categórica, y queremos predecirla con un conjunto disponible de variables explicativas (input).

Problema de clasificación: Tenemos como variable dependiente una del tipo categórica (i.e. con dos o más clases) que buscamos predecir.

A continuación podemos ver qué algoritmos podremos usar acorde a la variable que buscamos predecir dentro del aprendizaje supervisado.

Estos algoritmos se explicarán a medida que sean usados.

1.2. Caso de estudio: Detección de noticias falsas

Las noticias falsas son una forma de noticias que consiste en desinformar o no informar deliberadamente a través de distintos medios de comunicación tradicionales. Para detectarlas existen algunos recursos que pueden ser construidos a partir de técnicas de PLN, tanto de aprendizaje supervisado, como de aprendizaje no supervisado, que nos ayuden a detectarlas.

Específicamente, en este caso de estudio se busca crear un algoritmo de aprendizaje supervisado que sea capaz de clasificar tweets en falsos o verídicos para el contexto ecuatoriano, usando los posts que se pueden encontrar en las páginas de Twitter de distintos medios de comunicación.

2. Preprocesamiento y exploración de datos

2.1. Carga de datos

Para iniciar este ejercicio cargaremos la librerías necesarias en esta sección. Estas se enlistan a continuación:

library(tidyverse)
library(tidytext)
library(udpipe)
library(stopwords)
library(syuzhet)
library(mlr3)
library(summarytools)

Una vez que las librerías han sido cargadas, exploraremos los datos disponibilizados por el profesor. Estos se pueden encontrar en la carpeta de Google Drive. Para cargarlos ejecutaremos la siguiente línea de código, asegurándonos de que los datos hayan sido correctamente cargados.

fake_news_df = readRDS("Data/DeteccionNoticiasFalsas/2103_fake_news_df.RDS")
fake_news_df %>% head(3)

Como se puede notar, el archivo cargado corresponde a datos crudos extraídos desde Twitter. Verifiquemos entonces las cuentas de las cuales se han obtenido estos tweets, a la vez que observamos el tipo de tweet (orgánico, respuesta o retweet). Para ello crearemos gráficos.

# Definición del tipo de tweet
fake_news_df = fake_news_df %>% 
  mutate(tipo_tweet=case_when(is_retweet==T~"Retweet",
                              !is.na(reply_to_status_id)==T~"Respuesta",
                              T~"Orgánico"))

# Gráfico de cuentas por tipo de tweet
fake_news_df %>% 
  count(screen_name, tipo_tweet) %>% 
  ggplot(aes(x=tipo_tweet, y=n, fill=screen_name))+
  geom_col(position = "dodge")+
  theme(legend.position = "bottom",
        text = element_text(size=11))

En este conjunto de datos existen un total de 13892 tweets, donde casi todos ellos son orgánicos. Recordemos que un tweet orgánico es aquel publicado originalmente por la cuenta en análisis. Para detectar noticias falsas a partir de la cuenta original que publica un tweet, nos quedaremos solo con los orgánicos.

# Filtrado de tweets orgánicos
fake_news_df = fake_news_df %>% 
  filter(tipo_tweet=="Orgánico")

# Confirmación de filtro
fake_news_df %>% 
  count(screen_name, tipo_tweet) %>% 
  ggplot(aes(x=tipo_tweet, y=n, fill=screen_name))+
  geom_col(position = "dodge")+
  theme(legend.position = "bottom",
        text = element_text(size=11))

En este gráfico podemos confirmar que el conjunto de datos tiene ahora solamente tweets orgánicos de cinco cuentas:

  • @el_mercioco
  • @elMercioEC
  • @el_telegrafo
  • @elcomerciocom
  • @eluniversocom

En la siguiente sección nos ayudaremos de este análisis para definir la variable a predecir.

2.2. Creación de la variable objetivo

De las cuentas de twitter exploradas anteriormente, las dos primeras fuentes, acorde a Fundamedios corresponden a páginas de sátira o parodia que podrían engañar a los lectores con sus ‘noticias’, o su vez, arrancarles una risa (o un improperio). Las otras tres fuentes en cambio, corresponden a las páginas de twitter oficiales de tres medios de comunicación ecuatorianos: ‘El Comercio’, ‘El Universo’ y ‘El Telégrafo’, en los cuales las noticias corresponden a una fuente confiable y verídica.

En tal contexto, crearemos ahora la variable a predecir (variable dependiente u output) definida como:

\[ y = \begin{cases} \text{1,} &\quad\text{si la noticia es falsa (es publicada por @el_mercioco o @elMercioEC).}\\ \text{0,} &\quad\text{si la noticia viene de una fuente confiable.} \\ \end{cases} \]

Esto se logra a través del siguiente código.

# Creación de variable target
fake_news_df = fake_news_df %>% 
  mutate(target_falsa = case_when(screen_name %in% c("el_mercioco","ElMercioEC")~1,
                                  !screen_name %in% c("el_mercioco","ElMercioEC")~0))

# Comprobación
fake_news_df %>% 
  count(screen_name, target_falsa) %>% 
  ggplot(aes(x=target_falsa, y=n, fill=as.factor(screen_name)))+
  geom_col()+
  theme(legend.position = "bottom",
        text = element_text(size=11))

2.3. Creación de la variables explicativas

Para la creación de variables explicativas utilizaremos tanto criterios cualitativos como cuantitativos explotados a partir de los datos de texto (y por qué no, de metada adicional como el uso de hashtags). Comencemos entonces observando algunos ejemplos de los tweets en análisis.

fake_news_df %>%
  group_by(screen_name) %>% 
  slice_sample(n = 1) %>% 
  select(text)
Adding missing grouping variables: `screen_name`

En primer lugar crearemos una variable que cuente tanto el número de símbolos de admiración como interrogación que se utilicen en el texto, debido a que en noticias de fuentes oficiales el tipo de escritura suele ser más formal y elaborado. Para corroborar su creación, verificaremos medidas descriptivas para cada cuenta.

# Creación de variables
fake_news_df = fake_news_df %>%
  mutate(n_signos_admiracion = str_count(text, "\\!"), 
         n_signos_interrogacion = str_count(text, "\\?"))

# Descriptiva de variables
fake_news_df %>%
  group_by(screen_name) %>%
  summarise(n_signos_admiracion=mean(n_signos_admiracion),
            n_signos_interrogacion=mean(n_signos_interrogacion)) %>%
  pivot_longer(c(n_signos_admiracion, n_signos_interrogacion)) %>%
  ggplot(aes(x=screen_name, y=value, fill=as.factor(name)))+
  geom_col(position="dodge")+
  theme(legend.position = "bottom",
        text = element_text(size=11))

Ahora calcularemos el tamaño y variedad del diccionario de cada tweet, además del número de palabras usado por cada tipo de etiqueta POS, en la misma línea de pensamiento anterior.

# Carga de modelo udpipe
# udpipe_download_model(language = "spanish")
model_spanish = udpipe_load_model("spanish-gsd-ud-2.5-191206.udpipe")

# Anotación de datos
fake_news_ann_df = udpipe_annotate(model_spanish, x = fake_news_df$text,
                                   doc_id = fake_news_df$status_id) %>% 
  as_tibble()

# Creación de variables respecto al diccionario
fake_news_dict_df = fake_news_ann_df %>%
  group_by(doc_id) %>% 
  summarise(n_palabras = n(), 
            n_palabras_unicas = n_distinct(tolower(lemma)))

# Creación de variables respecto a la etiqueta POS
fake_news_pos_df = fake_news_ann_df %>%
  filter(upos %in% c("ADJ","NOUN","PROPN","PUNCT","VERB","ADV","PRON","DET"),!is.na(upos)) %>% 
  filter(!tolower(lemma) %in% stopwords(language = "es",source = "nltk")) %>% 
  group_by(doc_id, upos) %>% 
  summarise(n_palabras = n(), 
            n_palabras_unicas = n_distinct(lemma)) %>% 
  pivot_wider(names_from = "upos", values_from = c("n_palabras","n_palabras_unicas"), 
              values_fill = 0) 
`summarise()` has grouped output by 'doc_id'. You can override using the `.groups` argument.
# Unión al dataset original
fake_news_df = fake_news_df %>% 
  inner_join(fake_news_dict_df, by=c("status_id"="doc_id")) %>% 
  inner_join(fake_news_pos_df, by=c("status_id"="doc_id"))

# Descriptiva de variables
fake_news_df %>%
  group_by(screen_name) %>%
  summarise(n_palabras=mean(n_palabras),
            n_palabras_unicas=mean(n_palabras_unicas),
            n_palabras_ADJ=mean(n_palabras_ADJ),
            n_palabras_NOUN=mean(n_palabras_NOUN),
            n_palabras_PROPN=mean(n_palabras_PROPN),
            n_palabras_PUNCT=mean(n_palabras_PUNCT),
            n_palabras_VERB=mean(n_palabras_VERB),
            n_palabras_ADV=mean(n_palabras_ADV),
            n_palabras_PRON=mean(n_palabras_PRON),
            n_palabras_DET=mean(n_palabras_DET),
            n_palabras_unicas_ADJ=mean(n_palabras_ADJ),
            n_palabras_unicas_NOUN=mean(n_palabras_NOUN),
            n_palabras_unicas_PROPN=mean(n_palabras_PROPN),
            n_palabras_unicas_PUNCT=mean(n_palabras_PUNCT),
            n_palabras_unicas_VERB=mean(n_palabras_VERB),
            n_palabras_unicas_ADV=mean(n_palabras_ADV),
            n_palabras_unicas_PRON=mean(n_palabras_PRON),
            n_palabras_unicas_DET=mean(n_palabras_DET)) %>%
  pivot_longer(-c(screen_name)) %>%
  mutate(tipo=case_when(name %in% c("n_palabras","n_palabras_unicas")~"general",
                        T~"upos")) %>% 
  ggplot(aes(x=screen_name, y=value, fill=as.factor(name)))+
  geom_col(position="dodge")+
  facet_wrap(vars(tipo), scales = "free", ncol = 1)+
  theme(legend.position = "bottom",
        text = element_text(size=11))

Añadimos también variables que identifiquen con sentimientos cada uno los tweets analizados, dado que las noticias falsas podrían expresar más cierto tipos de sentimientos.

# Categorización de sentimientos
fake_news_sent_df = get_nrc_sentiment(fake_news_df$text, language = "spanish")
fake_news_sent_df = fake_news_sent_df %>% 
  mutate(across(everything(), function(x)(x-min(x))/(max(x)-min(x))))

# Unión a datos originales
fake_news_df = bind_cols(fake_news_df, fake_news_sent_df)

# Comprobación
fake_news_df %>% 
  group_by(screen_name) %>%
  summarise(anger=mean(anger),
            anticipation=mean(anticipation),
            disgust=mean(disgust),
            fear=mean(fear),
            joy=mean(joy),
            sadness=mean(sadness),
            surprise=mean(surprise),
            trust=mean(trust),
            negative=mean(negative),
            positive=mean(positive)) %>% 
  pivot_longer(-c(screen_name)) %>%
  ggplot(aes(x=screen_name, y=value, fill=as.factor(name)))+
  geom_col(position="dodge")+
  theme(legend.position = "bottom",
        text = element_text(size=11))

Finalmente, contaremos el número de hastags usados en cada tweet y la hora de publicación del mismo como variables explicativas adicionales.

# Creación de variable
fake_news_df = fake_news_df %>% 
  mutate(n_hashtags = sapply(hashtags,length))

# Descriptiva de la variable
fake_news_df %>%
  group_by(screen_name) %>%
  summarise(n_hashtags=mean(n_hashtags)) %>%
  ggplot(aes(x=screen_name, y=n_hashtags))+
  geom_col(position="dodge")+
  theme(legend.position = "bottom",
        text = element_text(size=11))

# Creación de variable
fake_news_df = fake_news_df %>% 
  mutate(hora_publicacion = format(created_at, "%H"))

# Descriptiva de la variable
fake_news_df %>%
  count(screen_name,hora_publicacion) %>%
  ggplot(aes(x=screen_name, y=n,fill=hora_publicacion))+
  geom_col(position="dodge")+
  theme(legend.position = "bottom",
        text = element_text(size=11))

2.4. Análisis exploratorio

Luego de la creación de variables nos quedamos con las aquellas que usaremos en el análisis de las siguiente sección.

# Selección de variables
fake_news_model_df = fake_news_df %>% 
  select(status_id, screen_name, text, target_falsa, n_signos_interrogacion, n_signos_admiracion,
         n_palabras, n_palabras_unicas, n_palabras_ADJ, n_palabras_NOUN,
         n_palabras_PROPN, n_palabras_PUNCT, n_palabras_VERB, n_palabras_ADV,
         n_palabras_PRON, n_palabras_DET, n_palabras_unicas_ADJ, n_palabras_unicas_NOUN,
         n_palabras_unicas_PROPN, n_palabras_unicas_PUNCT, n_palabras_unicas_VERB,
         n_palabras_unicas_ADV, n_palabras_unicas_PRON, n_palabras_unicas_DET,
         anger, anticipation, disgust, fear, joy, sadness, surprise, trust, 
         negative, positive, n_hashtags, hora_publicacion) %>% 
  mutate(hora_publicacion = as.factor(hora_publicacion))

# Ejemplos de datos
fake_news_model_df %>%
  group_by(screen_name) %>% 
  slice_sample(n = 1)

Y con ellas crearemos un reporte resumen gracias a la librería summarytools con una sola línea de código.

dfSummary(fake_news_model_df, varnumbers = F, valid.col = F) %>% view(method="render")

Data Frame Summary

dfSummary

Dimensions: 13892 x 36
Duplicates: 0
Variable Stats / Values Freqs (% of Valid) Graph Missing
status_id [character] 1. 1000059406778847232 2. 1000478858498400256 3. 1000490506948923394 4. 1000495893689323521 5. 1001168855392190464 6. 1001189637908520960 7. 1001545167097221120 8. 1002548403681808384 9. 1002930489882300416 10. 1002944111337500672 [ 13882 others ]
1(0.0%)
1(0.0%)
1(0.0%)
1(0.0%)
1(0.0%)
1(0.0%)
1(0.0%)
1(0.0%)
1(0.0%)
1(0.0%)
13882(99.9%)
0 (0.0%)
screen_name [character] 1. el_mercioco 2. el_telegrafo 3. elcomerciocom 4. ElMercioEC 5. eluniversocom
3029(21.8%)
3162(22.8%)
3121(22.5%)
1493(10.7%)
3087(22.2%)
0 (0.0%)
text [character] 1. "A Leo le tomó 5 nominaci 2. #Elecciones2021Ec | Guill 3. Corre plazo que le queda 4. Ricardo Patiño fue nombra 5. 'Canelo' Álvarez derrotó 6. 'El virus no se ha ido' f 7. 'El virus no se ha ido' f 8. 'Le dije hijo corre, no t 9. 'No pude dormir toda la n 10. 'No tengo miedo': Los bir [ 13878 others ]
2(0.0%)
2(0.0%)
2(0.0%)
2(0.0%)
1(0.0%)
1(0.0%)
1(0.0%)
1(0.0%)
1(0.0%)
1(0.0%)
13878(99.9%)
0 (0.0%)
target_falsa [numeric] Min : 0 Mean : 0.3 Max : 1
0:9370(67.4%)
1:4522(32.6%)
0 (0.0%)
n_signos_interrogacion [integer] Mean (sd) : 0.1 (0.3) min < med < max: 0 < 0 < 4 IQR (CV) : 0 (3.9)
0:12963(93.3%)
1:857(6.2%)
2:65(0.5%)
3:5(0.0%)
4:2(0.0%)
0 (0.0%)
n_signos_admiracion [integer] Mean (sd) : 0.1 (0.4) min < med < max: 0 < 0 < 5 IQR (CV) : 0 (3)
0:12360(89.0%)
1:1464(10.5%)
2:48(0.3%)
3:14(0.1%)
4:4(0.0%)
5:2(0.0%)
0 (0.0%)
n_palabras [integer] Mean (sd) : 23.1 (10.1) min < med < max: 1 < 21 < 66 IQR (CV) : 11 (0.4) 63 distinct values 0 (0.0%)
n_palabras_unicas [integer] Mean (sd) : 19.9 (7.2) min < med < max: 1 < 18 < 49 IQR (CV) : 9 (0.4) 47 distinct values 0 (0.0%)
n_palabras_ADJ [integer] Mean (sd) : 1 (1.1) min < med < max: 0 < 1 < 12 IQR (CV) : 2 (1.1)
0:5382(38.7%)
1:4924(35.4%)
2:2286(16.5%)
3:825(5.9%)
4:316(2.3%)
5:111(0.8%)
6:41(0.3%)
7:4(0.0%)
8:2(0.0%)
12:1(0.0%)
0 (0.0%)
n_palabras_NOUN [integer] Mean (sd) : 3.8 (2.4) min < med < max: 0 < 3 < 16 IQR (CV) : 3 (0.6) 17 distinct values 0 (0.0%)
n_palabras_PROPN [integer] Mean (sd) : 3.6 (2.3) min < med < max: 0 < 3 < 23 IQR (CV) : 3 (0.7) 18 distinct values 0 (0.0%)
n_palabras_PUNCT [integer] Mean (sd) : 2.4 (2.2) min < med < max: 0 < 2 < 21 IQR (CV) : 3 (0.9) 18 distinct values 0 (0.0%)
n_palabras_VERB [integer] Mean (sd) : 2 (1.3) min < med < max: 0 < 2 < 11 IQR (CV) : 2 (0.7) 12 distinct values 0 (0.0%)
n_palabras_ADV [integer] Mean (sd) : 0.2 (0.5) min < med < max: 0 < 0 < 4 IQR (CV) : 0 (2.2)
0:11267(81.1%)
1:2270(16.3%)
2:317(2.3%)
3:35(0.3%)
4:3(0.0%)
0 (0.0%)
n_palabras_PRON [integer] Mean (sd) : 0 (0.2) min < med < max: 0 < 0 < 3 IQR (CV) : 0 (6.2)
0:13522(97.3%)
1:359(2.6%)
2:10(0.1%)
3:1(0.0%)
0 (0.0%)
n_palabras_DET [integer] Mean (sd) : 0 (0.2) min < med < max: 0 < 0 < 3 IQR (CV) : 0 (4.6)
0:13248(95.4%)
1:622(4.5%)
2:20(0.1%)
3:2(0.0%)
0 (0.0%)
n_palabras_unicas_ADJ [integer] Mean (sd) : 1 (1.1) min < med < max: 0 < 1 < 11 IQR (CV) : 2 (1.1)
0:5382(38.7%)
1:4955(35.7%)
2:2298(16.5%)
3:812(5.8%)
4:298(2.1%)
5:110(0.8%)
6:30(0.2%)
7:4(0.0%)
8:2(0.0%)
11:1(0.0%)
0 (0.0%)
n_palabras_unicas_NOUN [integer] Mean (sd) : 3.7 (2.3) min < med < max: 0 < 3 < 16 IQR (CV) : 3 (0.6) 17 distinct values 0 (0.0%)
n_palabras_unicas_PROPN [integer] Mean (sd) : 3.5 (2.3) min < med < max: 0 < 3 < 23 IQR (CV) : 3 (0.6) 18 distinct values 0 (0.0%)
n_palabras_unicas_PUNCT [integer] Mean (sd) : 1.9 (1.6) min < med < max: 0 < 2 < 10 IQR (CV) : 2 (0.8) 11 distinct values 0 (0.0%)
n_palabras_unicas_VERB [integer] Mean (sd) : 1.9 (1.3) min < med < max: 0 < 2 < 10 IQR (CV) : 2 (0.7) 11 distinct values 0 (0.0%)
n_palabras_unicas_ADV [integer] Mean (sd) : 0.2 (0.5) min < med < max: 0 < 0 < 4 IQR (CV) : 0 (2.2)
0:11267(81.1%)
1:2287(16.5%)
2:302(2.2%)
3:34(0.2%)
4:2(0.0%)
0 (0.0%)
n_palabras_unicas_PRON [integer] Mean (sd) : 0 (0.2) min < med < max: 0 < 0 < 3 IQR (CV) : 0 (6.1)
0:13522(97.3%)
1:365(2.6%)
2:4(0.0%)
3:1(0.0%)
0 (0.0%)
n_palabras_unicas_DET [integer] Mean (sd) : 0 (0.2) min < med < max: 0 < 0 < 2 IQR (CV) : 0 (4.6)
0:13248(95.4%)
1:630(4.5%)
2:14(0.1%)
0 (0.0%)
anger [numeric] Mean (sd) : 0 (0.1) min < med < max: 0 < 0 < 1 IQR (CV) : 0 (2.5)
0.00  :11354(81.7%)
0.12 !:1656(11.9%)
0.25  :513(3.7%)
0.38 !:243(1.7%)
0.50  :88(0.6%)
0.62 !:29(0.2%)
0.75  :7(0.1%)
0.88 !:1(0.0%)
1.00  :1(0.0%)
! rounded
0 (0.0%)
anticipation [numeric] Mean (sd) : 0.1 (0.1) min < med < max: 0 < 0 < 1 IQR (CV) : 0.2 (1.9)
0.00  :10134(72.9%)
0.17 !:2797(20.1%)
0.33 !:746(5.4%)
0.50  :166(1.2%)
0.67 !:39(0.3%)
0.83 !:7(0.1%)
1.00  :3(0.0%)
! rounded
0 (0.0%)
disgust [numeric] Mean (sd) : 0 (0.1) min < med < max: 0 < 0 < 1 IQR (CV) : 0 (2.9)
0.00  :12004(86.4%)
0.14 !:1456(10.5%)
0.29 !:299(2.2%)
0.43 !:111(0.8%)
0.57 !:16(0.1%)
0.71 !:3(0.0%)
0.86 !:2(0.0%)
1.00  :1(0.0%)
! rounded
0 (0.0%)
fear [numeric] Mean (sd) : 0.1 (0.1) min < med < max: 0 < 0 < 1 IQR (CV) : 0.2 (2)
0.00  :10254(73.8%)
0.17 !:2414(17.4%)
0.33 !:756(5.4%)
0.50  :322(2.3%)
0.67 !:97(0.7%)
0.83 !:36(0.3%)
1.00  :13(0.1%)
! rounded
0 (0.0%)
joy [numeric] Mean (sd) : 0 (0.1) min < med < max: 0 < 0 < 1 IQR (CV) : 0 (2.3)
0.00  :11170(80.4%)
0.17 !:2072(14.9%)
0.33 !:494(3.6%)
0.50  :94(0.7%)
0.67 !:51(0.4%)
0.83 !:10(0.1%)
1.00  :1(0.0%)
! rounded
0 (0.0%)
sadness [numeric] Mean (sd) : 0 (0.1) min < med < max: 0 < 0 < 1 IQR (CV) : 0 (2.2) 11 distinct values 0 (0.0%)
surprise [numeric] Mean (sd) : 0 (0.1) min < med < max: 0 < 0 < 1 IQR (CV) : 0 (2.5)
0.00:11756(84.6%)
0.25:1846(13.3%)
0.50:264(1.9%)
0.75:24(0.2%)
1.00:2(0.0%)
0 (0.0%)
trust [numeric] Mean (sd) : 0.1 (0.1) min < med < max: 0 < 0 < 1 IQR (CV) : 0.1 (1.7)
0.00  :8908(64.1%)
0.11 !:3022(21.8%)
0.22 !:1233(8.9%)
0.33 !:481(3.5%)
0.44 !:170(1.2%)
0.56 !:54(0.4%)
0.67 !:16(0.1%)
0.78 !:6(0.0%)
0.89 !:1(0.0%)
1.00  :1(0.0%)
! rounded
0 (0.0%)
negative [numeric] Mean (sd) : 0.1 (0.1) min < med < max: 0 < 0 < 1 IQR (CV) : 0.1 (1.7) 12 distinct values 0 (0.0%)
positive [numeric] Mean (sd) : 0.1 (0.1) min < med < max: 0 < 0.1 < 1 IQR (CV) : 0.1 (1.3) 12 distinct values 0 (0.0%)
n_hashtags [integer] Mean (sd) : 1.1 (0.4) min < med < max: 1 < 1 < 6 IQR (CV) : 0 (0.4)
1:12570(90.5%)
2:1067(7.7%)
3:197(1.4%)
4:39(0.3%)
5:18(0.1%)
6:1(0.0%)
0 (0.0%)
hora_publicacion [factor] 1. 00 2. 01 3. 02 4. 03 5. 04 6. 05 7. 06 8. 07 9. 08 10. 09 [ 14 others ]
715(5.1%)
638(4.6%)
542(3.9%)
432(3.1%)
368(2.6%)
110(0.8%)
34(0.2%)
22(0.2%)
24(0.2%)
42(0.3%)
10965(78.9%)
0 (0.0%)

Generated by summarytools 0.9.8 (R version 4.0.3)
2021-03-12

2.5. Guardado de dataset procesado

Una vez que hemos explorado los datos analizados procedemos a guardar el conjunto de datos procesado para cargarlo cuando realicemos el modelamiento.

saveRDS(fake_news_model_df, "Caso3_NoticiasFalsas/fake_news_model_df.RDS")
LS0tDQp0aXRsZTogIkFuw6FsaXNpcyBkZSBjb21wb3J0YW1pZW50byBlbiByZWRlcyBzb2NpYWxlcyB1c2FuZG8gUHJvY2VzYW1pZW50byBkZWwgTGVuZ3VhamUgTmF0dXJhbCINCnN1YnRpdGxlOiAnQ2Fww610dWxvIDY6IEFwcmVuZGl6YWplIHN1cGVydmlzYWRvLCBwcm9ibGVtYXMgZGUgY2xhc2lmaWNhY2nDs24gY29uIE5MUCcNCmF1dGhvcjogSHVnbyBQb3JyYXMNCm91dHB1dDogDQogIGh0bWxfbm90ZWJvb2s6DQogICAgY3NzOiBFc3RpbG9zLmNzcw0KICAgIHRvYzogdHJ1ZQ0KICAgIHRvY19kZXB0aDogMg0KICAgIHRvY19mbG9hdDoNCiAgICAgIGNvbGxhcHNlZDogdHJ1ZQ0KICAgICAgc21vb3RoX3Njcm9sbDogZmFsc2UNCmJpYmxpb2dyYXBoeTogQmlibGlvZ3JhZmlhLmJpYg0KY3NsOiBjZXBhbC54bWwNCi0tLQ0KDQojICoqKlBBUlRFIDEqKioNCg0KIyAqKjEuIEFwcmVuZGl6YWplIHN1cGVydmlzYWRvOiBQcm9ibGVtYXMgZGUgY2xhc2lmaWNhY2nDs24qKg0KDQojIyAqKjEuMS4gRGVmaW5pY2lvbmVzIG5lY2VzYXJpYXMgcGFyYSBlbCBhbsOhbGlzaXMqKg0KDQoqKkFwcmVuZGl6YWplIHN1cGVydmlzYWRvOioqIFRlbmVtb3MgdW5hIHZhcmlhYmxlIGRlcGVuZGllbnRlIChvdXRwdXQpIGNvbnRpbnVhIG8gY2F0ZWfDs3JpY2EsIHkgcXVlcmVtb3MgcHJlZGVjaXJsYSBjb24gdW4gY29uanVudG8gZGlzcG9uaWJsZSBkZSB2YXJpYWJsZXMgZXhwbGljYXRpdmFzIChpbnB1dCkuDQoNCiFbXShmaWdzLzA1X1N1cGVydmlzZWRMZWFybmluZy5wbmcpDQoNCioqUHJvYmxlbWEgZGUgY2xhc2lmaWNhY2nDs246KiogVGVuZW1vcyBjb21vIHZhcmlhYmxlIGRlcGVuZGllbnRlIHVuYSBkZWwgdGlwbyBjYXRlZ8OzcmljYSAoaS5lLiBjb24gZG9zIG8gbcOhcyBjbGFzZXMpIHF1ZSBidXNjYW1vcyBwcmVkZWNpci4NCg0KIVtdKGZpZ3MvMDZfY2xhc2lmX3Byb2JsZW0ucG5nKXt3aWR0aD0iMTAwJSJ9DQoNCkEgY29udGludWFjacOzbiBwb2RlbW9zIHZlciBxdcOpIGFsZ29yaXRtb3MgcG9kcmVtb3MgdXNhciBhY29yZGUgYSBsYSB2YXJpYWJsZSBxdWUgYnVzY2Ftb3MgcHJlZGVjaXIgZGVudHJvIGRlbCBhcHJlbmRpemFqZSBzdXBlcnZpc2Fkby4NCg0KIVtdKGZpZ3MvMDZfYWxnb3JpdGhtcy5wbmcpDQoNCkVzdG9zIGFsZ29yaXRtb3Mgc2UgZXhwbGljYXLDoW4gYSBtZWRpZGEgcXVlIHNlYW4gdXNhZG9zLg0KDQojIyAqKjEuMi4gQ2FzbyBkZSBlc3R1ZGlvOiBEZXRlY2Npw7NuIGRlIG5vdGljaWFzIGZhbHNhcyoqDQoNCkxhcyBub3RpY2lhcyBmYWxzYXMgc29uIHVuYSBmb3JtYSBkZSBub3RpY2lhcyBxdWUgY29uc2lzdGUgZW4gZGVzaW5mb3JtYXIgbyBubyBpbmZvcm1hciBkZWxpYmVyYWRhbWVudGUgYSB0cmF2w6lzIGRlIGRpc3RpbnRvcyBtZWRpb3MgZGUgY29tdW5pY2FjacOzbiB0cmFkaWNpb25hbGVzLiBQYXJhIGRldGVjdGFybGFzIGV4aXN0ZW4gYWxndW5vcyByZWN1cnNvcyBxdWUgcHVlZGVuIHNlciBjb25zdHJ1aWRvcyBhIHBhcnRpciBkZSB0w6ljbmljYXMgZGUgUExOLCB0YW50byBkZSBhcHJlbmRpemFqZSBzdXBlcnZpc2FkbywgY29tbyBkZSBhcHJlbmRpemFqZSBubyBzdXBlcnZpc2FkbywgcXVlIG5vcyBheXVkZW4gYSBkZXRlY3Rhcmxhcy4NCg0KIVtdKGZpZ3MvMDZfZm5kLnBuZykNCg0KRXNwZWPDrWZpY2FtZW50ZSwgZW4gZXN0ZSBjYXNvIGRlIGVzdHVkaW8gc2UgYnVzY2EgY3JlYXIgdW4gYWxnb3JpdG1vIGRlIGFwcmVuZGl6YWplIHN1cGVydmlzYWRvIHF1ZSBzZWEgY2FwYXogZGUgY2xhc2lmaWNhciB0d2VldHMgZW4gZmFsc29zIG8gdmVyw61kaWNvcyBwYXJhIGVsIGNvbnRleHRvIGVjdWF0b3JpYW5vLCB1c2FuZG8gbG9zIHBvc3RzIHF1ZSBzZSBwdWVkZW4gZW5jb250cmFyIGVuIGxhcyBww6FnaW5hcyBkZSBUd2l0dGVyIGRlIGRpc3RpbnRvcyBtZWRpb3MgZGUgY29tdW5pY2FjacOzbi4NCg0KIyAqKjIuIFByZXByb2Nlc2FtaWVudG8geSBleHBsb3JhY2nDs24gZGUgZGF0b3MqKg0KDQojIyAqKjIuMS4gQ2FyZ2EgZGUgZGF0b3MqKg0KDQpQYXJhIGluaWNpYXIgZXN0ZSBlamVyY2ljaW8gY2FyZ2FyZW1vcyBsYSBsaWJyZXLDrWFzIG5lY2VzYXJpYXMgZW4gZXN0YSBzZWNjacOzbi4gRXN0YXMgc2UgZW5saXN0YW4gYSBjb250aW51YWNpw7NuOg0KDQpgYGB7ciB3YXJuaW5nPUYsIG1lc3NhZ2U9Rn0NCmxpYnJhcnkodGlkeXZlcnNlKQ0KbGlicmFyeSh0aWR5dGV4dCkNCmxpYnJhcnkodWRwaXBlKQ0KbGlicmFyeShzdG9wd29yZHMpDQpsaWJyYXJ5KHN5dXpoZXQpDQpsaWJyYXJ5KG1scjMpDQpsaWJyYXJ5KHN1bW1hcnl0b29scykNCmBgYA0KDQpVbmEgdmV6IHF1ZSBsYXMgbGlicmVyw61hcyBoYW4gc2lkbyBjYXJnYWRhcywgZXhwbG9yYXJlbW9zIGxvcyBkYXRvcyBkaXNwb25pYmlsaXphZG9zIHBvciBlbCBwcm9mZXNvci4gRXN0b3Mgc2UgcHVlZGVuIGVuY29udHJhciBlbiBsYSBjYXJwZXRhIGRlIFtHb29nbGUgRHJpdmVdKGh0dHBzOi8vZHJpdmUuZ29vZ2xlLmNvbS9kcml2ZS9mb2xkZXJzLzFXX2ltTDNqZ19vYXdqM25TUTFEMmRXUWp6X2c1a3Q4bj91c3A9c2hhcmluZykuIFBhcmEgY2FyZ2FybG9zIGVqZWN1dGFyZW1vcyBsYSBzaWd1aWVudGUgbMOtbmVhIGRlIGPDs2RpZ28sIGFzZWd1csOhbmRvbm9zIGRlIHF1ZSBsb3MgZGF0b3MgaGF5YW4gc2lkbyBjb3JyZWN0YW1lbnRlIGNhcmdhZG9zLg0KDQpgYGB7cn0NCmZha2VfbmV3c19kZiA9IHJlYWRSRFMoIkRhdGEvRGV0ZWNjaW9uTm90aWNpYXNGYWxzYXMvMjEwM19mYWtlX25ld3NfZGYuUkRTIikNCmZha2VfbmV3c19kZiAlPiUgaGVhZCgzKQ0KYGBgDQoNCkNvbW8gc2UgcHVlZGUgbm90YXIsIGVsIGFyY2hpdm8gY2FyZ2FkbyBjb3JyZXNwb25kZSBhIGRhdG9zIGNydWRvcyBleHRyYcOtZG9zIGRlc2RlIFR3aXR0ZXIuIFZlcmlmaXF1ZW1vcyBlbnRvbmNlcyBsYXMgY3VlbnRhcyBkZSBsYXMgY3VhbGVzIHNlIGhhbiBvYnRlbmlkbyBlc3RvcyB0d2VldHMsIGEgbGEgdmV6IHF1ZSBvYnNlcnZhbW9zIGVsIHRpcG8gZGUgdHdlZXQgKG9yZ8OhbmljbywgcmVzcHVlc3RhIG8gcmV0d2VldCkuIFBhcmEgZWxsbyBjcmVhcmVtb3MgZ3LDoWZpY29zLg0KDQpgYGB7cn0NCiMgRGVmaW5pY2nDs24gZGVsIHRpcG8gZGUgdHdlZXQNCmZha2VfbmV3c19kZiA9IGZha2VfbmV3c19kZiAlPiUgDQogIG11dGF0ZSh0aXBvX3R3ZWV0PWNhc2Vfd2hlbihpc19yZXR3ZWV0PT1UfiJSZXR3ZWV0IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICFpcy5uYShyZXBseV90b19zdGF0dXNfaWQpPT1UfiJSZXNwdWVzdGEiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVH4iT3Jnw6FuaWNvIikpDQoNCiMgR3LDoWZpY28gZGUgY3VlbnRhcyBwb3IgdGlwbyBkZSB0d2VldA0KZmFrZV9uZXdzX2RmICU+JSANCiAgY291bnQoc2NyZWVuX25hbWUsIHRpcG9fdHdlZXQpICU+JSANCiAgZ2dwbG90KGFlcyh4PXRpcG9fdHdlZXQsIHk9biwgZmlsbD1zY3JlZW5fbmFtZSkpKw0KICBnZW9tX2NvbChwb3NpdGlvbiA9ICJkb2RnZSIpKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwNCiAgICAgICAgdGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTExKSkNCmBgYA0KDQpFbiBlc3RlIGNvbmp1bnRvIGRlIGRhdG9zIGV4aXN0ZW4gdW4gdG90YWwgZGUgYHIgbnJvdyhmYWtlX25ld3NfZGYpYCB0d2VldHMsIGRvbmRlIGNhc2kgdG9kb3MgZWxsb3Mgc29uIG9yZ8Ohbmljb3MuIFJlY29yZGVtb3MgcXVlIHVuIHR3ZWV0IG9yZ8OhbmljbyBlcyBhcXVlbCBwdWJsaWNhZG8gb3JpZ2luYWxtZW50ZSBwb3IgbGEgY3VlbnRhIGVuIGFuw6FsaXNpcy4gUGFyYSBkZXRlY3RhciBub3RpY2lhcyBmYWxzYXMgYSBwYXJ0aXIgZGUgbGEgY3VlbnRhIG9yaWdpbmFsIHF1ZSBwdWJsaWNhIHVuIHR3ZWV0LCBub3MgcXVlZGFyZW1vcyBzb2xvIGNvbiBsb3Mgb3Jnw6FuaWNvcy4NCg0KYGBge3J9DQojIEZpbHRyYWRvIGRlIHR3ZWV0cyBvcmfDoW5pY29zDQpmYWtlX25ld3NfZGYgPSBmYWtlX25ld3NfZGYgJT4lIA0KICBmaWx0ZXIodGlwb190d2VldD09Ik9yZ8OhbmljbyIpDQoNCiMgQ29uZmlybWFjacOzbiBkZSBmaWx0cm8NCmZha2VfbmV3c19kZiAlPiUgDQogIGNvdW50KHNjcmVlbl9uYW1lLCB0aXBvX3R3ZWV0KSAlPiUgDQogIGdncGxvdChhZXMoeD10aXBvX3R3ZWV0LCB5PW4sIGZpbGw9c2NyZWVuX25hbWUpKSsNCiAgZ2VvbV9jb2wocG9zaXRpb24gPSAiZG9kZ2UiKSsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsDQogICAgICAgIHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT0xMSkpDQpgYGANCg0KRW4gZXN0ZSBncsOhZmljbyBwb2RlbW9zIGNvbmZpcm1hciBxdWUgZWwgY29uanVudG8gZGUgZGF0b3MgdGllbmUgYWhvcmEgc29sYW1lbnRlIHR3ZWV0cyBvcmfDoW5pY29zIGRlIGNpbmNvIGN1ZW50YXM6DQoNCi0gICBcQGVsX21lcmNpb2NvDQotICAgXEBlbE1lcmNpb0VDDQotICAgXEBlbF90ZWxlZ3JhZm8NCi0gICBcQGVsY29tZXJjaW9jb20NCi0gICBcQGVsdW5pdmVyc29jb20NCg0KRW4gbGEgc2lndWllbnRlIHNlY2Npw7NuIG5vcyBheXVkYXJlbW9zIGRlIGVzdGUgYW7DoWxpc2lzIHBhcmEgZGVmaW5pciBsYSB2YXJpYWJsZSBhIHByZWRlY2lyLg0KDQojIyAqKjIuMi4gQ3JlYWNpw7NuIGRlIGxhIHZhcmlhYmxlIG9iamV0aXZvKioNCg0KRGUgbGFzIGN1ZW50YXMgZGUgdHdpdHRlciBleHBsb3JhZGFzIGFudGVyaW9ybWVudGUsIGxhcyBkb3MgcHJpbWVyYXMgZnVlbnRlcywgYWNvcmRlIGEgW0Z1bmRhbWVkaW9zXShodHRwczovL3d3dy5mdW5kYW1lZGlvcy5vcmcuZWMvdGFnL2Zha2UtbmV3cy8pIGNvcnJlc3BvbmRlbiBhIHDDoWdpbmFzIGRlIHPDoXRpcmEgbyBwYXJvZGlhIHF1ZSBwb2Ryw61hbiBlbmdhw7FhciBhIGxvcyBsZWN0b3JlcyBjb24gc3VzICdub3RpY2lhcycsIG8gc3UgdmV6LCBhcnJhbmNhcmxlcyB1bmEgcmlzYSAobyB1biBpbXByb3BlcmlvKS4gTGFzIG90cmFzIHRyZXMgZnVlbnRlcyBlbiBjYW1iaW8sIGNvcnJlc3BvbmRlbiBhIGxhcyBww6FnaW5hcyBkZSB0d2l0dGVyIG9maWNpYWxlcyBkZSB0cmVzIG1lZGlvcyBkZSBjb211bmljYWNpw7NuIGVjdWF0b3JpYW5vczogJ0VsIENvbWVyY2lvJywgJ0VsIFVuaXZlcnNvJyB5ICdFbCBUZWzDqWdyYWZvJywgZW4gbG9zIGN1YWxlcyBsYXMgbm90aWNpYXMgY29ycmVzcG9uZGVuIGEgdW5hIGZ1ZW50ZSBjb25maWFibGUgeSB2ZXLDrWRpY2EuDQoNCkVuIHRhbCBjb250ZXh0bywgY3JlYXJlbW9zIGFob3JhIGxhIHZhcmlhYmxlIGEgcHJlZGVjaXIgKHZhcmlhYmxlIGRlcGVuZGllbnRlIHUgb3V0cHV0KSBkZWZpbmlkYSBjb21vOg0KDQokJA0KeSA9IA0KICAgICBcYmVnaW57Y2FzZXN9DQogICAgICAgXHRleHR7MSx9ICZccXVhZFx0ZXh0e3NpIGxhIG5vdGljaWEgZXMgZmFsc2EgKGVzIHB1YmxpY2FkYSBwb3IgQGVsX21lcmNpb2NvIG8gQGVsTWVyY2lvRUMpLn1cXA0KICAgICAgIFx0ZXh0ezAsfSAmXHF1YWRcdGV4dHtzaSBsYSBub3RpY2lhIHZpZW5lIGRlIHVuYSBmdWVudGUgY29uZmlhYmxlLn0gXFwNCiAgICAgXGVuZHtjYXNlc30NCiQkDQoNCkVzdG8gc2UgbG9ncmEgYSB0cmF2w6lzIGRlbCBzaWd1aWVudGUgY8OzZGlnby4NCg0KYGBge3J9DQojIENyZWFjacOzbiBkZSB2YXJpYWJsZSB0YXJnZXQNCmZha2VfbmV3c19kZiA9IGZha2VfbmV3c19kZiAlPiUgDQogIG11dGF0ZSh0YXJnZXRfZmFsc2EgPSBjYXNlX3doZW4oc2NyZWVuX25hbWUgJWluJSBjKCJlbF9tZXJjaW9jbyIsIkVsTWVyY2lvRUMiKX4xLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICFzY3JlZW5fbmFtZSAlaW4lIGMoImVsX21lcmNpb2NvIiwiRWxNZXJjaW9FQyIpfjApKQ0KDQojIENvbXByb2JhY2nDs24NCmZha2VfbmV3c19kZiAlPiUgDQogIGNvdW50KHNjcmVlbl9uYW1lLCB0YXJnZXRfZmFsc2EpICU+JSANCiAgZ2dwbG90KGFlcyh4PXRhcmdldF9mYWxzYSwgeT1uLCBmaWxsPWFzLmZhY3RvcihzY3JlZW5fbmFtZSkpKSsNCiAgZ2VvbV9jb2woKSsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsDQogICAgICAgIHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT0xMSkpDQpgYGANCg0KIyMgKioyLjMuIENyZWFjacOzbiBkZSBsYSB2YXJpYWJsZXMgZXhwbGljYXRpdmFzKioNCg0KUGFyYSBsYSBjcmVhY2nDs24gZGUgdmFyaWFibGVzIGV4cGxpY2F0aXZhcyB1dGlsaXphcmVtb3MgdGFudG8gY3JpdGVyaW9zIGN1YWxpdGF0aXZvcyBjb21vIGN1YW50aXRhdGl2b3MgZXhwbG90YWRvcyBhIHBhcnRpciBkZSBsb3MgZGF0b3MgZGUgdGV4dG8gKHkgcG9yIHF1w6kgbm8sIGRlIG1ldGFkYSBhZGljaW9uYWwgY29tbyBlbCB1c28gZGUgaGFzaHRhZ3MpLiBDb21lbmNlbW9zIGVudG9uY2VzIG9ic2VydmFuZG8gYWxndW5vcyBlamVtcGxvcyBkZSBsb3MgdHdlZXRzIGVuIGFuw6FsaXNpcy4NCg0KYGBge3J9DQpmYWtlX25ld3NfZGYgJT4lDQogIGdyb3VwX2J5KHNjcmVlbl9uYW1lKSAlPiUgDQogIHNsaWNlX3NhbXBsZShuID0gMSkgJT4lIA0KICBzZWxlY3QodGV4dCkNCmBgYA0KDQpFbiBwcmltZXIgbHVnYXIgY3JlYXJlbW9zIHVuYSB2YXJpYWJsZSBxdWUgY3VlbnRlIHRhbnRvIGVsIG7Dum1lcm8gZGUgc8OtbWJvbG9zIGRlIGFkbWlyYWNpw7NuIGNvbW8gaW50ZXJyb2dhY2nDs24gcXVlIHNlIHV0aWxpY2VuIGVuIGVsIHRleHRvLCBkZWJpZG8gYSBxdWUgZW4gbm90aWNpYXMgZGUgZnVlbnRlcyBvZmljaWFsZXMgZWwgdGlwbyBkZSBlc2NyaXR1cmEgc3VlbGUgc2VyIG3DoXMgZm9ybWFsIHkgZWxhYm9yYWRvLiBQYXJhIGNvcnJvYm9yYXIgc3UgY3JlYWNpw7NuLCB2ZXJpZmljYXJlbW9zIG1lZGlkYXMgZGVzY3JpcHRpdmFzIHBhcmEgY2FkYSBjdWVudGEuDQoNCmBgYHtyfQ0KIyBDcmVhY2nDs24gZGUgdmFyaWFibGVzDQpmYWtlX25ld3NfZGYgPSBmYWtlX25ld3NfZGYgJT4lDQogIG11dGF0ZShuX3NpZ25vc19hZG1pcmFjaW9uID0gc3RyX2NvdW50KHRleHQsICJcXCEiKSwgDQogICAgICAgICBuX3NpZ25vc19pbnRlcnJvZ2FjaW9uID0gc3RyX2NvdW50KHRleHQsICJcXD8iKSkNCg0KIyBEZXNjcmlwdGl2YSBkZSB2YXJpYWJsZXMNCmZha2VfbmV3c19kZiAlPiUNCiAgZ3JvdXBfYnkoc2NyZWVuX25hbWUpICU+JQ0KICBzdW1tYXJpc2Uobl9zaWdub3NfYWRtaXJhY2lvbj1tZWFuKG5fc2lnbm9zX2FkbWlyYWNpb24pLA0KICAgICAgICAgICAgbl9zaWdub3NfaW50ZXJyb2dhY2lvbj1tZWFuKG5fc2lnbm9zX2ludGVycm9nYWNpb24pKSAlPiUNCiAgcGl2b3RfbG9uZ2VyKGMobl9zaWdub3NfYWRtaXJhY2lvbiwgbl9zaWdub3NfaW50ZXJyb2dhY2lvbikpICU+JQ0KICBnZ3Bsb3QoYWVzKHg9c2NyZWVuX25hbWUsIHk9dmFsdWUsIGZpbGw9YXMuZmFjdG9yKG5hbWUpKSkrDQogIGdlb21fY29sKHBvc2l0aW9uPSJkb2RnZSIpKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwNCiAgICAgICAgdGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTExKSkNCmBgYA0KDQpBaG9yYSBjYWxjdWxhcmVtb3MgZWwgdGFtYcOxbyB5IHZhcmllZGFkIGRlbCBkaWNjaW9uYXJpbyBkZSBjYWRhIHR3ZWV0LCBhZGVtw6FzIGRlbCBuw7ptZXJvIGRlIHBhbGFicmFzIHVzYWRvIHBvciBjYWRhIHRpcG8gZGUgZXRpcXVldGEgUE9TLCBlbiBsYSBtaXNtYSBsw61uZWEgZGUgcGVuc2FtaWVudG8gYW50ZXJpb3IuDQoNCmBgYHtyfQ0KIyBDYXJnYSBkZSBtb2RlbG8gdWRwaXBlDQojIHVkcGlwZV9kb3dubG9hZF9tb2RlbChsYW5ndWFnZSA9ICJzcGFuaXNoIikNCm1vZGVsX3NwYW5pc2ggPSB1ZHBpcGVfbG9hZF9tb2RlbCgic3BhbmlzaC1nc2QtdWQtMi41LTE5MTIwNi51ZHBpcGUiKQ0KDQojIEFub3RhY2nDs24gZGUgZGF0b3MNCmZha2VfbmV3c19hbm5fZGYgPSB1ZHBpcGVfYW5ub3RhdGUobW9kZWxfc3BhbmlzaCwgeCA9IGZha2VfbmV3c19kZiR0ZXh0LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkb2NfaWQgPSBmYWtlX25ld3NfZGYkc3RhdHVzX2lkKSAlPiUgDQogIGFzX3RpYmJsZSgpDQoNCiMgQ3JlYWNpw7NuIGRlIHZhcmlhYmxlcyByZXNwZWN0byBhbCBkaWNjaW9uYXJpbw0KZmFrZV9uZXdzX2RpY3RfZGYgPSBmYWtlX25ld3NfYW5uX2RmICU+JQ0KICBncm91cF9ieShkb2NfaWQpICU+JSANCiAgc3VtbWFyaXNlKG5fcGFsYWJyYXMgPSBuKCksIA0KICAgICAgICAgICAgbl9wYWxhYnJhc191bmljYXMgPSBuX2Rpc3RpbmN0KHRvbG93ZXIobGVtbWEpKSkNCg0KIyBDcmVhY2nDs24gZGUgdmFyaWFibGVzIHJlc3BlY3RvIGEgbGEgZXRpcXVldGEgUE9TDQpmYWtlX25ld3NfcG9zX2RmID0gZmFrZV9uZXdzX2Fubl9kZiAlPiUNCiAgZmlsdGVyKHVwb3MgJWluJSBjKCJBREoiLCJOT1VOIiwiUFJPUE4iLCJQVU5DVCIsIlZFUkIiLCJBRFYiLCJQUk9OIiwiREVUIiksIWlzLm5hKHVwb3MpKSAlPiUgDQogIGZpbHRlcighdG9sb3dlcihsZW1tYSkgJWluJSBzdG9wd29yZHMobGFuZ3VhZ2UgPSAiZXMiLHNvdXJjZSA9ICJubHRrIikpICU+JSANCiAgZ3JvdXBfYnkoZG9jX2lkLCB1cG9zKSAlPiUgDQogIHN1bW1hcmlzZShuX3BhbGFicmFzID0gbigpLCANCiAgICAgICAgICAgIG5fcGFsYWJyYXNfdW5pY2FzID0gbl9kaXN0aW5jdChsZW1tYSkpICU+JSANCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9ICJ1cG9zIiwgdmFsdWVzX2Zyb20gPSBjKCJuX3BhbGFicmFzIiwibl9wYWxhYnJhc191bmljYXMiKSwgDQogICAgICAgICAgICAgIHZhbHVlc19maWxsID0gMCkgDQoNCiMgVW5pw7NuIGFsIGRhdGFzZXQgb3JpZ2luYWwNCmZha2VfbmV3c19kZiA9IGZha2VfbmV3c19kZiAlPiUgDQogIGlubmVyX2pvaW4oZmFrZV9uZXdzX2RpY3RfZGYsIGJ5PWMoInN0YXR1c19pZCI9ImRvY19pZCIpKSAlPiUgDQogIGlubmVyX2pvaW4oZmFrZV9uZXdzX3Bvc19kZiwgYnk9Yygic3RhdHVzX2lkIj0iZG9jX2lkIikpDQoNCiMgRGVzY3JpcHRpdmEgZGUgdmFyaWFibGVzDQpmYWtlX25ld3NfZGYgJT4lDQogIGdyb3VwX2J5KHNjcmVlbl9uYW1lKSAlPiUNCiAgc3VtbWFyaXNlKG5fcGFsYWJyYXM9bWVhbihuX3BhbGFicmFzKSwNCiAgICAgICAgICAgIG5fcGFsYWJyYXNfdW5pY2FzPW1lYW4obl9wYWxhYnJhc191bmljYXMpLA0KICAgICAgICAgICAgbl9wYWxhYnJhc19BREo9bWVhbihuX3BhbGFicmFzX0FESiksDQogICAgICAgICAgICBuX3BhbGFicmFzX05PVU49bWVhbihuX3BhbGFicmFzX05PVU4pLA0KICAgICAgICAgICAgbl9wYWxhYnJhc19QUk9QTj1tZWFuKG5fcGFsYWJyYXNfUFJPUE4pLA0KICAgICAgICAgICAgbl9wYWxhYnJhc19QVU5DVD1tZWFuKG5fcGFsYWJyYXNfUFVOQ1QpLA0KICAgICAgICAgICAgbl9wYWxhYnJhc19WRVJCPW1lYW4obl9wYWxhYnJhc19WRVJCKSwNCiAgICAgICAgICAgIG5fcGFsYWJyYXNfQURWPW1lYW4obl9wYWxhYnJhc19BRFYpLA0KICAgICAgICAgICAgbl9wYWxhYnJhc19QUk9OPW1lYW4obl9wYWxhYnJhc19QUk9OKSwNCiAgICAgICAgICAgIG5fcGFsYWJyYXNfREVUPW1lYW4obl9wYWxhYnJhc19ERVQpLA0KICAgICAgICAgICAgbl9wYWxhYnJhc191bmljYXNfQURKPW1lYW4obl9wYWxhYnJhc19BREopLA0KICAgICAgICAgICAgbl9wYWxhYnJhc191bmljYXNfTk9VTj1tZWFuKG5fcGFsYWJyYXNfTk9VTiksDQogICAgICAgICAgICBuX3BhbGFicmFzX3VuaWNhc19QUk9QTj1tZWFuKG5fcGFsYWJyYXNfUFJPUE4pLA0KICAgICAgICAgICAgbl9wYWxhYnJhc191bmljYXNfUFVOQ1Q9bWVhbihuX3BhbGFicmFzX1BVTkNUKSwNCiAgICAgICAgICAgIG5fcGFsYWJyYXNfdW5pY2FzX1ZFUkI9bWVhbihuX3BhbGFicmFzX1ZFUkIpLA0KICAgICAgICAgICAgbl9wYWxhYnJhc191bmljYXNfQURWPW1lYW4obl9wYWxhYnJhc19BRFYpLA0KICAgICAgICAgICAgbl9wYWxhYnJhc191bmljYXNfUFJPTj1tZWFuKG5fcGFsYWJyYXNfUFJPTiksDQogICAgICAgICAgICBuX3BhbGFicmFzX3VuaWNhc19ERVQ9bWVhbihuX3BhbGFicmFzX0RFVCkpICU+JQ0KICBwaXZvdF9sb25nZXIoLWMoc2NyZWVuX25hbWUpKSAlPiUNCiAgbXV0YXRlKHRpcG89Y2FzZV93aGVuKG5hbWUgJWluJSBjKCJuX3BhbGFicmFzIiwibl9wYWxhYnJhc191bmljYXMiKX4iZ2VuZXJhbCIsDQogICAgICAgICAgICAgICAgICAgICAgICBUfiJ1cG9zIikpICU+JSANCiAgZ2dwbG90KGFlcyh4PXNjcmVlbl9uYW1lLCB5PXZhbHVlLCBmaWxsPWFzLmZhY3RvcihuYW1lKSkpKw0KICBnZW9tX2NvbChwb3NpdGlvbj0iZG9kZ2UiKSsNCiAgZmFjZXRfd3JhcCh2YXJzKHRpcG8pLCBzY2FsZXMgPSAiZnJlZSIsIG5jb2wgPSAxKSsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsDQogICAgICAgIHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT0xMSkpDQpgYGANCg0KQcOxYWRpbW9zIHRhbWJpw6luIHZhcmlhYmxlcyBxdWUgaWRlbnRpZmlxdWVuIGNvbiBzZW50aW1pZW50b3MgY2FkYSB1bm8gbG9zIHR3ZWV0cyBhbmFsaXphZG9zLCBkYWRvIHF1ZSBsYXMgbm90aWNpYXMgZmFsc2FzIHBvZHLDrWFuIGV4cHJlc2FyIG3DoXMgY2llcnRvIHRpcG9zIGRlIHNlbnRpbWllbnRvcy4NCg0KYGBge3J9DQojIENhdGVnb3JpemFjacOzbiBkZSBzZW50aW1pZW50b3MNCmZha2VfbmV3c19zZW50X2RmID0gZ2V0X25yY19zZW50aW1lbnQoZmFrZV9uZXdzX2RmJHRleHQsIGxhbmd1YWdlID0gInNwYW5pc2giKQ0KZmFrZV9uZXdzX3NlbnRfZGYgPSBmYWtlX25ld3Nfc2VudF9kZiAlPiUgDQogIG11dGF0ZShhY3Jvc3MoZXZlcnl0aGluZygpLCBmdW5jdGlvbih4KSh4LW1pbih4KSkvKG1heCh4KS1taW4oeCkpKSkNCg0KIyBVbmnDs24gYSBkYXRvcyBvcmlnaW5hbGVzDQpmYWtlX25ld3NfZGYgPSBiaW5kX2NvbHMoZmFrZV9uZXdzX2RmLCBmYWtlX25ld3Nfc2VudF9kZikNCg0KIyBDb21wcm9iYWNpw7NuDQpmYWtlX25ld3NfZGYgJT4lIA0KICBncm91cF9ieShzY3JlZW5fbmFtZSkgJT4lDQogIHN1bW1hcmlzZShhbmdlcj1tZWFuKGFuZ2VyKSwNCiAgICAgICAgICAgIGFudGljaXBhdGlvbj1tZWFuKGFudGljaXBhdGlvbiksDQogICAgICAgICAgICBkaXNndXN0PW1lYW4oZGlzZ3VzdCksDQogICAgICAgICAgICBmZWFyPW1lYW4oZmVhciksDQogICAgICAgICAgICBqb3k9bWVhbihqb3kpLA0KICAgICAgICAgICAgc2FkbmVzcz1tZWFuKHNhZG5lc3MpLA0KICAgICAgICAgICAgc3VycHJpc2U9bWVhbihzdXJwcmlzZSksDQogICAgICAgICAgICB0cnVzdD1tZWFuKHRydXN0KSwNCiAgICAgICAgICAgIG5lZ2F0aXZlPW1lYW4obmVnYXRpdmUpLA0KICAgICAgICAgICAgcG9zaXRpdmU9bWVhbihwb3NpdGl2ZSkpICU+JSANCiAgcGl2b3RfbG9uZ2VyKC1jKHNjcmVlbl9uYW1lKSkgJT4lDQogIGdncGxvdChhZXMoeD1zY3JlZW5fbmFtZSwgeT12YWx1ZSwgZmlsbD1hcy5mYWN0b3IobmFtZSkpKSsNCiAgZ2VvbV9jb2wocG9zaXRpb249ImRvZGdlIikrDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLA0KICAgICAgICB0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9MTEpKQ0KYGBgDQoNCkZpbmFsbWVudGUsIGNvbnRhcmVtb3MgZWwgbsO6bWVybyBkZSBoYXN0YWdzIHVzYWRvcyBlbiBjYWRhIHR3ZWV0IHkgbGEgaG9yYSBkZSBwdWJsaWNhY2nDs24gZGVsIG1pc21vIGNvbW8gdmFyaWFibGVzIGV4cGxpY2F0aXZhcyBhZGljaW9uYWxlcy4NCg0KYGBge3J9DQojIENyZWFjacOzbiBkZSB2YXJpYWJsZQ0KZmFrZV9uZXdzX2RmID0gZmFrZV9uZXdzX2RmICU+JSANCiAgbXV0YXRlKG5faGFzaHRhZ3MgPSBzYXBwbHkoaGFzaHRhZ3MsbGVuZ3RoKSkNCg0KIyBEZXNjcmlwdGl2YSBkZSBsYSB2YXJpYWJsZQ0KZmFrZV9uZXdzX2RmICU+JQ0KICBncm91cF9ieShzY3JlZW5fbmFtZSkgJT4lDQogIHN1bW1hcmlzZShuX2hhc2h0YWdzPW1lYW4obl9oYXNodGFncykpICU+JQ0KICBnZ3Bsb3QoYWVzKHg9c2NyZWVuX25hbWUsIHk9bl9oYXNodGFncykpKw0KICBnZW9tX2NvbChwb3NpdGlvbj0iZG9kZ2UiKSsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsDQogICAgICAgIHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT0xMSkpDQpgYGANCg0KYGBge3J9DQojIENyZWFjacOzbiBkZSB2YXJpYWJsZQ0KZmFrZV9uZXdzX2RmID0gZmFrZV9uZXdzX2RmICU+JSANCiAgbXV0YXRlKGhvcmFfcHVibGljYWNpb24gPSBmb3JtYXQoY3JlYXRlZF9hdCwgIiVIIikpDQoNCiMgRGVzY3JpcHRpdmEgZGUgbGEgdmFyaWFibGUNCmZha2VfbmV3c19kZiAlPiUNCiAgY291bnQoc2NyZWVuX25hbWUsaG9yYV9wdWJsaWNhY2lvbikgJT4lDQogIGdncGxvdChhZXMoeD1zY3JlZW5fbmFtZSwgeT1uLGZpbGw9aG9yYV9wdWJsaWNhY2lvbikpKw0KICBnZW9tX2NvbChwb3NpdGlvbj0iZG9kZ2UiKSsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsDQogICAgICAgIHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT0xMSkpDQpgYGANCg0KIyMgKioyLjQuIEFuw6FsaXNpcyBleHBsb3JhdG9yaW8qKg0KDQpMdWVnbyBkZSBsYSBjcmVhY2nDs24gZGUgdmFyaWFibGVzIG5vcyBxdWVkYW1vcyBjb24gbGFzIGFxdWVsbGFzIHF1ZSB1c2FyZW1vcyBlbiBlbCBhbsOhbGlzaXMgZGUgbGFzIHNpZ3VpZW50ZSBzZWNjacOzbi4NCg0KYGBge3J9DQojIFNlbGVjY2nDs24gZGUgdmFyaWFibGVzDQpmYWtlX25ld3NfbW9kZWxfZGYgPSBmYWtlX25ld3NfZGYgJT4lIA0KICBzZWxlY3Qoc3RhdHVzX2lkLCBzY3JlZW5fbmFtZSwgdGV4dCwgdGFyZ2V0X2ZhbHNhLCBuX3NpZ25vc19pbnRlcnJvZ2FjaW9uLCBuX3NpZ25vc19hZG1pcmFjaW9uLA0KICAgICAgICAgbl9wYWxhYnJhcywgbl9wYWxhYnJhc191bmljYXMsIG5fcGFsYWJyYXNfQURKLCBuX3BhbGFicmFzX05PVU4sDQogICAgICAgICBuX3BhbGFicmFzX1BST1BOLCBuX3BhbGFicmFzX1BVTkNULCBuX3BhbGFicmFzX1ZFUkIsIG5fcGFsYWJyYXNfQURWLA0KICAgICAgICAgbl9wYWxhYnJhc19QUk9OLCBuX3BhbGFicmFzX0RFVCwgbl9wYWxhYnJhc191bmljYXNfQURKLCBuX3BhbGFicmFzX3VuaWNhc19OT1VOLA0KICAgICAgICAgbl9wYWxhYnJhc191bmljYXNfUFJPUE4sIG5fcGFsYWJyYXNfdW5pY2FzX1BVTkNULCBuX3BhbGFicmFzX3VuaWNhc19WRVJCLA0KICAgICAgICAgbl9wYWxhYnJhc191bmljYXNfQURWLCBuX3BhbGFicmFzX3VuaWNhc19QUk9OLCBuX3BhbGFicmFzX3VuaWNhc19ERVQsDQogICAgICAgICBhbmdlciwgYW50aWNpcGF0aW9uLCBkaXNndXN0LCBmZWFyLCBqb3ksIHNhZG5lc3MsIHN1cnByaXNlLCB0cnVzdCwgDQogICAgICAgICBuZWdhdGl2ZSwgcG9zaXRpdmUsIG5faGFzaHRhZ3MsIGhvcmFfcHVibGljYWNpb24pICU+JSANCiAgbXV0YXRlKGhvcmFfcHVibGljYWNpb24gPSBhcy5mYWN0b3IoaG9yYV9wdWJsaWNhY2lvbikpDQoNCiMgRWplbXBsb3MgZGUgZGF0b3MNCmZha2VfbmV3c19tb2RlbF9kZiAlPiUNCiAgZ3JvdXBfYnkoc2NyZWVuX25hbWUpICU+JSANCiAgc2xpY2Vfc2FtcGxlKG4gPSAxKQ0KYGBgDQoNClkgY29uIGVsbGFzIGNyZWFyZW1vcyB1biByZXBvcnRlIHJlc3VtZW4gZ3JhY2lhcyBhIGxhIGxpYnJlcsOtYSAqc3VtbWFyeXRvb2xzKiBjb24gdW5hIHNvbGEgbMOtbmVhIGRlIGPDs2RpZ28uDQoNCmBgYHtyfQ0KZGZTdW1tYXJ5KGZha2VfbmV3c19tb2RlbF9kZiwgdmFybnVtYmVycyA9IEYsIHZhbGlkLmNvbCA9IEYpICU+JSB2aWV3KG1ldGhvZD0icmVuZGVyIikNCmBgYA0KDQojIyAqKjIuNS4gR3VhcmRhZG8gZGUgZGF0YXNldCBwcm9jZXNhZG8qKg0KDQpVbmEgdmV6IHF1ZSBoZW1vcyBleHBsb3JhZG8gbG9zIGRhdG9zIGFuYWxpemFkb3MgcHJvY2VkZW1vcyBhIGd1YXJkYXIgZWwgY29uanVudG8gZGUgZGF0b3MgcHJvY2VzYWRvIHBhcmEgY2FyZ2FybG8gY3VhbmRvIHJlYWxpY2Vtb3MgZWwgbW9kZWxhbWllbnRvLg0KDQpgYGB7cn0NCnNhdmVSRFMoZmFrZV9uZXdzX21vZGVsX2RmLCAiQ2FzbzNfTm90aWNpYXNGYWxzYXMvZmFrZV9uZXdzX21vZGVsX2RmLlJEUyIpDQpgYGANCg==