Este código compara dos corpus de texto pertenecientes a dos políticos, identifica las palabras más significativas de cada corpus mediante el vectorizador TF-IDF y calcula una métrica de similitud entre los corpus preprocesados. Finalmente, muestra las palabras significativas y la métrica de similitud en la salida.
De esta forma, se pueden ver las diferencias de enfoque que cada político pone en la comunicación con su electorado, así como los distintos aspectos a los que presta atención en sus campañas o mensajes.
El código proporcionado realiza las siguientes tareas:
Cada parte del código se explica de la siguiente manera:
Importación de bibliotecas:
Se importan las bibliotecas necesarias para procesar texto, calcular el vectorizador TF-IDF y la métrica de similitud.
import spacy
import numpy as np
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics.pairwise import cosine_similarity
read_file
función:
Esta función toma una ruta de archivo como entrada y devuelve su contenido como una cadena.
def read_file(file_path):
with open(file_path, 'r', encoding='utf-8') as file:
return file.read()
preprocess
función:
Esta función toma un texto como entrada y realiza las siguientes tareas de preprocesamiento:
es_core_news_sm
SpaCy modelo de lenguaje para procesar texto en español.def preprocess(text):
nlp = spacy.load("es_core_news_sm")
doc = nlp(text)
tokens = [token.lemma_ for token in doc if not token.is_stop and not token.is_punct]
return " ".join(tokens)
get_significant_words
función:
Esta función toma dos corpus y hace lo siguiente:
top_n
palabras con los mayores pesos TF-IDF para cada corpus.def get_significant_words(corpus1, corpus2):
vectorizer = TfidfVectorizer()
corpus = [corpus1, corpus2]
X = vectorizer.fit_transform(corpus)
feature_names = vectorizer.get_feature_names_out()top_n = 10
significant_words = []
for i in range(len(corpus)):
row = np.squeeze(X[i].toarray())
top_indices = row.argsort()[-top_n:]
words = [feature_names[idx] for idx in top_indices]
significant_words.append(words)
return significant_words
get_similarity_metric
función:
Esta función toma dos corpus y calcula la métrica de similitud (similitud de coseno) entre ellos. Devuelve la métrica de similitud como un valor entre 0 y 1.
def get_similarity_metric(corpus1, corpus2):
vectorizer = TfidfVectorizer()
X = vectorizer.fit_transform([corpus1, corpus2])
similarity_matrix = cosine_similarity(X)
similarity_score = similarity_matrix[0, 1]
return similarity_score
Ejecutando el código:
read_file
función.file_path1 = "politician1.txt"
file_path2 = "politician2.txt"corpus_politician1 = read_file(file_path1)
corpus_politician2 = read_file(file_path2)
Los corpus son preprocesados usando el preprocess
función para eliminar palabras vacías, signos de puntuación y aplicar lematización.
corpus1_preprocessed = preprocess(corpus_politician1)
corpus2_preprocessed = preprocess(corpus_politician2)
Las palabras significativas de cada corpus se obtienen mediante el get_significant_words
función.
significant_words_list = get_significant_words(corpus1_preprocessed, corpus2_preprocessed)
La métrica de similitud (similitud de coseno) entre los corpus preprocesados se calcula utilizando el get_similarity_metric
función.
similarity_score = get_similarity_metric(corpus1_preprocessed, corpus2_preprocessed)
Las palabras significativas y la métrica de similitud se imprimen en la salida.
print(f"Significant words for Politician 1 ({file_path1}):")
for word in significant_words_list[0]:
print(f"- {word}")print(f"nSignificant words for Politician 2 ({file_path2}):")
for word in significant_words_list[1]:
print(f"- {word}")
print(f"nSimilarity metric between the two corpora: {similarity_score:.4f}")
Este código compara dos corpus de texto pertenecientes a dos políticos, identifica las palabras más significativas de cada corpus mediante el vectorizador TF-IDF y calcula una métrica de similitud entre los corpus preprocesados. Finalmente, muestra las palabras significativas y la métrica de similitud en la salida.
Versión completa:
import spacy
import numpy as np
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics.pairwise import cosine_similaritydef read_file(file_path):
with open(file_path, 'r', encoding='utf-8') as file:
return file.read()
def preprocess(text):
nlp = spacy.load("es_core_news_sm")
doc = nlp(text)
tokens = [token.lemma_ for token in doc if not token.is_stop and not token.is_punct]
return " ".join(tokens)
def get_significant_words(corpus1, corpus2):
vectorizer = TfidfVectorizer()
corpus = [corpus1, corpus2]
X = vectorizer.fit_transform(corpus)
feature_names = vectorizer.get_feature_names_out()
top_n = 10
significant_words = []
for i in range(len(corpus)):
row = np.squeeze(X[i].toarray())
top_indices = row.argsort()[-top_n:]
words = [feature_names[idx] for idx in top_indices]
significant_words.append(words)
return significant_words
def get_similarity_metric(corpus1, corpus2):
vectorizer = TfidfVectorizer()
X = vectorizer.fit_transform([corpus1, corpus2])
similarity_matrix = cosine_similarity(X)
similarity_score = similarity_matrix[0, 1]
return similarity_score
file_path1 = "politician1.txt"
file_path2 = "politician2.txt"
corpus_politician1 = read_file(file_path1)
corpus_politician2 = read_file(file_path2)
corpus1_preprocessed = preprocess(corpus_politician1)
corpus2_preprocessed = preprocess(corpus_politician2)
significant_words_list = get_significant_words(corpus1_preprocessed, corpus2_preprocessed)
similarity_score = get_similarity_metric(corpus1_preprocessed, corpus2_preprocessed)
print(f"Significant words for Politician 1 ({file_path1}):")
for word in significant_words_list[0]:
print(f"- {word}")
El Log Odds Ratio con Informative Dirichlet Prior (LODP) es un método poderoso y sólido para comparar el uso de palabras en dos corpus, desarrollado por Monroe et al. en su artículo de 2009 «Fightin’ Words: selección y evaluación de características léxicas para identificar el contenido del conflicto político». El método es particularmente útil para identificar palabras características que distinguen el idioma utilizado en dos textos o conjuntos de textos diferentes.
En pocas palabras, LODP calcula el logaritmo de la razón de probabilidades de las frecuencias de los términos entre dos corpus al tiempo que incorpora una distribución previa de frecuencias de palabras para tener en cuenta los posibles sesgos y suavizar las estimaciones. Esta información previa generalmente se genera a partir de un conjunto de datos más grande y representativo, lo cual es útil cuando los corpus que se comparan son pequeños o contienen datos escasos.
LODP se basa en el concepto de un marco bayesiano que utiliza un Dirichlet previo, que es una generalización multivariante de la distribución Beta. Aborda el problema del sobreajuste en el método tradicional de razón de probabilidades logarítmicas mediante la incorporación de conocimientos previos de un conjunto de datos más grande. Esto garantiza que se regularicen las palabras raras o las palabras con proporciones extremas de probabilidades logarítmicas, lo que proporciona una estimación más estable de la importancia de las palabras.
Los pasos clave en el método LODP son los siguientes:
El método LODP ofrece varias ventajas sobre los métodos tradicionales basados en la frecuencia, como el TF-IDF, al incorporar información previa y al proporcionar una medida de importancia (puntuaciones z) para cada palabra. Esto permite una comparación más confiable de la importancia y el uso de las palabras en dos corpus, lo que la convierte en una herramienta valiosa para el análisis comparativo de textos en el campo del procesamiento del lenguaje natural.
Sobre la base proporcionada en la explicación anterior, el método LODP también brilla en su capacidad para manejar corpus desequilibrados, donde un corpus puede ser significativamente más grande que el otro. Este desequilibrio a menudo conduce a resultados poco fiables en otras técnicas, pero LODP puede mantener su solidez gracias a la incorporación del informativo Dirichlet previo.
Una de las fortalezas clave de LODP es su adaptabilidad a varias aplicaciones en el procesamiento del lenguaje natural, como:
El método LODP también se puede extender para manejar más de dos corpus, haciendo comparaciones por pares y agregando los resultados. Además, LODP se puede utilizar junto con otras técnicas de PNL, como el modelado de temas o el análisis de sentimientos, para proporcionar una comprensión más completa de las diferencias y similitudes entre los corpus.
El Log Odds Ratio con Informative Dirichlet Prior es un método altamente eficaz y versátil para comparar el uso de palabras en diferentes textos o conjuntos de textos. Su solidez a las variaciones en el tamaño del corpus, la incorporación de información previa y la medida de importancia (puntajes z) lo convierten en una herramienta invaluable para investigadores y profesionales en el campo del procesamiento del lenguaje natural. La capacidad del método LODP para identificar palabras y patrones distintivos contribuye a una comprensión más profunda del lenguaje y la comunicación, lo que permite análisis más informados de una amplia gama de datos basados en texto.
import numpy as np
import spacy
from collections import Counter
from scipy.sparse import csr_matrix
from scipy.special import psi
import matplotlib.pyplot as pltdef read_file(file_path):
with open(file_path, 'r', encoding='utf-8') as file:
return file.read()
def preprocess(text):
nlp = spacy.load("es_core_news_sm")
doc = nlp(text)
tokens = [token.lemma_ for token in doc if not token.is_stop and not token.is_punct]
return tokens
def log_odds_ratio_informative_dirichlet_prior(corpus1, corpus2, prior_corpus, alpha=0.01):
term_count_corpus1 = Counter(corpus1)
term_count_corpus2 = Counter(corpus2)
term_count_prior = Counter(prior_corpus)
vocab = set(term_count_corpus1) | set(term_count_corpus2) | set(term_count_prior)
n_terms = len(vocab)
term_indices = {term: i for i, term in enumerate(vocab)}
counts1 = np.zeros(n_terms)
counts2 = np.zeros(n_terms)
prior_counts = np.zeros(n_terms)
for term, count in term_count_corpus1.items():
counts1[term_indices[term]] = count
for term, count in term_count_corpus2.items():
counts2[term_indices[term]] = count
for term, count in term_count_prior.items():
prior_counts[term_indices[term]] = count
n1 = counts1.sum()
n2 = counts2.sum()
nprior = prior_counts.sum()
counts1 += alpha * prior_counts
counts2 += alpha * prior_counts
log_odds = np.log(counts1) - np.log(counts1.sum()) - np.log(counts2) + np.log(counts2.sum())
variance = 1 / counts1 + 1 / counts2
z_scores = log_odds / np.sqrt(variance)
return {term: z_scores[i] for term, i in term_indices.items()}
def plot_top_words(z_scores, n=10):
sorted_terms = sorted(z_scores, key=z_scores.get)
top_positive_terms = sorted_terms[-n:]
top_negative_terms = sorted_terms[:n]
top_positive_scores = [z_scores[term] for term in top_positive_terms]
top_negative_scores = [z_scores[term] for term in top_negative_terms]
fig, ax = plt.subplots()
y_pos = np.arange(n)
ax.barh(y_pos, top_positive_scores, align='center', color='blue', label='Corpus 1')
ax.barh(-y_pos - 1, top_negative_scores, align='center', color='red', label='Corpus 2')
ax.set_yticks(np.hstack((y_pos, -y_pos - 1)))
ax.set_yticklabels(top_positive_terms + top_negative_terms)
ax.invert_yaxis()
ax.set_xlabel('Z-Scores')
ax.set_title('Top Words by Log Odds Ratio with Informative Dirichlet Prior')
ax.legend()
plt.show()
file_path1 = "politician1.txt"
file_path2 = "politician2.txt"corpus_politician1 = read_file(file_path1)
corpus_politician2 = read_file(file_path2)
corpus1_preprocessed = preprocess(corpus_politician1)
corpus2_preprocessed = preprocess(corpus_politician2)
# Combine both corpora to create a prior corpus
prior_corpus = corpus1_preprocessed + corpus2_preprocessed
z_scores = log_odds_ratio_informative_dirichlet_prior(corpus1_preprocessed, corpus2_preprocessed, prior_corpus)
plot_top_words(z_scores)
# Combine both corpora to create a prior corpus
prior_corpus = corpus1_preprocessed + corpus2_preprocessed
z_scores = log_odds_ratio_informative_dirichlet_prior(corpus1_preprocessed, corpus2_preprocessed, prior_corpus)
plot_top_words(z_scores)
Si te resultó útil, sígueme para ver las próximas publicaciones.
¡Gracias!