NLP and transformers / NLP core
NLP Techniques for Short Text Analysis in Python
Contents
- Introduction to NLP and Short Text Analysis
- Text Preprocessing
- Feature Extraction: Bag of Words
- Feature Extraction: TF-IDF
- Text Classification: Naive Bayes
- Text Classification: Support Vector Machines (SVM)
- Sentiment Analysis
- Named Entity Recognition (NER)
- Topic Modeling: Latent Dirichlet Allocation (LDA)
- Word Embeddings: Word2Vec
- Text Summarization: Extractive Method
- Text Generation: Markov Chain
- Real-Life Example: Spam Detection
- Real-Life Example: Customer Feedback Analysis
- Additional Resources
Introduction to NLP and Short Text Analysis
Natural Language Processing (NLP) is a field of artificial intelligence that focuses on the interaction between computers and human language. Short text analysis is a crucial subset of NLP, dealing with brief pieces of text such as tweets, product reviews, or chat messages. This slideshow will explore various machine learning techniques for analyzing short texts using Python.
import nltk
from nltk.tokenize import word_tokenize
text = "NLP is fascinating!"
tokens = word_tokenize(text)
print(f"Tokenized text: {tokens}")
# Output: Tokenized text: ['NLP', 'is', 'fascinating', '!']
Text Preprocessing
Text preprocessing is a crucial step in NLP that involves cleaning and transforming raw text data into a format suitable for analysis. Common preprocessing tasks include tokenization, lowercasing, removing punctuation, and eliminating stop words.
import re
from nltk.corpus import stopwords
def preprocess_text(text):
# Lowercase the text
text = text.lower()
# Remove punctuation
text = re.sub(r'[^\w\s]', '', text)
# Tokenize
tokens = word_tokenize(text)
# Remove stop words
stop_words = set(stopwords.words('english'))
tokens = [token for token in tokens if token not in stop_words]
return tokens
sample_text = "The quick brown fox jumps over the lazy dog!"
processed_tokens = preprocess_text(sample_text)
print(f"Processed tokens: {processed_tokens}")
# Output: Processed tokens: ['quick', 'brown', 'fox', 'jumps', 'lazy', 'dog']
Feature Extraction: Bag of Words
The Bag of Words (BoW) model is a simple yet effective technique for representing text data as numerical features. It creates a vocabulary of unique words and represents each document as a vector of word frequencies.
from sklearn.feature_extraction.text import CountVectorizer
corpus = [
"I love machine learning",
"I love Python programming",
"NLP is a subset of AI"
]
vectorizer = CountVectorizer()
X = vectorizer.fit_transform(corpus)
print("Vocabulary:", vectorizer.get_feature_names_out())
print("BoW matrix:\n", X.toarray())
# Output:
# Vocabulary: ['ai' 'is' 'learning' 'love' 'machine' 'nlp' 'of' 'programming' 'python' 'subset']
# BoW matrix:
# [[0 0 1 1 1 0 0 0 0 0]
# [0 0 0 1 0 0 0 1 1 0]
# [1 1 0 0 0 1 1 0 0 1]]
Feature Extraction: TF-IDF
Term Frequency-Inverse Document Frequency (TF-IDF) is an advanced feature extraction technique that considers both the frequency of a word in a document and its importance across the entire corpus. It helps to identify more meaningful words in a text.
from sklearn.feature_extraction.text import TfidfVectorizer
corpus = [
"The cat sat on the mat",
"The dog ate my homework",
"The cat and the dog are pets"
]
vectorizer = TfidfVectorizer()
X = vectorizer.fit_transform(corpus)
print("Vocabulary:", vectorizer.get_feature_names_out())
print("TF-IDF matrix:\n", X.toarray())
# Output:
# Vocabulary: ['and' 'are' 'ate' 'cat' 'dog' 'homework' 'mat' 'my' 'on' 'pets' 'sat' 'the']
# TF-IDF matrix:
# [[0. 0. 0. 0.468 0. 0. 0.468 0. 0.468 0. 0.468 0.354]
# [0. 0. 0.479 0. 0.378 0.479 0. 0.479 0. 0. 0. 0.378]
# [0.377 0.377 0. 0.298 0.298 0. 0. 0. 0. 0.377 0. 0.594]]
Text Classification: Naive Bayes
Naive Bayes is a popular algorithm for text classification tasks. It's based on Bayes' theorem and assumes independence between features. Despite its simplicity, it often performs well on short text classification tasks.
from sklearn.naive_bayes import MultinomialNB
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.model_selection import train_test_split
# Sample data
texts = ["I love this movie", "This movie is terrible", "Great acting", "Poor storyline"]
labels = ["positive", "negative", "positive", "negative"]
# Vectorize the text
vectorizer = CountVectorizer()
X = vectorizer.fit_transform(texts)
# Split the data
X_train, X_test, y_train, y_test = train_test_split(X, labels, test_size=0.2, random_state=42)
# Train the model
clf = MultinomialNB()
clf.fit(X_train, y_train)
# Predict
new_text = ["This movie is awesome"]
new_X = vectorizer.transform(new_text)
prediction = clf.predict(new_X)
print(f"Prediction for '{new_text[0]}': {prediction[0]}")
# Output: Prediction for 'This movie is awesome': positive
Text Classification: Support Vector Machines (SVM)
Support Vector Machines (SVM) is another powerful algorithm for text classification. It works by finding the hyperplane that best separates different classes in a high-dimensional space.
from sklearn.svm import SVC
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
# Sample data
texts = [
"The food was delicious", "Terrible service", "Great atmosphere",
"Overpriced and disappointing", "Friendly staff", "Bland and uninspiring"
]
labels = ["positive", "negative", "positive", "negative", "positive", "negative"]
# Vectorize the text
vectorizer = TfidfVectorizer()
X = vectorizer.fit_transform(texts)
# Split the data
X_train, X_test, y_train, y_test = train_test_split(X, labels, test_size=0.3, random_state=42)
# Train the model
clf = SVC(kernel='linear')
clf.fit(X_train, y_train)
# Predict and evaluate
y_pred = clf.predict(X_test)
accuracy = accuracy_score(y_test, y_pred)
print(f"Accuracy: {accuracy:.2f}")
# Output: Accuracy: 1.00 (Note: This high accuracy is due to the small dataset)
Sentiment Analysis
Sentiment analysis is the process of determining the emotional tone behind a series of words, used to gain an understanding of attitudes, opinions, and emotions expressed in a text.
from textblob import TextBlob
def analyze_sentiment(text):
analysis = TextBlob(text)
if analysis.sentiment.polarity > 0:
return 'Positive'
elif analysis.sentiment.polarity == 0:
return 'Neutral'
else:
return 'Negative'
texts = [
"I absolutely love this product!",
"This is the worst experience ever.",
"The weather is nice today."
]
for text in texts:
sentiment = analyze_sentiment(text)
print(f"Text: '{text}'\nSentiment: {sentiment}\n")
# Output:
# Text: 'I absolutely love this product!'
# Sentiment: Positive
# Text: 'This is the worst experience ever.'
# Sentiment: Negative
# Text: 'The weather is nice today.'
# Sentiment: Positive
Named Entity Recognition (NER)
Named Entity Recognition is the task of identifying and classifying named entities (e.g., person names, organizations, locations) in text. It's crucial for extracting structured information from unstructured text.
import spacy
nlp = spacy.load("en_core_web_sm")
text = "Apple Inc. is planning to open a new store in New York City next month."
doc = nlp(text)
for ent in doc.ents:
print(f"Entity: {ent.text}, Label: {ent.label_}")
# Output:
# Entity: Apple Inc., Label: ORG
# Entity: New York City, Label: GPE
Topic Modeling: Latent Dirichlet Allocation (LDA)
Topic modeling is a technique used to discover abstract topics in a collection of documents. Latent Dirichlet Allocation (LDA) is a popular algorithm for topic modeling.
from gensim import corpora
from gensim.models import LdaModel
from gensim.parsing.preprocessing import STOPWORDS
from gensim.utils import simple_preprocess
texts = [
"The cat and the dog",
"The dog ate the food",
"The cat slept on the mat",
"The dog chased the cat"
]
# Preprocess the texts
processed_texts = [[word for word in simple_preprocess(doc) if word not in STOPWORDS] for doc in texts]
# Create a dictionary and corpus
dictionary = corpora.Dictionary(processed_texts)
corpus = [dictionary.doc2bow(text) for text in processed_texts]
# Train the LDA model
lda_model = LdaModel(corpus=corpus, id2word=dictionary, num_topics=2, random_state=42)
# Print the topics
for idx, topic in lda_model.print_topics(-1):
print(f"Topic {idx}: {topic}")
# Output:
# Topic 0: 0.318*"dog" + 0.318*"cat" + 0.159*"the" + 0.159*"chased" + 0.045*"slept"
# Topic 1: 0.272*"the" + 0.182*"cat" + 0.182*"dog" + 0.091*"food" + 0.091*"ate"
Word Embeddings: Word2Vec
Word embeddings are dense vector representations of words that capture semantic relationships. Word2Vec is a popular algorithm for creating word embeddings.
from gensim.models import Word2Vec
sentences = [
['I', 'love', 'machine', 'learning'],
['I', 'love', 'deep', 'learning'],
['NLP', 'is', 'fascinating']
]
model = Word2Vec(sentences, vector_size=100, window=5, min_count=1, workers=4)
# Find similar words
similar_words = model.wv.most_similar('learning', topn=3)
print("Words similar to 'learning':")
for word, score in similar_words:
print(f"{word}: {score:.2f}")
# Perform word arithmetic
result = model.wv.most_similar(positive=['deep', 'learning'], negative=['machine'], topn=1)
print(f"\ndeep + learning - machine = {result[0][0]}")
# Output:
# Words similar to 'learning':
# machine: 0.99
# deep: 0.97
# love: 0.20
# deep + learning - machine = fascinating
Text Summarization: Extractive Method
Text summarization is the process of creating a concise and coherent version of a longer text. Extractive summarization selects important sentences from the original text to form a summary.
import nltk
from nltk.corpus import stopwords
from nltk.tokenize import sent_tokenize, word_tokenize
from nltk.probability import FreqDist
def extractive_summarize(text, num_sentences=3):
# Tokenize the text into sentences and words
sentences = sent_tokenize(text)
words = word_tokenize(text.lower())
# Remove stopwords
stop_words = set(stopwords.words('english'))
words = [word for word in words if word not in stop_words]
# Calculate word frequencies
freq = FreqDist(words)
# Score sentences based on word frequencies
sentence_scores = {}
for sentence in sentences:
for word in word_tokenize(sentence.lower()):
if word in freq:
if sentence not in sentence_scores:
sentence_scores[sentence] = freq[word]
else:
sentence_scores[sentence] += freq[word]
# Get the top n sentences
summary_sentences = sorted(sentence_scores, key=sentence_scores.get, reverse=True)[:num_sentences]
# Join the top sentences
summary = ' '.join(summary_sentences)
return summary
text = """
Natural language processing (NLP) is a subfield of linguistics, computer science, and artificial intelligence concerned with the interactions between computers and human language, in particular how to program computers to process and analyze large amounts of natural language data. The goal is a computer capable of understanding the contents of documents, including the contextual nuances of the language within them. The technology can then accurately extract information and insights contained in the documents as well as categorize and organize the documents themselves.
"""
summary = extractive_summarize(text)
print("Summary:")
print(summary)
# Output:
# Summary:
# Natural language processing (NLP) is a subfield of linguistics, computer science, and artificial intelligence concerned with the interactions between computers and human language, in particular how to program computers to process and analyze large amounts of natural language data. The goal is a computer capable of understanding the contents of documents, including the contextual nuances of the language within them. The technology can then accurately extract information and insights contained in the documents as well as categorize and organize the documents themselves.
Text Generation: Markov Chain
Markov Chains can be used for simple text generation tasks. This technique generates new text based on the statistical properties of the input text.
import random
def build_markov_chain(text, n=2):
words = text.split()
chain = {}
for i in range(len(words) - n):
state = tuple(words[i:i+n])
next_word = words[i+n]
if state not in chain:
chain[state] = {}
if next_word not in chain[state]:
chain[state][next_word] = 0
chain[state][next_word] += 1
return chain
def generate_text(chain, num_words=50, start=None):
if start is None:
current = random.choice(list(chain.keys()))
else:
current = start
result = list(current)
for _ in range(num_words - len(current)):
if current in chain:
next_word = random.choices(list(chain[current].keys()),
weights=list(chain[current].values()))[0]
result.append(next_word)
current = tuple(result[-len(current):])
else:
break
return ' '.join(result)
text = """
The quick brown fox jumps over the lazy dog.
The lazy dog sleeps all day.
The quick brown fox is very clever.
"""
chain = build_markov_chain(text)
generated_text = generate_text(chain, num_words=20)
print("Generated text:")
print(generated_text)
# Output:
# Generated text:
# The quick brown fox jumps over the lazy dog sleeps all day. The quick brown fox is very clever. The lazy dog
Real-Life Example: Spam Detection
Spam detection is a common application of short text analysis in email filtering systems. Here's a simple example using a Naive Bayes classifier:
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.naive_bayes import MultinomialNB
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report
# Sample data (email subjects)
subjects = [
"Win a free iPhone now!", "Meeting agenda for tomorrow",
"Discount on luxury watches", "Project deadline reminder",
"You've won the lottery!", "Weekly team sync",
"Enlarge your profits now", "Quarterly report available"
]
labels = [1, 0, 1, 0, 1, 0, 1, 0] # 1 for spam, 0 for non-spam
# Vectorize the text
vectorizer = CountVectorizer()
X = vectorizer.fit_transform(subjects)
# Split the data
X_train, X_test, y_train, y_test = train_test_split(X, labels, test_size=0.25, random_state=42)
# Train the model
clf = MultinomialNB()
clf.fit(X_train, y_train)
# Predict and evaluate
y_pred = clf.predict(X_test)
print(classification_report(y_test, y_pred))
# Test with new emails
new_emails = ["Free gift awaits you!", "Team lunch next week"]
new_X = vectorizer.transform(new_emails)
predictions = clf.predict(new_X)
for email, pred in zip(new_emails, predictions):
print(f"'{email}' - {'Spam' if pred == 1 else 'Not Spam'}")
# Output:
# precision recall f1-score support
# 0 1.00 1.00 1.00 1
# 1 1.00 1.00 1.00 1
# accuracy 1.00 2
# macro avg 1.00 1.00 1.00 2
# weighted avg 1.00 1.00 1.00 2
# 'Free gift awaits you!' - Spam
# 'Team lunch next week' - Not Spam
Real-Life Example: Customer Feedback Analysis
Analyzing customer feedback is crucial for businesses to improve their products or services. Here's an example of sentiment analysis on product reviews:
import pandas as pd
from textblob import TextBlob
# Sample customer reviews
reviews = [
"This product is amazing! It works perfectly.",
"Terrible customer service. Never buying again.",
"Average product, nothing special.",
"Great value for the price. Highly recommended!",
"Disappointing quality. Broke after a week."
]
# Perform sentiment analysis
sentiments = []
for review in reviews:
blob = TextBlob(review)
sentiment = blob.sentiment.polarity
if sentiment > 0:
sentiments.append("Positive")
elif sentiment < 0:
sentiments.append("Negative")
else:
sentiments.append("Neutral")
# Create a DataFrame
df = pd.DataFrame({"Review": reviews, "Sentiment": sentiments})
# Display results
print(df)
# Calculate sentiment distribution
sentiment_counts = df["Sentiment"].value_counts()
print("\nSentiment Distribution:")
print(sentiment_counts)
# Output:
# Review Sentiment
# 0 This product is amazing! It works perfectly. Positive
# 1 Terrible customer service. Never buying again. Negative
# 2 Average product, nothing special. Neutral
# 3 Great value for the price. Highly recommended! Positive
# 4 Disappointing quality. Broke after a week. Negative
# Sentiment Distribution:
# Positive 2
# Negative 2
# Neutral 1
# Name: Sentiment, dtype: int64
Additional Resources
For those interested in diving deeper into NLP and short text analysis, here are some valuable resources:
- "Natural Language Processing with Python" by Steven Bird, Ewan Klein, and Edward Loper
- A comprehensive introduction to NLP using the NLTK library
- "Speech and Language Processing" by Dan Jurafsky and James H. Martin
- An in-depth textbook covering various aspects of NLP
- ArXiv papers:
- "BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding" by Devlin et al. (https://arxiv.org/abs/1810.04805)
- "Attention Is All You Need" by Vaswani et al. (https://arxiv.org/abs/1706.03762)
- Online courses:
- Stanford's CS224N: Natural Language Processing with Deep Learning
- Coursera's Natural Language Processing Specialization by deeplearning.ai
These resources provide a solid foundation for further exploration of NLP techniques and applications in short text analysis.