Toxicidad política en Tweets
Introducción
«Merodeando» por Hugging Face y viendo modelos de clasificación en Español, me tope con un modelo creado por el equipo de NLP de Newtral que asigna a un tweet una puntuación (score) sobre el nivel de «toxicidad política» que genera el tweet. Tras el «descubrimiento» de este modelo no me pude resistir a aplicarlo al corpus de Tweets de polític@s españoles que desde mayo del 2019 hasta la fecha de este artículo sigo manteniendo y actualizando diariamente, utilizado para realizar ejemplos de clasificación automática de textos en mis clases de Master de Procesamiento de Lenguaje Natural.
El corpus en cuestión recopila los tweets de varias cuentas de polític@s españoles y etiqueta estos tweets con el partido político al que pertenecen. Dado que este corpus lo uso con fines didácticos, ‘solo’ recopilo tweets de los principales partidos políticos representados en la cámara baja: PSOE, PP, Vox, Unidas Podemos y Ciudadanos (escritos por orden de representación en el parlamento).
MUY MUY MUY IMPORTANTE: Este artículo no persigue ningún fin político, ni partidista, ni posicionarse a favor o en contra de ningún partido político y ni perjudicar ni beneficiarle y por supuesto no perjudicar ni beneficiar a ningún político en particular; de hecho, el corpus utilizado no identifica a la cuenta de Twitter que publica el tweet, aunque es obvio que no sería difícil identificarlo, pero esto no lo hacemos en este artículo; en definitiva, no se pretende herir la sensibilidad de nadie. Este artículo tiene como finalidad exponer un posible caso de uso del PROCESAMIENTO DEL LENGUAJE NATURAL (NLP) usando un modelo ya entrenado y explotándolo con la librería de Hugging Face (transformers) a partir de un Corpus que es usado con fines didácticos.
Resultados
Así que con este corpus y el modelo de toxicidad política, pase a predecir la toxicidad de cada uno de los tweets, obteniendo como los 5 tweets más tóxicos los siguientes(*):
(*)Al final del artículo muestro en un anexo los 30 tweets que el modelo considera «más tóxicos».
Así de primeras puede parecer sorprendente que 4 de los 5 tweets que el modelo considera más tóxico hayan sido escritos por polític@s pertenecientes a Ciudadanos, pero haciendo un análisis de las puntuaciones de toxicidad que se obtienen agregadas por partido político, se observa que son los tweets publicados por los políticos de Vox los que mayor puntuación de toxicidad media presentan:
Si visualizamos la distribución de la toxicidad por cuartiles en un gráfico de cajas, podemos observar como los tweets de Vox tienden a tener puntuaciones de toxicidad más elevadas que el resto de los tweets:
Conclusiones
- Sobre las puntuaciones de toxicidad de los tweets, parece evidente que el modelo detecta bastante bien aquellos tweets que son ofensivos, insultantes, etc. en definitiva tóxicos. Ejemplo de ello los tenemos al leer los 5 tweets que el modelo considera como los más tóxicos (también al leer los 30 más tóxicos al final del artículo), que sin entrar a valorar si uno es más tóxico que otro, podemos ver que todos son tweets con mensajes bastantes «destructivos».
- Antes de obtener las puntuaciones de toxicidad de los tweets, podíamos esperar que fuese Vox, el partido político que mayor puntuación de toxicidad obtuviese y desde luego que así ha sido, obteniendo unos valores medios de toxicidad considerablemente superiores al resto de partidos políticos.
- Excluyendo a Vox del análisis, se puede observar que los dos partidos políticos de derechas (Ciudadanos y PP) presentan unos valores medios de toxicidad superiores al de los partidos políticos de izquierdas (Unidas Podemos y PSOE). Este hecho da que pensar que el modelo ha podido ser entrenado con un corpus sesgado. ¿Qué quiero decir con esto?: Si leemos la documentación del corpus utilizado para entrenar el modelo; dice, que ha utilizado tweets escritos en el año 2021 por políticos españoles del congreso de los diputados y que estos han sido puntuados (por alguna persona humana) con un determinado grado de toxicidad. Si las personas que han leído y puntuado los tweets tenían ciertos sesgos ideológicos (por ejemplo que «fuesen de izquierdas») es posible que los tweets de políticos de derechas los puntuasen con puntuaciones más elevadas que los tweets publicados por políticos de izquierdas. Esta podría ser una explicación (no la única) del sesgo que vemos entre los niveles de toxicidad entre los partidos de izquierdas y de derechas.
- Por último observamos los bajos niveles de toxicidad que obtiene el PSOE. La explicación más plausible vendría dada por ser el partido político que esta gobernando (el corpus tiene tweets desde mayo del 2019 hasta la fecha de publicación de este artículo) y parece lógico que el partido que esta en el gobierno y sus políticos deban de mantener un tono mucho más moderado y amigable en sus tweets que los políticos que están en la oposición.
Implementación de la puntuación de toxicidad de los tweets
1.- Instalación del entorno y librerías
Para la ejecución de todo el proceso de predicción de toxicidad se ha utilizado un entorno virtual de anaconda con Python 3.7. En este entorno se han instalado de manera específica las librerías de:
- opendatasets: Librería que nos permite (entre otras cosas) descargar los datasets de Kaggle (con nombre de usuario y API KEY).
- tweet-preprocesor: Esta librería nos permite limpiar los tweets, eliminando enlaces, menciones, hashtags, emoticonos, etc.
- transformers: Librería de Hugging Face para la importación y explotación de modelos (principalmente de NLP) ya entrenados.
- tqdm: Librería que utilizo para que nos muestre una barra de evolución de los procesos (dentro de un bucle for)
Con el entorno virtual de Conda activado, procedemos a instalar estas librerías en el propio Notebook que usaremos para la predicción y análisis de toxicidad:
!pip install opendatasets==0.1.22 --user !pip install tweet-preprocessor==0.6.0 --user !pip install transformers==4.17.0 --user !pip install tqdm --user
2.- Lectura de los tweets
El Corpus (dataset) lo vamos a descargar directamente de Kaggle. Para ello y haciendo uso de la librería «opendatasets» descargaremos el dataset con la función «download()«, pasándole la url de Kaggle donde se encuentra la librería. Cuando se ejecute este comando os pedirá que ingreséis vuestro nombre de usuario de Kaggle (debéis de estar registrado en Kaggle para su descarga) y posteriormente os pedirá un API KEY que la podéis descargar de vuestro perfil de Kaggle, tal y como muestro en la siguiente imagen:
El código que descarga el Corpus (lo guarda en el sistema de ficheros del proyecto) y que lo carga en un dataframe de pandas sería el siguiente:
import pandas as pd import opendatasets as od # Descagamos el Dataset de Kaggle od.download('https://www.kaggle.com/datasets/ricardomoya/tweets-poltica-espaa', force=True) # Cargamos los tweets en un dataframe df = pd.read_table('./tweets-poltica-espaa/tweets_politica_kaggle.csv', sep='\t', header=0, engine='python') print('\nNúmero de Tweets: {}'.format(df.shape[0])) df.sample(5)
A continuación mostramos el porcentaje de tweets que hay de cada partido político en el Corpus, con el siguiente fragmento de código:
import matplotlib.pyplot as plt %matplotlib inline # Conteo de tweets por partido político df_agg = df.groupby('partido')['tweet'].count().reset_index() # Pintamos en una gráfica de sectores los resultados colors={'psoe':'#E74C3C', 'pp':'#3498DB', 'vox':'#58D68D', 'podemos':'#8E44AD', 'ciudadanos':'#E67E22'} plt.figure(figsize=(12, 6)) plt.pie(x=df_agg['tweet'].values, labels=df_agg['partido'].values, colors=[colors[key] for key in df_agg['partido'].values], autopct='%1.2f%%') plt.show()
3.- Preprocesado y limpieza de los tweets
Aunque este paso no sería necesario hacerlo para la predicción de toxicidad del tweet, es recomendable hace una pequeña limpieza de los tweets, quitando el texto que no aporta información relevante para saber el grado de toxicidad de un tweet. En este caso, usando la librería «tweet-preprocesor» y configurandola para que elimine de los tweets las urls, menciones, hashtags, y emoticonos (entre otras), eliminaremos de cada todo ese texto, de tal manera que nos quede el tweet más limpio para pasárselo al modelo y para que tenga que procesar menor cantidad de texto, lo que nos supondrá una reducción en los tiempos de predicción. A continuación mostramos el código que realiza esta limpieza, guardando el tweet «limpio» en una nueva columna (clean_tweet) del dataframe de pandas.
import preprocessor as p import unidecode from tqdm import tqdm # Configuramos tweet-preprocessor para que nos elimine del tweet: Urls, menciones, emoticonos, etc. p.set_options(p.OPT.URL, p.OPT.MENTION, p.OPT.HASHTAG, p.OPT.EMOJI, p.OPT.SMILEY, p.OPT.ESCAPE_CHAR) # Limpiamos los tweets for i in tqdm(range(df.shape[0])): # Limpiamos el tweet con tweet-preprocessor y lo pasamos a minúsculas df.loc[i, 'clean_tweet'] = (p.clean(unidecode.unidecode(df.iloc[i]['tweet'].lower()))) df[['partido', 'timestamp', 'tweet', 'clean_tweet']].sample(5)
4.- Predicción de la Toxicidad de los Tweets
Para realizar la predicción de la toxicidad de un tweet, debemos en primer lugar importarnos el modelo de Hugging Face creado por el equipo de Newtral. Esto es tan sencillo como:
from transformers import pipeline # Importamos el modelo toxicity_scorer = pipeline("text-classification", model="Newtral/xlm-r-finetuned-toxic-political-tweets-es")
Una vez que tenemos el modelo importando (en el objeto «toxicity_score«), su explotación es tan sencilla como pasarle el texto a predecir al objeto del modelo:
toxicity_scorer("TEXTO CON EL TWEET PARA SU PUNTUACIÓN", return_all_scores=True)
Esto nos devolverá una estructura de datos con las puntuaciones de «Toxic» y «Very_Toxic» (LABEL_0 y LABEL_1) del tweet que le hemos pasado.
A continuación mostramos el fragmento de código en el que le pasamos al objeto que contiene el modelo el tweet «limpio» y guardamos en el dataframe (en 3 nuevas columnas) los 2 valores de toxicidad que nos devuelve el modelo («Toxic» y «Very_Toxic») y otra nueva columna con la suma de las 2 puntuaciones. IMPORTANTE: este proceso es muy costoso computacionalmente y puede tardar varias horas en ejecutarse, dependiendo de las características del ordenador:
from transformers import pipeline # Importamos el modelo toxicity_scorer = pipeline("text-classification", model="Newtral/xlm-r-finetuned-toxic-political-tweets-es") # Obtenemos los scores de cada uno de los tweets for i in tqdm(range(df.shape[0])): score = toxicity_scorer(df.iloc[i]['clean_tweet'], return_all_scores=True) df.loc[i, 'toxic'] = score[0][0]['score'] df.loc[i, 'very_toxic'] = score[0][1]['score'] df.loc[i, 'toxic_score'] = score[0][0]['score'] + score[0][1]['score']
5.- Ranking de los tweets más tóxicos
Con los tweets ya puntuados, los ordenamos de mayor a menor toxicidad y mostramos los 10 tweets más tóxicos.
from datetime import datetime # Ordenamos los tweets por toxicidad de mayor a menor df_rank = df.sort_values('toxic_score', ascending=False).reset_index() # Mostramos los 10 tweets más tóxicos según el modelo TOP = 10 for i in range(TOP): print('{}º Posición:'.format(i+1)) print('\tPartido Político: {}'.format(df_rank.iloc[i]['partido'].upper())) print('\tFecha: {}'.format(datetime.fromtimestamp(int(df_rank.iloc[i]['timestamp'])).strftime('%d-%m-%Y'))) print('\tScore: {:.6f}'.format(df_rank.iloc[i]['toxic_score'])) print('\tTweet: {}\n'.format(df_rank.iloc[i]['tweet'])) print('----------------------------------------------------------------------------')
No se muestra la salida de este fragmento de código, ya que los 5 tweets considerados más tóxicos se muestran al principio del artículo y los 30 tweets más tóxicos al final del artículo.
6.- Gráficos con las distribuciones y toxicidades de los tweets por partido político
Por último realizamos un sencillo análisis de toxicidad de los tweets publicados por los miembros de los diferentes partidos políticos, agregando las puntuaciones. A continuación calculamos los valores medios de toxicidad:
df_agg = (df_rank .groupby('partido')['toxic_score'] .mean() .reset_index() .sort_values('toxic_score', ascending=False))
Mismos valores representados en un gráfico de barras:
import matplotlib.pyplot as plt import seaborn as sns fig, ax = plt.subplots(figsize=(12, 6)) sns.barplot(x="partido", y="toxic_score", data=df_rank, order=df_agg['partido'], palette=colors) ax.set_title('Toxicidad Media de lo Tweets por Partido Político') ax.set_ylabel('Score Toxicidad (Media)') ax.set_xlabel('Partido Político') ax.grid()
Distribución por cuartiles de las puntuaciones de toxicidad:
fig, ax = plt.subplots(figsize=(12, 6)) sns.boxplot(x="partido", y="toxic_score", data=df_rank, order=df_agg['partido'], palette=colors) ax.set_title('Distribución Toxicidad de lo Tweets por Partido Político') ax.set_ylabel('Score Toxicidad (Media)') ax.set_xlabel('Partido Político')
ANEXO: 30 Tweets con mayor puntuación de toxicidad
1º Posición:
Partido Político: CIUDADANOS
Fecha: 20-06-2019
Score: 1.991903
Tweet: Que es como decir que el castellano es la lengua de las putas y los camellos. Una nueva ocurrencia de la fanática que quemó la Constitución en TV3.Estáis rociando Cataluña de gasolina desde hace décadas, Empar. Un día saltará una chispa. https://t.co/uKuIjpYkka
2º Posición:
Partido Político: VOX
Fecha: 03-12-2019
Score: 1.991774
Tweet: Lamentable es que dejárais a los separatistas dar un golpe de Estado y sentárais las bases para el segundo. Tuit ridiculo. ¿Pero no eramos fachas irredentos? Sois trileros y desleales, y la gente lo sabe.¿Todo para azuzar el miedo? Si tenéis miedo, apartaos, ¡que vamos! https://t.co/SBDNmZ53Ce
3º Posición:
Partido Político: CIUDADANOS
Fecha: 03-05-2021
Score: 1.991752
Tweet: Para ser un auténtico oprimido tienes que tener la nómina de un conseller y una corte de aduladores colocados en todo tipo de chiringuitos.Por dinero y poder, Junts y ERC son capaces de gobernar juntos sin ni tan siquiera dirigirse la palabra.https://t.co/8D1zAPyWil
4º Posición:
Partido Político: CIUDADANOS
Fecha: 04-01-2020
Score: 1.991741
Tweet: A ver si se entera @NestorRego que no puede hablar en esa tribuna en nombre de todos los gallegos. Los gallegos somos gente de bien, y no Kamikaces desnortados que se vendan por 1 €. Lástima la ingenuidad de este @obloque creyéndose la palabra del infame de Sánchez y su pacto https://t.co/iVcstiLyOq
5º Posición:
Partido Político: CIUDADANOS
Fecha: 24-11-2021
Score: 1.991736
Tweet: A Sánchez ya no le queda más libertad por perder ante los separatistas:❌Sacar a la @policia de Via Laietana❌Ley infame para las universidades❌Adoctrinamiento📡@InesArrimadas «Regalan este pack de la vergüenza al nacionalismo para mantenerse en Moncloa» #ActualidadCs https://t.co/ZP0VgZ6hiz
6º Posición:
Partido Político: VOX
Fecha: 17-03-2021
Score: 1.991732
Tweet: A los que hoy se rasgan las vestiduras hablando del suicido, errejonistas, podemitas y demás patulea pogre: muchos de los que se suicidan son hombres traumatizados por las denuncias falsas de violencia «de género» y por no poder ver a sus hijos.Y os da igual. Hipócritas.
7º Posición:
Partido Político: VOX
Fecha: 07-02-2022
Score: 1.991727
Tweet: Zapatero anda ya por el mundo con una escolta como la de un Chapo Guzmán. Como los grandes narcos y asesinos que dirigen allí los negocios del “progresismo”. Nada sería más justo que dejar a Zapatero sin escolta en cualquier rincón del país que más sufre su infamia infinita. https://t.co/4sh1dP7FzF
8º Posición:
Partido Político: VOX
Fecha: 06-09-2021
Score: 1.991721
Tweet: @Espectadorescep @Frexer3000 @_JJOAKINN_ @beerman_garcia @CapitanBitcoin Eso os pasa a los progreanalfabetos, que tiráis de wikipedia y no solo os creéis todas sus trampas sectarias y manipulaciones sino que no tenéis los elementos básicos para entender las oraciones enteras.
9º Posición:
Partido Político: VOX
Fecha: 13-05-2021
Score: 1.991710
Tweet: Contra la libertad que es libertinaje, Casado quiere medios para acabar con estas malditas manías de los españoles de moverse por España sin permiso suyo. https://t.co/W4moymYHU0
10º Posición:
Partido Político: PP
Fecha: 11-08-2021
Score: 1.991700
Tweet: Podemos amenaza con salir a la calle por la luz: «Daremos la batalla en todos los espacios» “En todos los espacios” excepto en el gobierno al que pertenecen. Son gobierno y oposición. Unos inútiles charlatanes. https://t.co/v5bY8kumf0
11º Posición:
Partido Político: PP
Fecha: 29-05-2021
Score: 1.991699
Tweet: Todo eran mentiras de unos dirigentes tramposos y sin escrúpulos. Ahora todo vale para mantenerse en el helicóptero riéndose de los españoles https://t.co/LfTJsb0JNV
12º Posición:
Partido Político: VOX
Fecha: 08-09-2021
Score: 1.991678
Tweet: El voto al PP de Casado es tan tóxico como el voto a Sánchez. O peor. Porque volverá a embarrar todo para confundir al español de buena voluntad. Y solo tapará con mentiras las heridas hoy abiertas para que pudran más como hicieron bajo Rajoy. España tiene que sanar sus heridas.
13º Posición:
Partido Político: VOX
Fecha: 09-01-2022
Score: 1.991667
Tweet: Vamos a ver, Carmeida, aquí el único que ha vetado a los madrileños y a la verdad has sido tú, engañándolos y traicionándolos.https://t.co/hJAipqyDsJ
14º Posición:
Partido Político: PODEMOS
Fecha: 28-02-2020
Score: 1.991660
Tweet: De los productores de «Paletos», con Díaz Ayuso, llega a sus pantallas «Otro pijazo madrileño de derechas que insulta a toda la España Vaciada». Protagoniza Jorge «prefiero a un corrupto que a un comunista» Bustos, jefe de opinión en El Mundo. https://t.co/GjjGMYDLCe
15º Posición:
Partido Político: PP
Fecha: 08-11-2021
Score: 1.991658
Tweet: La propaganda de Sánchez: “No vamos a dejar a nadie atrás”Los hechos: Con Sánchez toda España se queda atrás 👉 @FinancialTimes “España se queda atrás#HayAlternativa al (des)gobierno de Sánchez que arruina 🇪🇸 https://t.co/uCzrYJFDvB
16º Posición:
Partido Político: CIUDADANOS
Fecha: 08-03-2022
Score: 1.991656
Tweet: Es vergonzoso que la Generalitat siga con su aquelarre separatista, gastando el dinero de todos en chiringuitos en el extranjero. Con la crisis que estamos sufriendo deberían centrarse en atraer inversiones y no en vender odio a España.https://t.co/455d7X7yj1
17º Posición:
Partido Político: VOX
Fecha: 04-11-2021
Score: 1.991649
Tweet: Unai Sordo rechaza a los trabajadores de España de @solidaridad_esp Como buen subvencionado, prefiere sentarse con las patronales subvencionadas, los separatistas subvencionados, los chiringuitos de género subvencionados. Bravo por Solidaridad https://t.co/MIy9Ynjeb0
18º Posición:
Partido Político: VOX
Fecha: 18-06-2019
Score: 1.991648
Tweet: 😡 Socialismo en estado puro: el chiringuito cultural de Susana Díaz dedicaba 23 millones a pagar sueldos y sólo uno a la gestión cultural. ✅ Esperamos que la consejera actual tenga el valor de acabar con esta mamandurria.⬇⬇⬇https://t.co/j4vFkgcA0O
19º Posición:
Partido Político: VOX
Fecha: 17-03-2021
Score: 1.991647
Tweet: Esta televisión de Madrid se la entregaron Ciudadanos y el PP a Podemos y a los sórdidos matones sindicales. Así están. Esta es la televisión pública madrileña: «La que ha liado Isabel Díaz Ayuso, la que ha liado» – Periodista Digital https://t.co/NtvM5iDqAH
20º Posición:
Partido Político: VOX
Fecha: 28-10-2021
Score: 1.991641
Tweet: Los enemigos de España y la libertad son forofos de George Soros. El izquierdismo separatista y el corrupto consenso socialdemócrata rezan a su gurú con zozobra. Tienen miedo a la resistencia. No son Polonia y Hungria solas, es toda la Europa de las naciones. La auténtica Europa. https://t.co/jktlBWxbaF
21º Posición:
Partido Político: VOX
Fecha: 29-01-2020
Score: 1.991641
Tweet: Pues que no se preocupe el señor Cocho que ya lo hacemos los de VOX: Un gobierno que pacta con golpistas y comunistas, después de haber dicho en campaña que nunca lo haría, es un gobierno legal pero ilegítimo, y su presidente, un traidor a España y a los españoles
22º Posición:
Partido Político: VOX
Fecha: 02-02-2022
Score: 1.991639
Tweet: ¡Puigdemont, golpista cobarde! Menos preguntas lloronas a la Comisión Europea y más rendir cuentas de tus delitos ante los tribunales españoles. No te vas a salir de rositas. En @vox_es no nos olvidamos de tus delitos. Y más pronto que tarde…tic, tac, tic, tac https://t.co/qahEK24NvD
23º Posición:
Partido Político: VOX
Fecha: 06-09-2021
Score: 1.991631
Tweet: Esto es Macron, el ultracentrismo. Que pega palizas como la policía de Putin. ¿La obsesión de Casado por tener una ley de pandemia para recortar nuestros derechos fundamentales se debe a las ganas de imitar al cínico e hipócrita napoleoncito? https://t.co/pF3uI0bwLL
24º Posición:
Partido Político: PODEMOS
Fecha: 14-12-2021
Score: 1.991623
Tweet: Iván Espinosa de los Monteros es un defraudador condenado. Sabemos que la ultraderecha no tiene escrúpulos y que aprendieron del partido más corrupto de Europa, pero tenga un poco de decencia, deje de manchar las instituciones y dimita.
25º Posición:
Partido Político: VOX
Fecha: 09-04-2021
Score: 1.991614
Tweet: @MiquelGimenezG1 @ACOM_es Los ayuntamientos con podemitas y sus socios gabilondos por toda la geografía española se han convertido en covachas antisemitas que financian a terroristas, incitan al odio a Israel y banalizan por sistema el Holocausto. Hay que evitar que esa mugre inmoral gobierne Madrid.
26º Posición:
Partido Político: PP
Fecha: 17-01-2020
Score: 1.991612
Tweet: 📚 Qué barbaridad, señora Celaá. ¿Cómo que los hijos no pertenecen a los padres?Los hijos a quien no le pertenecen es a usted, ni a la señora Montero, ni al señor Sánchez. https://t.co/zlPNygbfOT
27º Posición:
Partido Político: CIUDADANOS
Fecha: 03-06-2019
Score: 1.991610
Tweet: El separatismo sigue dando tratos privilegiados a sus amigos, ya sean corruptos o golpistas. Es vergonzoso que se exija a los ciudadanos que cumplan con la ley, mientras los líderes nacionalistas quieren impunidad para seguir haciendo de las suyas. https://t.co/kkhtmQPQth
28º Posición:
Partido Político: CIUDADANOS
Fecha: 03-06-2019
Score: 1.991610
Tweet: El separatismo sigue dando tratos privilegiados a sus amigos, ya sean corruptos o golpistas. Es vergonzoso que se exija a los ciudadanos que cumplan con la ley, mientras los líderes nacionalistas quieren impunidad para seguir haciendo de las suyas. https://t.co/kkhtmQPQth
29º Posición:
Partido Político: VOX
Fecha: 12-04-2021
Score: 1.991607
Tweet: Nadia Calviño es una estafadora política tan consumada co,o Sánchez, Iglesias o Yolanda Díaz.Es una estafa más pretender que en este gobierno queda cualquier resto de probidad. https://t.co/at3Bpx2FTp
30º Posición:
Partido Político: PODEMOS
Fecha: 10-02-2021
Score: 1.991607
Tweet: Rapero de izquierdas canta que el emérito es corrupto 👉 a prisión.Neonazi que trabajó para VOX dispara con una escopeta a las fotos del Presidente, el Vicepresidente y varios Ministros 👉 no hay delito.Plena normalidad democrática. Di que sí. https://t.co/ahDuUGfVU5