¿Melania Trump plagió el discurso de Michelle Obama?
En el año 2016, durante la convención del partido republicano, Melania Trump dio un discurso apoyando la campaña de su esposo Donald; tan pronto como terminó la convención, usuarios de Twitter notaron similitudes en algunas lineas del discurso de la señora Trump y otro pronunciado por Michelle Obama ocho años antes en la convención del partido demócrata. La crítica sobre los Trump no se hizo esperar y el equipo de campaña llevó a cabo su labor de defensa con el argumento de que el discurso era un reflejo de experiencias de la vida real de Melania.
¿Cómo fue que los usuarios de Twitter notaron las semejanzas? Por un lado, algunas lineas eran exactamente iguales, por otro, como lo dijo un articulo de Usa Today:
It’s not entirely a verbatim match, but the two sections bear considerable similarity in wording, construction and themes.
Si quisieras automatizar el proceso de detección de similitudes ¿qué enfoque tomarías? Una posible solución sería comparar ambos textos, palabra por palabra, sin embargo esto no escalaría de manera eficiente; considera la complejidad de comparar todas las posibles frases compuestas por palabras consecutivas de un documento contra otro. Afortunadamente NLP nos da una solución elegante.
¿Cómo lo logramos?
Hay una técnica de NLP llamada similitud de textos, que se encarga del problema descrito: ¿Cómo comparar textos de una manera eficiente? Para lograr esto, es necesario transformar los documentos en un representación común y definir una métrica para compararlos.
En las secciones siguientes encontraras: los conceptos matemáticos detrás del proceso, el código explicado en detalle para que lo puedas reusar y finalmente la respuesta a la pregunta inicial: ¿Melania cometió plagio o no?
Conceptos de similitud de textos
TF-IDF
El texto es convertido en un vector. Las palabras se denominan features. Cada posición del vector representa un feature y el valor de la posición en el vector depende del método usado. Una forma de calcularlo, es contar cuantas veces la palabra aparece en el texto, dividirlo por el total de palabras únicas del documento y asignar este valor en el vector para el feature, esto es llamado Term Frequency o TF.
Term frequency por si solo da relevancia a palabras comunes en el documento, pero que no son necesariamente importantes, pueden ser stopwords, Las stopwords son palabras que no añaden valor al texto, como artículos, pronombres o preposiciones: yo, tu, el, la, a, ante, de, desde, etc.
Para saber si una palabra es importante en un documento, Inverse document frequency o IDF es usado, IDF encuentra la importancia en el documento contando cuantos documentos ademas del actual, contienen la palabra.
En IDF, N representa el número de documentos en el corpus, mientras que dft representa el número de documentos que contienen a una palabra t. Si todos los documentos en el corpus contienen la palabra t, entonces N/dft será igual a 1, y log(1) = 0, lo que significa que la palabra no es representativa, pues haciendo énfasis nuevamente, aparece en todos los documentos.
Term frequency–inverse document frequency o TF-IDF combina las dos métricas anteriores: si una palabra aparece en un documento, pero también aparece en los demás documentos del corpus, significa que no es representativa y TF-IDF le da un valor bajo. Por el contrario, si la palabra aparece muchas veces en un documento y solo aparece en ese documento, TF-IDF le da un valor alto.
Los valores de TF-IDF son calculados para cada palabra y dichos valores son asignados a las palabras del vector.
Similitud de coseno
Si se tienen los textos en representación vectorial ¿cómo se pueden comparar?
Primero, veamos un ejemplo de la conversión de texto a vector en Python:
from sklearn.feature_extraction.text import TfidfVectorizer phrase_one = 'This is Sparta' phrase_two = 'This is New York' vectorizer = TfidfVectorizer () X = vectorizer.fit_transform([phrase_one,phrase_two]) vectorizer.get_feature_names() ['is', 'new', 'sparta', 'this', 'york'] X.toarray() array([[0.50154891, 0. , 0.70490949, 0.50154891, 0. ], [0.40993715, 0.57615236, 0. , 0.40993715, 0.57615236]])
Este código muestra dos textos, “This is Sparta” y “This is New York“. El vocabulario está compuesto por cinco palabras: “This“, “is“, “Sparta“, “New” y “York“.
La linea vectorizer.get_feature_names() muestra el vocabulario. La linea X.toarray() muestra ambos textos como vectores con el valor asignado por TF-IDF para cada palabra. Se puede ver como, para el primer vector, la segunda y quinta posición tienen un valor de cero. Estas posiciones corresponden a las palabras: “new” y “york” las cuales no aparecen en el primer texto. De la misma forma, la tercer posición del segundo vector es también cero, esta posición corresponde a la palabra “sparta“, la cual no aparece en el segundo texto.
¿Y cómo comparamos los vectores? Usando el producto punto es posible encontrar el ángulo entre dos vectores, este es el concepto conocido como similitud de coseno. Teniendo dos vectores y calculando el ángulo entre ellos, es posible medir que tan cerca están estos, por lo tanto, permite determinar que tan parecidos son dos textos. Un ángulo de cero significa que los textos son exactamente iguales. Si recuerdas tus clases de secundaria, el coseno de cero es 1.
Encontrando la similitud entre textos con Python
Primero, se cargan los paquetes de NLTK y Sklearn, se define una lista con los símbolos de puntuación y las stopwords, para que sean retiradas del texto.
from string import punctuation from nltk.corpus import stopwords from sklearn.metrics.pairwise import cosine_similarity from sklearn.feature_extraction.text import TfidfVectorizer language_stopwords = stopwords.words('english') non_words = list(punctuation)
Se definen tres funciones, una para remover las stopwords, otra para remover los símbolos de puntuación y otra que recibe la ruta de un archivo de texto como parámetro, lee el archivo, transforma el texto a minúscula y llama las otras dos funciones para tener el texto preprocesado.
def remove_stop_words(dirty_text): cleaned_text = '' for word in dirty_text.split(): if word in language_stopwords or word in non_words: continue else: cleaned_text += word + ' ' return cleaned_text def remove_punctuation(dirty_string): for word in non_words: dirty_string = dirty_string.replace(word, '') return dirty_string def process_file(file_name): file_content = open(file_name, "r").read() # All to lower case file_content = file_content.lower() # Remove punctuation and spanish stopwords file_content = remove_punctuation(file_content) file_content = remove_stop_words(file_content) return file_content
Se llama la función process_file para cargar los archivos a analizar, en este ejemplo, estoy usando el contenido de tres posts anteriores de mi blog.
nlp_article = process_file("nlp.txt") sentiment_analysis_article = process_file("sentiment_analysis.txt") java_certification_article = process_file("java_cert.txt")
Una vez que se tiene el texto preprocesado, se usa TF-IDF y se aplica la similitud de coseno.
#TF-IDF vectorizer = TfidfVectorizer () X = vectorizer.fit_transform([nlp_article,sentiment_analysis_article,java_certification_article]) similarity_matrix = cosine_similarity(X,X)
La salida es la siguiente matriz de similitud:
[[1. 0.217227 0.05744137] [0.217227 1. 0.04773379] [0.05744137 0.04773379 1. ]]
Observa la diagonal de unos en la matriz, cada uno representa la similitud de un documento consigo mismo, el valor 0.217227 es la similitud entre los posts de NLP y análisis de sentimientos. El valor de 0.05744137 es la similitud entre el post de NLP y el de certificación de Java. Finalmente el valor de 0.04773379 representa la similitud entre los posts de análisis de sentimientos y el de la certificación de Java. Ya que el de NLP y el de análisis de sentimientos tratan temas en común, su medida de similitud es mas grande que la que tiene cada uno con la de la certificación de Java.
Similitud entre el discurso de Melania Trump y el de Michelle Obama
Los textos de los discursos se pueden encontrar en este artículo, usando el mismo proceso se calcula la siguiente matriz de similitud:
[[1. 0.29814417] [0.29814417 1. ]]
Si te saltaste la explicación técnica hasta este punto buscando el resultado, te daré un resumen: usando una técnica de NLP estimé la similitud de dos posts de este blog que tienen temas en común y fueron escritos por mi. Luego, usando el mismo método, estimé la similitud entre el discurso de Melania y Michelle.
Ahora, apliquemos algo de análisis. Al calcular la similitud entre dos posts escritos por un mismo autor (yo) que tratan sobre temas relacionados (NLP y análisis de sentimientos), el resultado fue de 0.217227. La similitud entre los discursos de Melania y Michelle fue de 0.29814417. Lo anterior, quiere decir, que dos discursos escritos por personas diferentes pertenecientes a corrientes políticas opuestas, son mas parecidos que mis dos posts. Te dejo la conclusión final a ti. El código completo y los archivos puedes encontrarlos en mi repo de Github.
¡Buena suerte con tu análisis!