NLP/NLU Specialization Notes
  • Natural Language Processing/Understanding Notes, Resources
  • Natural Language Processing With Attention Models
    • NLP With Attention Models
  • Natural Language Processing With Attention Models Notebooks
    • Assignment 1: Neural Machine Translation
    • Basic Attention Operation: Ungraded Lab
    • Calculating the Bilingual Evaluation Understudy (BLEU) score: Ungraded Lab
    • Scaled Dot-Product Attention: Ungraded Lab
    • Assignment 2: Transformer Summarizer
    • The Three Ways of Attention and Dot Product Attention: Ungraded Lab Notebook
    • Masking
    • Positional Encoding
    • Assignment 3: Question Answering
    • Assignment 3: Question Answering
    • Question Answering with BERT and HuggingFace
    • Question Answering with BERT and HuggingFace 🤗 (Fine-tuning)
    • SentencePiece and BPE
  • Natural Language Processing With Classification And Vector Spaces
    • NLP With Classification and Vector Spaces
  • Natural Language Processing With Sequence Models
    • NLP With Sequence Models
  • Natural Language Processing with Classification and Vector Spaces Notebooks
    • Assignment 1: Logistic Regression
    • Preprocessing
    • Building and Visualizing word frequencies
    • Visualizing tweets and the Logistic Regression model
    • Assignment 2: Naive Bayes
    • Assignment 3: Hello Vectors
    • Linear algebra in Python with NumPy
    • Manipulating word embeddings
    • Another explanation about PCA
    • Assignment 4 - Naive Machine Translation and LSH
    • Vector manipulation in Python
    • Hash functions and multiplanes
  • Natural Language Processing with Probabilistic Models
    • NLP With Probabilistic Models
  • Natural Language Processing with Probabilistic Models Notebooks
    • Assignment 1: Autocorrect
    • NLP Course 2 Week 1 Lesson : Building The Model - Lecture Exercise 01
    • NLP Course 2 Week 1 Lesson : Building The Model - Lecture Exercise 02
    • Assignment 2: Parts-of-Speech Tagging (POS)
    • Parts-of-Speech Tagging - First Steps: Working with text files, Creating a Vocabulary and Handling Unknown Words
    • Parts-of-Speech Tagging - Working with tags and Numpy
    • Assignment 3: Language Models: Auto-Complete
    • N-grams Corpus preprocessing
    • Building the language model
    • Out of vocabulary words (OOV)
    • Assignment 4: Word Embeddings
    • Word Embeddings First Steps: Data Preparation
    • Word Embeddings: Intro to CBOW model, activation functions and working with Numpy
    • Word Embeddings: Training the CBOW model
    • Word Embeddings: Hands On
    • Word Embeddings: Ungraded Practice Notebook
  • Natural Language Processing with Sequence Models Notebooks
    • Assignment 1: Deep N-grams
    • Hidden State Activation : Ungraded Lecture Notebook
    • Assignment 1: Sentiment with Deep Neural Networks
    • Vanilla RNNs and GRUs
    • Lab 1: TensorFlow Tutorial and Some Useful Functions
    • Calculating perplexity using numpy: Ungraded Lecture Notebook
    • Assignment 2 - Named Entity Recognition (NER)
    • Vanishing Gradients and Exploding Gradients in RNNs : Ungraded Lecture Notebook
    • Evaluate a Siamese model: Ungraded Lecture Notebook
    • Assignment 3: Question duplicates
    • Modified Triplet Loss : Ungraded Lecture Notebook
    • Creating a Siamese model: Ungraded Lecture Notebook
  • Stanford
    • Stanford CS 224U,224N
  • Udacity
    • NLP Nanodegree
  • Previous
  • Next
  • Visualizing tweets and the Logistic Regression model
    • Import the required libraries
    • Load the NLTK sample dataset
  • Load the extracted features
    • Load a pretrained Logistic Regression model
    • Plot the samples in a scatter plot
    • Plot the model alongside the data

Visualizing tweets and the Logistic Regression model¶

Objectives: Visualize and interpret the logistic regression model

Steps:

  • Plot tweets in a scatter plot using their positive and negative sums.
  • Plot the output of the logistic regression model in the same plot as a solid line

Import the required libraries¶

We will be using NLTK, an opensource NLP library, for collecting, handling, and processing Twitter data. In this lab, we will use the example dataset that comes alongside with NLTK. This dataset has been manually annotated and serves to establish baselines for models quickly.

So, to start, let's import the required libraries.

In [1]:
Copied!
import nltk                         # NLP toolbox
from os import getcwd
import pandas as pd                 # Library for Dataframes 
from nltk.corpus import twitter_samples 
import matplotlib.pyplot as plt     # Library for visualization
import numpy as np                  # Library for math functions

from utils import process_tweet, build_freqs # Our functions for NLP

nltk.download('twitter_samples')
import nltk # NLP toolbox from os import getcwd import pandas as pd # Library for Dataframes from nltk.corpus import twitter_samples import matplotlib.pyplot as plt # Library for visualization import numpy as np # Library for math functions from utils import process_tweet, build_freqs # Our functions for NLP nltk.download('twitter_samples')
[nltk_data] Downloading package twitter_samples to
[nltk_data]     /home/jovyan/nltk_data...
[nltk_data]   Package twitter_samples is already up-to-date!
Out[1]:
True

Load the NLTK sample dataset¶

To complete this lab, you need the sample dataset of the previous lab. Here, we assume the files are already available, and we only need to load into Python lists.

In [2]:
Copied!
# select the set of positive and negative tweets
all_positive_tweets = twitter_samples.strings('positive_tweets.json')
all_negative_tweets = twitter_samples.strings('negative_tweets.json')

tweets = all_positive_tweets + all_negative_tweets ## Concatenate the lists. 
labels = np.append(np.ones((len(all_positive_tweets),1)), np.zeros((len(all_negative_tweets),1)), axis = 0)

# split the data into two pieces, one for training and one for testing (validation set) 
train_pos  = all_positive_tweets[:4000]
train_neg  = all_negative_tweets[:4000]

train_x = train_pos + train_neg 

print("Number of tweets: ", len(train_x))
# select the set of positive and negative tweets all_positive_tweets = twitter_samples.strings('positive_tweets.json') all_negative_tweets = twitter_samples.strings('negative_tweets.json') tweets = all_positive_tweets + all_negative_tweets ## Concatenate the lists. labels = np.append(np.ones((len(all_positive_tweets),1)), np.zeros((len(all_negative_tweets),1)), axis = 0) # split the data into two pieces, one for training and one for testing (validation set) train_pos = all_positive_tweets[:4000] train_neg = all_negative_tweets[:4000] train_x = train_pos + train_neg print("Number of tweets: ", len(train_x))
Number of tweets:  8000

Load the extracted features¶

Part of this week's assignment is the creation of the numerical features needed for the Logistic regression model. In order not to interfere with it, we have previously calculated and stored these features in a CSV file for the entire training set.

So, please load these features created for the tweets sample.

In [3]:
Copied!
data = pd.read_csv('./data/logistic_features.csv'); # Load a 3 columns csv file using pandas function
data.head(10) # Print the first 10 data entries
data = pd.read_csv('./data/logistic_features.csv'); # Load a 3 columns csv file using pandas function data.head(10) # Print the first 10 data entries
Out[3]:
bias positive negative sentiment
0 1.0 3020.0 61.0 1.0
1 1.0 3573.0 444.0 1.0
2 1.0 3005.0 115.0 1.0
3 1.0 2862.0 4.0 1.0
4 1.0 3119.0 225.0 1.0
5 1.0 2955.0 119.0 1.0
6 1.0 3934.0 538.0 1.0
7 1.0 3162.0 276.0 1.0
8 1.0 628.0 189.0 1.0
9 1.0 264.0 112.0 1.0

Now let us get rid of the data frame to keep only Numpy arrays.

In [ ]:
Copied!
# Each feature is labeled as bias, positive and negative
X = data[['bias', 'positive', 'negative']].values # Get only the numerical values of the dataframe
Y = data['sentiment'].values; # Put in Y the corresponding labels or sentiments

print(X.shape) # Print the shape of the X part
print(X) # Print some rows of X
# Each feature is labeled as bias, positive and negative X = data[['bias', 'positive', 'negative']].values # Get only the numerical values of the dataframe Y = data['sentiment'].values; # Put in Y the corresponding labels or sentiments print(X.shape) # Print the shape of the X part print(X) # Print some rows of X

Load a pretrained Logistic Regression model¶

In the same way, as part of this week's assignment, a Logistic regression model must be trained. The next cell contains the resulting model from such training. Notice that a list of 3 numeric values represents the whole model, that we have called theta $\theta$.

In [ ]:
Copied!
theta = [6.03518871e-08, 5.38184972e-04, -5.58300168e-04]
theta = [6.03518871e-08, 5.38184972e-04, -5.58300168e-04]

Plot the samples in a scatter plot¶

The vector theta represents a plane that split our feature space into two parts. Samples located over that plane are considered positive, and samples located under that plane are considered negative. Remember that we have a 3D feature space, i.e., each tweet is represented as a vector comprised of three values: [bias, positive_sum, negative_sum], always having bias = 1.

If we ignore the bias term, we can plot each tweet in a cartesian plane, using positive_sum and negative_sum. In the cell below, we do precisely this. Additionally, we color each tweet, depending on its class. Positive tweets will be green and negative tweets will be red.

In [ ]:
Copied!
# Plot the samples using columns 1 and 2 of the matrix
fig, ax = plt.subplots(figsize = (8, 8))

colors = ['red', 'green']

# Color based on the sentiment Y
ax.scatter(X[:,1], X[:,2], c=[colors[int(k)] for k in Y], s = 0.1)  # Plot a dot for each pair of words
plt.xlabel("Positive")
plt.ylabel("Negative")
# Plot the samples using columns 1 and 2 of the matrix fig, ax = plt.subplots(figsize = (8, 8)) colors = ['red', 'green'] # Color based on the sentiment Y ax.scatter(X[:,1], X[:,2], c=[colors[int(k)] for k in Y], s = 0.1) # Plot a dot for each pair of words plt.xlabel("Positive") plt.ylabel("Negative")

From the plot, it is evident that the features that we have chosen to represent tweets as numerical vectors allow an almost perfect separation between positive and negative tweets. So you can expect a very high accuracy for this model!

Plot the model alongside the data¶

We will draw a gray line to show the cutoff between the positive and negative regions. In other words, the gray line marks the line where $$ z = \theta * x = 0.$$ To draw this line, we have to solve the above equation in terms of one of the independent variables.

$$ z = \theta * x = 0$$ $$ x = [1, pos, neg] $$ $$ z(\theta, x) = \theta_0+ \theta_1 * pos + \theta_2 * neg = 0 $$ $$ neg = (-\theta_0 - \theta_1 * pos) / \theta_2 $$

The red and green lines that point in the direction of the corresponding sentiment are calculated using a perpendicular line to the separation line calculated in the previous equations (neg function). It must point in the same direction as the derivative of the Logit function, but the magnitude may differ. It is only for a visual representation of the model.

$$direction = pos * \theta_2 / \theta_1$$

In [ ]:
Copied!
# Equation for the separation plane
# It give a value in the negative axe as a function of a positive value
# f(pos, neg, W) = w0 + w1 * pos + w2 * neg = 0
# s(pos, W) = (-w0 - w1 * pos) / w2
def neg(theta, pos):
    return (-theta[0] - pos * theta[1]) / theta[2]

# Equation for the direction of the sentiments change
# We don't care about the magnitude of the change. We are only interested 
# in the direction. So this direction is just a perpendicular function to the 
# separation plane
# df(pos, W) = pos * w2 / w1
def direction(theta, pos):
    return    pos * theta[2] / theta[1]
# Equation for the separation plane # It give a value in the negative axe as a function of a positive value # f(pos, neg, W) = w0 + w1 * pos + w2 * neg = 0 # s(pos, W) = (-w0 - w1 * pos) / w2 def neg(theta, pos): return (-theta[0] - pos * theta[1]) / theta[2] # Equation for the direction of the sentiments change # We don't care about the magnitude of the change. We are only interested # in the direction. So this direction is just a perpendicular function to the # separation plane # df(pos, W) = pos * w2 / w1 def direction(theta, pos): return pos * theta[2] / theta[1]

The green line in the chart points in the direction where z > 0 and the red line points in the direction where z < 0. The direction of these lines are given by the weights $\theta_1$ and $\theta_2$

In [ ]:
Copied!
# Plot the samples using columns 1 and 2 of the matrix
fig, ax = plt.subplots(figsize = (8, 8))

colors = ['red', 'green']

# Color base on the sentiment Y
ax.scatter(X[:,1], X[:,2], c=[colors[int(k)] for k in Y], s = 0.1)  # Plot a dot for each pair of words
plt.xlabel("Positive")
plt.ylabel("Negative")

# Now lets represent the logistic regression model in this chart. 
maxpos = np.max(X[:,1])

offset = 5000 # The pos value for the direction vectors origin

# Plot a gray line that divides the 2 areas.
ax.plot([0,  maxpos], [neg(theta, 0),   neg(theta, maxpos)], color = 'gray') 

# Plot a green line pointing to the positive direction
ax.arrow(offset, neg(theta, offset), offset, direction(theta, offset), head_width=500, head_length=500, fc='g', ec='g')
# Plot a red line pointing to the negative direction
ax.arrow(offset, neg(theta, offset), -offset, -direction(theta, offset), head_width=500, head_length=500, fc='r', ec='r')

plt.show()
# Plot the samples using columns 1 and 2 of the matrix fig, ax = plt.subplots(figsize = (8, 8)) colors = ['red', 'green'] # Color base on the sentiment Y ax.scatter(X[:,1], X[:,2], c=[colors[int(k)] for k in Y], s = 0.1) # Plot a dot for each pair of words plt.xlabel("Positive") plt.ylabel("Negative") # Now lets represent the logistic regression model in this chart. maxpos = np.max(X[:,1]) offset = 5000 # The pos value for the direction vectors origin # Plot a gray line that divides the 2 areas. ax.plot([0, maxpos], [neg(theta, 0), neg(theta, maxpos)], color = 'gray') # Plot a green line pointing to the positive direction ax.arrow(offset, neg(theta, offset), offset, direction(theta, offset), head_width=500, head_length=500, fc='g', ec='g') # Plot a red line pointing to the negative direction ax.arrow(offset, neg(theta, offset), -offset, -direction(theta, offset), head_width=500, head_length=500, fc='r', ec='r') plt.show()

Note that more critical than the Logistic regression itself, are the features extracted from tweets that allow getting the right results in this exercise.

That is all, folks. Hopefully, now you understand better what the Logistic regression model represents, and why it works that well for this specific problem.


Documentation built with MkDocs.

Keyboard Shortcuts

Keys Action
? Open this help
n Next page
p Previous page
s Search