Quiz 2
Registry Synced

Text Analysis of Social Media Data

2266 words
11 min read

Reading compass

Now · 🎯 Learning Objectives

Text Analysis of Social Media Data

🎯 Learning Objectives

  • Preprocess social media text (tokenization, stemming, stop word removal)
  • Perform sentiment analysis using lexicon-based and ML approaches
  • Compute TF-IDF vectors for document comparison
  • Apply topic modeling (LDA) to discover themes
  • Use word embeddings for semantic analysis

1. Text Preprocessing

1.1 Intuition

Social media text is messy — it's full of hashtags, @mentions, URLs, emojis, slang, and typos. You can't analyze this raw text directly. Preprocessing is like cleaning ingredients before cooking: you remove the parts you don't need and standardize what remains so the analysis is consistent.

1.2 Preprocessing Pipeline

(Diagram)

1.3 Step-by-Step Example

Raw tweet:
pseudo
RT @ml_expert: Machine Learning is AMAZING!!! 🚀 Check out our new paper at https://example.com #AI #MachineLearning
StepOperationResult
1Lowercasert @ml_expert: machine learning is amazing!!! 🚀 check out our new paper at https://example.com #ai #machinelearning
2Remove URLsrt @ml_expert: machine learning is amazing!!! 🚀 check out our new paper at #ai #machinelearning
3Remove @mentionsrt: machine learning is amazing!!! 🚀 check out our new paper at #ai #machinelearning
4Tokenize['rt', ':', 'machine', 'learning', 'is', 'amazing', '!', '🚀', 'check', 'out', 'our', 'new', 'paper', 'at', '#ai', '#machinelearning']
5Remove stop words['machine', 'learning', 'amazing', '🚀', 'check', 'new', 'paper', '#ai', '#machinelearning']
6Stemming['machin', 'learn', 'amaz', '🚀', 'check', 'new', 'paper', '#ai', '#machinelearn']

1.4 Python Implementation

python
import re
import nltk
from nltk.tokenize import word_tokenize
from nltk.corpus import stopwords
from nltk.stem import PorterStemmer
nltk.download('punkt')
nltk.download('stopwords')
def preprocess_tweet(text):
    """Clean and preprocess a single tweet."""
    # Lowercase
    text = text.lower()
    # Remove URLs
    text = re.sub(r'http\S+|www\S+|https\S+', '', text)
    # Remove @mentions
    text = re.sub(r'@\w+', '', text)
    # Keep hashtags but remove # symbol
    text = re.sub(r'#(\w+)', r'\1', text)
    # Remove special chars (keep letters, numbers, spaces)
    text = re.sub(r'[^a-zA-Z0-9\s]', '', text)
    # Tokenize
    tokens = word_tokenize(text)
    # Remove stop words
    stop_words = set(stopwords.words('english'))
    tokens = [t for t in tokens if t not in stop_words]
    # Stem
    stemmer = PorterStemmer()
    tokens = [stemmer.stem(t) for t in tokens]
    return tokens
# Example
tweet = "RT @ml_expert: Machine Learning is AMAZING!!! Check out https://example.com #AI"
print(preprocess_tweet(tweet))
# Output: ['machin', 'learn', 'amaz', 'check', 'ai']

2. Sentiment Analysis

2.1 Intuition

Sentiment analysis determines whether a piece of text expresses positive, negative, or neutral emotion. Think of it as teaching a computer to read between the lines — is that tweet praising or criticizing? This is crucial for understanding public opinion on products, policies, or events.

2.2 Lexicon-Based Approach

Uses a dictionary of words with pre-assigned sentiment scores.
WordSentiment Score
amazing+0.8
terrible-0.9
good+0.4
bad-0.6
love+0.7
hate-0.8
Algorithm:
S(tweet)=wtweetscore(w)S(tweet) = \sum_{w \in tweet} score(w)

2.3 Worked Example: VADER Sentiment

VADER (Valence Aware Dictionary and sEntiment Reasoner) is designed for social media text.
python
from nltk.sentiment import SentimentIntensityAnalyzer
nltk.download('vader_lexicon')
sia = SentimentIntensityAnalyzer()
tweets = [
    "I love this new AI feature! It's amazing! 🎉",
    "This update is terrible. Worst experience ever.",
    "The meeting is at 3pm tomorrow.",
    "The product is okay, nothing special."
]
for tweet in tweets:
    scores = sia.polarity_scores(tweet)
    print(f"Tweet: {tweet[:40]}...")
    print(f"  Scores: {scores}")
    print(f"  Overall: {'Positive' if scores['compound'] > 0.05 else 'Negative' if scores['compound'] < -0.05 else 'Neutral'}")
Tracing Table of VADER scores:
TweetnegneuposcompoundSentiment
"I love this new AI feature! It's amazing!"0.00.420.580.89Positive
"This update is terrible. Worst experience ever."0.670.330.0-0.93Negative
"The meeting is at 3pm tomorrow."0.01.00.00.0Neutral
"The product is okay, nothing special."0.00.730.27-0.14Neutral

2.4 ML-Based Sentiment

Using a classifier trained on labeled data:
python
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.naive_bayes import MultinomialNB
# Training data (labeled tweets)
train_texts = [
    "This product is amazing",
    "I love using this app",
    "Terrible customer service",
    "Worst purchase ever",
]
train_labels = [1, 1, 0, 0]  # 1 = positive, 0 = negative
# Convert text to features
vectorizer = TfidfVectorizer()
X_train = vectorizer.fit_transform(train_texts)
# Train classifier
clf = MultinomialNB()
clf.fit(X_train, train_labels)
# Predict new tweet
new_tweet = ["This app is fantastic!"]
X_new = vectorizer.transform(new_tweet)
prediction = clf.predict(X_new)
print(f"Prediction: {'Positive' if prediction[0] == 1 else 'Negative'}")

3. TF-IDF Vectorization

3.1 Intuition

TF-IDF answers the question: "Which words are important in this document compared to all documents?" A word is important if it appears frequently in this document (TF) but rarely across all documents (IDF). For example, "the" appears everywhere — low importance. "Blockchain" in a finance article — high importance.

3.2 Formula

Term Frequency (TF):
TF(t,d)=count of term t in document dtotal terms in document dTF(t, d) = \frac{\text{count of term } t \text{ in document } d}{\text{total terms in document } d}
Inverse Document Frequency (IDF):
IDF(t)=log(Nnumber of documents containing t)IDF(t) = \log\left(\frac{N}{\text{number of documents containing } t}\right)
TF-IDF:
TF-IDF(t,d)=TF(t,d)×IDF(t)TF\text{-}IDF(t, d) = TF(t, d) \times IDF(t)

3.3 Worked Example

Documents:
DocText
D1"AI is transforming healthcare"
D2"Machine learning AI is powerful"
D3"Healthcare needs more funding"
Tracing Table — Computing TF-IDF:
TermTF(D1)TF(D2)TF(D3)DFIDFTF-IDF(D1)TF-IDF(D2)TF-IDF(D3)
ai1/41/402log(3/2)=0.1760.0440.0440
transforming1/4001log(3/1)=0.4770.11900
healthcare1/401/42log(3/2)=0.1760.04400.044
machine01/4010.47700.1190
learning01/4010.47700.1190
powerful01/4010.47700.1190
needs001/410.477000.119
funding001/410.477000.119
Key insight: D1's most important term is "transforming" (unique to D1). D2's important terms are "machine", "learning", "powerful" (unique to D2). Common terms like "AI" and "healthcare" get lower scores.

4. Topic Modeling with LDA

4.1 Intuition

Topic modeling automatically discovers the themes running through a collection of documents. It's like sorting a pile of mixed LEGO bricks into groups — the "space" group, the "castle" group, the "city" group. LDA (Latent Dirichlet Allocation) assumes each document is a mixture of topics, and each topic is a mixture of words.

4.2 How LDA Works

(Diagram)

4.3 Python Example

python
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.decomposition import LatentDirichletAllocation
# Sample tweets
tweets = [
    "Just bought Bitcoin and Ethereum crypto investment",
    "Election results show voter turnout increase",
    "Bitcoin price drops after regulation news",
    "New healthcare bill passes Congress debate",
    "My crypto portfolio is up 50% this month",
    "Voting machines need better security measures"
]
# Vectorize
vectorizer = CountVectorizer(max_features=100, stop_words='english')
X = vectorizer.fit_transform(tweets)
# Run LDA with 2 topics
lda = LatentDirichletAllocation(n_components=2, random_state=42)
lda.fit(X)
# Display topics
feature_names = vectorizer.get_feature_names_out()
for topic_idx, topic in enumerate(lda.components_):
    top_words = [feature_names[i] for i in topic.argsort()[:-6:-1]]
    print(f"Topic {topic_idx}: {', '.join(top_words)}")
Output:
pseudo
Topic 0: bitcoin, crypto, ethereum, price, investment
Topic 1: election, voting, healthcare, bill, congress
Tracing Table — Tweet-Topic Distribution:
TweetTopic 0 (Crypto)Topic 1 (Politics)Assigned Topic
"Bitcoin and Ethereum crypto"0.950.05Crypto
"Election results voter turnout"0.020.98Politics
"Bitcoin price drops regulation"0.880.12Crypto
"Healthcare bill Congress"0.010.99Politics
"Crypto portfolio up 50%"0.970.03Crypto
"Voting machines security"0.150.85Politics

5. Word Embeddings

5.1 Intuition

Word embeddings represent words as vectors in a continuous space where similar words are close together. Unlike TF-IDF (sparse, high-dimensional), embeddings are dense (typically 100-300 dimensions). The classic example: vector("king") - vector("man") + vector("woman") ≈ vector("queen").

5.2 Using Pre-trained Embeddings

python
import gensim.downloader as api
# Load pre-trained GloVe embeddings (trained on Twitter data!)
# This is a 200MB download
glove = api.load("glove-twitter-25")
# Find similar words
similar = glove.most_similar("ai", topn=5)
for word, score in similar:
    print(f"{word}: {score:.3f}")
Output:
pseudo
machine: 0.85
intelligence: 0.82
deep: 0.76
learning: 0.74
data: 0.71

5.3 Visualizing Embeddings with PCA

python
import numpy as np
from sklearn.decomposition import PCA
import matplotlib.pyplot as plt
# Get vectors for some words
words = ['king', 'queen', 'man', 'woman', 'prince', 'princess',
         'computer', 'science', 'programming', 'data']
vectors = np.array([glove[w] for w in words])
# Reduce to 2D
pca = PCA(n_components=2)
vectors_2d = pca.fit_transform(vectors)
# Plot
plt.figure(figsize=(10, 8))
for i, word in enumerate(words):
    plt.scatter(vectors_2d[i, 0], vectors_2d[i, 1])
    plt.annotate(word, (vectors_2d[i, 0], vectors_2d[i, 1]))
plt.title("Word Embeddings Visualization")
plt.show()

6. Common Pitfalls

Pitfall 1: Removing All Punctuation (Including Hashtags)

The mistake: Stripping # and converting #AI to ai, losing the information that this was a hashtag. Why students make it: Standard NLP tutorials remove punctuation as a first step. How to catch it: Check if your analysis benefits from knowing which terms were hashtagged. Hashtags often signal topic relevance. Correct approach: Keep the # symbol or create a separate feature flag for hashtagged terms.

Pitfall 2: Using Stop Words Lists Meant for Formal Text

The mistake: Using standard NLTK stop words on social media, removing words like "u", "im", "dont" that are meaningful contractions. Why students make it: Default stop word lists are designed for formal English (newspapers, books). How to catch it: Check if your stop words list includes social media common terms that carry meaning. Correct approach: Create a custom stop words list that only removes truly non-informative terms.

Pitfall 3: Ignoring Emojis and Emoticons

The mistake: Removing all emojis as "noise" before analysis. Why students make it: Emojis look like random Unicode characters that break tokenization. How to catch it: Notice that sentiment analysis performs worse on emoji-heavy text. 😊 signals positive sentiment! Correct approach: Convert emojis to sentiment-bearing text using libraries like emoji or map them to sentiment scores.
python
import emoji
def demojize(text):
    return emoji.demojize(text)
tweet = "I love this! 😊🎉"
print(demojize(tweet))
# Output: I love this! :smiling_face_with_smiling_eyes: :party_popper:

7. Key Concepts Reference

ConceptDefinitionApplication
TokenizationSplitting text into individual tokensFirst preprocessing step
StemmingReducing words to root form (running→run)Vocabulary reduction
LemmatizationDictionary-based root finding (better→good)More accurate than stemming
Stop WordsCommon words removed before analysisReduces noise
TF-IDFTerm frequency × inverse document frequencyFeature extraction
Sentiment AnalysisDetermining emotional toneOpinion mining
LDALatent Dirichlet Allocation topic modelTheme discovery
Word EmbeddingsDense vector representationsSemantic similarity

8. 📝 Practice Questions

Q1: Tokenize and preprocess: "I CAN'T BELIEVE this!!! Check out http://bit.ly/abc #excited"
Answer: Step 1: Lowercase → "i can't believe this!!! check out http://bit.ly/abc #excited" Step 2: Remove URL → "i can't believe this!!! check out #excited" Step 3: Remove punctuation → "i cant believe this check out excited" Step 4: Tokenize → ['i', 'cant', 'believe', 'this', 'check', 'out', 'excited'] Step 5: Remove stop words → ['cant', 'believe', 'check', 'excited'] Step 6: Stem → ['cant', 'believ', 'check', 'excit'] Q2: Using VADER, a tweet scores compound = 0.0. What does this mean?
Answer: A compound score of 0.0 means the text is either perfectly neutral (equal positive and negative language) or contains no sentiment-bearing words at all. For example, "The meeting starts at 3pm" would score near 0.0. Compound scores between -0.05 and +0.05 are typically classified as neutral. Q3: A term appears in 5 out of 100 documents. What is its IDF?
Answer: IDF = log(N/df) = log(100/5) = log(20) = 2.996 (using base e) Or using base 10: log10(20) = 1.301 Or using base 2: log2(20) = 4.322 Most implementations use natural log or base 10. The exact value depends on the implementation, but the key point is that rare terms get higher IDF scores. Q4: Explain why TF-IDF is better than raw word counts for document comparison.
Answer: Raw word counts favor frequent words (like "the", "and", "is") regardless of their importance. TF-IDF downweights common words (high document frequency → low IDF) and upweights rare words that distinguish documents. For example, "blockchain" in a finance document would get high TF-IDF, while "the" would get near-zero. This makes TF-IDF much better at capturing document similarity based on meaningful content rather than function words. Q5: With K=3 topics in LDA, a tweet has topic distribution [0.7, 0.2, 0.1]. Interpret this.
Answer: The tweet is composed of approximately 70% Topic 1, 20% Topic 2, and 10% Topic 3. Since Topic 1 dominates, the tweet is most strongly associated with Topic 1. The mixture reflects how LDA models documents — they don't belong to a single topic but are mixtures of all topics. A threshold of 0.5 would classify this as Topic 1. Q6: Why might stemming reduce "universe" and "university" to similar roots?
Answer: The Porter stemmer reduces both to "univers" because it applies rules like removing common suffixes without considering meaning. This is a known limitation — words with different meanings but similar spelling get conflated. Lemmatization would handle this better by using dictionary lookups: "universe" → "universe", "university" → "university". Q7: In word embeddings, vector("Paris") - vector("France") + vector("Italy") ≈ ?
Answer: This should approximate vector("Rome"). The analogy is: Paris is to France as Rome is to Italy. The vector arithmetic computes: capital(Paris) - country(France) + country(Italy) = capital(Rome). This is the classic analogy-solving property of word embeddings — the vector space captures relational semantics. Q8: A sentiment classifier trained on movie reviews performs poorly on tweets. Why?
Answer: Domain mismatch: (1) Movie reviews are longer, more formal, and grammatically correct. Tweets are short, informal, full of slang/abbreviations. (2) Movie reviews use different vocabulary (plot, character, director vs. hashtags, @mentions, emojis). (3) Tweet sentiment is conveyed differently (caps, repeated punctuation, emojis). This is why domain-specific training data matters — a model trained on one domain doesn't transfer well. Q9: Calculate the TF for "crypto" in a 50-word tweet where "crypto" appears 3 times.
Answer: TF(crypto) = count of "crypto" / total terms = 3/50 = 0.06 This means 6% of the words in the tweet are "crypto" — a relatively high concentration indicating the tweet is likely about cryptocurrency. Q10: Why might you use word embeddings (like GloVe) instead of TF-IDF vectors?
Answer: (1) Embeddings capture semantic relationships (synonyms, analogies) while TF-IDF treats each word independently. (2) Embeddings are dense (300 dimensions) vs. TF-IDF being sparse (vocabulary-sized, often 10,000+). (3) Embeddings capture context — "bank" near "river" vs. "bank" near "money" would have different meanings, but TF-IDF treats them as the same term. (4) Embeddings are pre-trained on massive data and transfer well to new tasks.

9. 🔗 Cross-References

  • Week 2 - Data Collection: Raw data comes from APIs
  • Week 6 - Fake News: Text analysis for misinformation detection
  • Week 8 - Privacy: Text anonymization techniques
  • BSCS3031 (CSD): Sentiment analysis applications Join Discord PreviousData CollectionNextWeb Tracking
Document outline

Keep your place and jump directly to a heading.

Table of Contents
System Normal // Awaiting Context

Intelligence Hub

Navigate the knowledge graph to generate context. The Hub adapts dynamically to surface backlinks, related notes, and metadata insights.