Initial Steps

Downloading

import requests
from collections import Counter
url = "https://www.gutenberg.org/files/1342/1342-0.txt"

document = requests.get(url).text

Tokenizing

words = document.split()
print(words)

Activity 1

Try downloading and tokenizing a copy of another book from Project Gutenberg.

Save the results as my_document and my_words

Word Frequencies

counts = Counter(words)
counts.most_common(25)

Cleaning Data

# Use Regular Expressions to get rid of non-word characters
import re
cleaned = []

for word in words:
  clean_word = re.sub(r'[^a-zA-Z]', '', word)
  clean_word = clean_word.lower()
  cleaned.append(clean_word)
print(cleaned)
frequencies = Counter(cleaned)
frequencies.most_common(25)

Activity 2

Take a few minutes to find the top 10 most frequent words from your book (my_document).

What are they? Put a few of them in the chat.

Removing Stopwords

# Deal with stopwords
import nltk
from nltk.corpus import stopwords
nltk.download('stopwords')
# 'punkt' is for sentence tokenizing later
nltk.download('punkt')
stop_words = stopwords.words('english')
print(stop_words)
cleaned = []

for word in words:
  clean_word = re.sub(r'[^a-zA-Z]', '', word)
  clean_word = clean_word.lower()
  if clean_word not in stop_words:
    cleaned.append(clean_word)
frequencies = Counter(cleaned)
frequencies.most_common(25)

Adding our own stopwords

stop_words = stopwords.words('english')

my_stop_words = ['mr', 'could', 'would', 'may', 'might']

for word in my_stop_words:
  stop_words.append(word)
cleaned = []

for word in words:
  clean_word = re.sub(r'[^a-zA-Z]', '', word)
  clean_word = clean_word.lower()
  if clean_word not in stop_words:
    cleaned.append(clean_word)

frequencies = Counter(cleaned)
frequencies.most_common(25)

Activity 3

Add some custom stopwords to your own list.

What are they? What new words made it into your top 25 after this?

Saving Results

import pandas as pd
import seaborn as sns

# Writing to a file in colab requires mounting GDrive
from google.colab import drive
drive.mount('/content/gdrive')
word_col = []
count_col = []

for word, count in frequencies.most_common(25):
  word_col.append(word)
  count_col.append(count)

most_frequent = pd.DataFrame(list(zip(word_col, count_col)), columns = ['word', 'count'])
most_frequent
most_frequent.to_csv('/content/gdrive/MyDrive/most_frequent.csv')

Activity 4

Save your results to your own Google Drive.

# Making a basic visualization
sns.catplot(
    data = most_frequent,
    x = "word",
    y = "count",
    kind = "bar",
    aspect = 3
)

Sentiment Analysis

# install vaderSentiment to do sentiment analysis
# VADER (Valence Aware Dictionary and sEntiment Reasoner)
# -4 to 4 for each word
!pip install vaderSentiment
from vaderSentiment.vaderSentiment import SentimentIntensityAnalyzer

sa = SentimentIntensityAnalyzer()
# Preview the lexicon
sa.lexicon
# overall polarity scores are -1 to 1
my_negative_sentence = "I absolutely hate Victorian novels. They are the worst."

sa.polarity_scores(my_negative_sentence)
my_positive_sentence = "Victorian novels are fantastic. I completely adore them."

sa.polarity_scores(my_positive_sentence)

Activity 5

Write a very positive sentence and a very negative sentence.

Analyze their polarity scores with VADER.

compound = sa.polarity_scores(my_positive_sentence)['compound']
print(compound)
from nltk.tokenize import sent_tokenize
sentences = sent_tokenize(document)
sentences[0:10]
score = []
text = []


for sentence in sentences:
  text.append(sentence)
  score.append(sa.polarity_scores(sentence)['compound'])

scores = pd.DataFrame(list(zip(score, text)), columns = ['score', 'text'])
scores
scores.to_csv('/content/gdrive/MyDrive/scores.csv')
sns.relplot(
    data = scores,
    x = scores.index,
    y = 'score',
    kind = 'line',
    aspect = 4
)

Activity 6

Plot the polarity scores (sentence-by-sentence) of your book.

LS0tCnRpdGxlOiAiSW50cm9kdWN0aW9uIHRvIFRleHQgQW5hbHlzaXMiCm91dHB1dDoKICBodG1sX25vdGVib29rOgogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6IHRydWUKZWRpdG9yX29wdGlvbnM6IAogIGNodW5rX291dHB1dF90eXBlOiBpbmxpbmUKLS0tCgpgYGB7ciBlY2hvPUZBTFNFfQprbml0cjo6b3B0c19jaHVuayhldmFsPUZBTFNFKQpgYGAKCgojIEluaXRpYWwgU3RlcHMKIyMgRG93bmxvYWRpbmcKYGBge3B5dGhvbn0KaW1wb3J0IHJlcXVlc3RzCmZyb20gY29sbGVjdGlvbnMgaW1wb3J0IENvdW50ZXIKYGBgCgpgYGB7cHl0aG9ufQp1cmwgPSAiaHR0cHM6Ly93d3cuZ3V0ZW5iZXJnLm9yZy9maWxlcy8xMzQyLzEzNDItMC50eHQiCgpkb2N1bWVudCA9IHJlcXVlc3RzLmdldCh1cmwpLnRleHQKYGBgCgojIyBUb2tlbml6aW5nCmBgYHtweXRob259CndvcmRzID0gZG9jdW1lbnQuc3BsaXQoKQpgYGAKCmBgYHtweXRob259CnByaW50KHdvcmRzKQpgYGAKCgojIEFjdGl2aXR5IDEKClRyeSBkb3dubG9hZGluZyBhbmQgdG9rZW5pemluZyBhIGNvcHkgb2YgYW5vdGhlciBib29rIGZyb20gUHJvamVjdCBHdXRlbmJlcmcuCgpTYXZlIHRoZSByZXN1bHRzIGFzIG15X2RvY3VtZW50IGFuZCBteV93b3JkcwoKIyBXb3JkIEZyZXF1ZW5jaWVzCmBgYHtweXRob259CmNvdW50cyA9IENvdW50ZXIod29yZHMpCmBgYAoKYGBge3B5dGhvbn0KY291bnRzLm1vc3RfY29tbW9uKDI1KQpgYGAKCiMjIENsZWFuaW5nIERhdGEKYGBge3B5dGhvbn0KIyBVc2UgUmVndWxhciBFeHByZXNzaW9ucyB0byBnZXQgcmlkIG9mIG5vbi13b3JkIGNoYXJhY3RlcnMKaW1wb3J0IHJlCmBgYAoKYGBge3B5dGhvbn0KY2xlYW5lZCA9IFtdCgpmb3Igd29yZCBpbiB3b3JkczoKICBjbGVhbl93b3JkID0gcmUuc3ViKHInW15hLXpBLVpdJywgJycsIHdvcmQpCiAgY2xlYW5fd29yZCA9IGNsZWFuX3dvcmQubG93ZXIoKQogIGNsZWFuZWQuYXBwZW5kKGNsZWFuX3dvcmQpCmBgYAoKYGBge3B5dGhvbn0KcHJpbnQoY2xlYW5lZCkKYGBgCgpgYGB7cHl0aG9ufQpmcmVxdWVuY2llcyA9IENvdW50ZXIoY2xlYW5lZCkKZnJlcXVlbmNpZXMubW9zdF9jb21tb24oMjUpCmBgYAoKCiMgQWN0aXZpdHkgMgoKVGFrZSBhIGZldyBtaW51dGVzIHRvIGZpbmQgdGhlIHRvcCAxMCBtb3N0IGZyZXF1ZW50IHdvcmRzIGZyb20geW91ciBib29rIChteV9kb2N1bWVudCkuCgpXaGF0IGFyZSB0aGV5PyBQdXQgYSBmZXcgb2YgdGhlbSBpbiB0aGUgY2hhdC4KCiMjIFJlbW92aW5nIFN0b3B3b3JkcwoKYGBge3B5dGhvbn0KIyBEZWFsIHdpdGggc3RvcHdvcmRzCmltcG9ydCBubHRrCmZyb20gbmx0ay5jb3JwdXMgaW1wb3J0IHN0b3B3b3JkcwpubHRrLmRvd25sb2FkKCdzdG9wd29yZHMnKQojICdwdW5rdCcgaXMgZm9yIHNlbnRlbmNlIHRva2VuaXppbmcgbGF0ZXIKbmx0ay5kb3dubG9hZCgncHVua3QnKQpgYGAKCmBgYHtweXRob259CnN0b3Bfd29yZHMgPSBzdG9wd29yZHMud29yZHMoJ2VuZ2xpc2gnKQpgYGAKCmBgYHtweXRob259CnByaW50KHN0b3Bfd29yZHMpCmBgYAoKYGBge3B5dGhvbn0KY2xlYW5lZCA9IFtdCgpmb3Igd29yZCBpbiB3b3JkczoKICBjbGVhbl93b3JkID0gcmUuc3ViKHInW15hLXpBLVpdJywgJycsIHdvcmQpCiAgY2xlYW5fd29yZCA9IGNsZWFuX3dvcmQubG93ZXIoKQogIGlmIGNsZWFuX3dvcmQgbm90IGluIHN0b3Bfd29yZHM6CiAgICBjbGVhbmVkLmFwcGVuZChjbGVhbl93b3JkKQpgYGAKCmBgYHtweXRob259CmZyZXF1ZW5jaWVzID0gQ291bnRlcihjbGVhbmVkKQpmcmVxdWVuY2llcy5tb3N0X2NvbW1vbigyNSkKYGBgCgojIyMgQWRkaW5nIG91ciBvd24gc3RvcHdvcmRzCmBgYHtweXRob259CnN0b3Bfd29yZHMgPSBzdG9wd29yZHMud29yZHMoJ2VuZ2xpc2gnKQoKbXlfc3RvcF93b3JkcyA9IFsnbXInLCAnY291bGQnLCAnd291bGQnLCAnbWF5JywgJ21pZ2h0J10KCmZvciB3b3JkIGluIG15X3N0b3Bfd29yZHM6CiAgc3RvcF93b3Jkcy5hcHBlbmQod29yZCkKYGBgCgpgYGB7cHl0aG9ufQpjbGVhbmVkID0gW10KCmZvciB3b3JkIGluIHdvcmRzOgogIGNsZWFuX3dvcmQgPSByZS5zdWIocidbXmEtekEtWl0nLCAnJywgd29yZCkKICBjbGVhbl93b3JkID0gY2xlYW5fd29yZC5sb3dlcigpCiAgaWYgY2xlYW5fd29yZCBub3QgaW4gc3RvcF93b3JkczoKICAgIGNsZWFuZWQuYXBwZW5kKGNsZWFuX3dvcmQpCgpmcmVxdWVuY2llcyA9IENvdW50ZXIoY2xlYW5lZCkKZnJlcXVlbmNpZXMubW9zdF9jb21tb24oMjUpCmBgYAoKIyBBY3Rpdml0eSAzCgpBZGQgc29tZSBjdXN0b20gc3RvcHdvcmRzIHRvIHlvdXIgb3duIGxpc3QuCgpXaGF0IGFyZSB0aGV5PyBXaGF0IG5ldyB3b3JkcyBtYWRlIGl0IGludG8geW91ciB0b3AgMjUgYWZ0ZXIgdGhpcz8KCiMjIFNhdmluZyBSZXN1bHRzCmBgYHtweXRob259CmltcG9ydCBwYW5kYXMgYXMgcGQKaW1wb3J0IHNlYWJvcm4gYXMgc25zCgojIFdyaXRpbmcgdG8gYSBmaWxlIGluIGNvbGFiIHJlcXVpcmVzIG1vdW50aW5nIEdEcml2ZQpmcm9tIGdvb2dsZS5jb2xhYiBpbXBvcnQgZHJpdmUKZHJpdmUubW91bnQoJy9jb250ZW50L2dkcml2ZScpCmBgYAoKYGBge3B5dGhvbn0Kd29yZF9jb2wgPSBbXQpjb3VudF9jb2wgPSBbXQoKZm9yIHdvcmQsIGNvdW50IGluIGZyZXF1ZW5jaWVzLm1vc3RfY29tbW9uKDI1KToKICB3b3JkX2NvbC5hcHBlbmQod29yZCkKICBjb3VudF9jb2wuYXBwZW5kKGNvdW50KQoKbW9zdF9mcmVxdWVudCA9IHBkLkRhdGFGcmFtZShsaXN0KHppcCh3b3JkX2NvbCwgY291bnRfY29sKSksIGNvbHVtbnMgPSBbJ3dvcmQnLCAnY291bnQnXSkKbW9zdF9mcmVxdWVudApgYGAKCmBgYHtweXRob259Cm1vc3RfZnJlcXVlbnQudG9fY3N2KCcvY29udGVudC9nZHJpdmUvTXlEcml2ZS9tb3N0X2ZyZXF1ZW50LmNzdicpCmBgYAoKIyBBY3Rpdml0eSA0ClNhdmUgeW91ciByZXN1bHRzIHRvIHlvdXIgb3duIEdvb2dsZSBEcml2ZS4KCmBgYHtweXRob259CiMgTWFraW5nIGEgYmFzaWMgdmlzdWFsaXphdGlvbgpzbnMuY2F0cGxvdCgKICAgIGRhdGEgPSBtb3N0X2ZyZXF1ZW50LAogICAgeCA9ICJ3b3JkIiwKICAgIHkgPSAiY291bnQiLAogICAga2luZCA9ICJiYXIiLAogICAgYXNwZWN0ID0gMwopCmBgYAoKIyBTZW50aW1lbnQgQW5hbHlzaXMKYGBge3B5dGhvbn0KIyBpbnN0YWxsIHZhZGVyU2VudGltZW50IHRvIGRvIHNlbnRpbWVudCBhbmFseXNpcwojIFZBREVSIChWYWxlbmNlIEF3YXJlIERpY3Rpb25hcnkgYW5kIHNFbnRpbWVudCBSZWFzb25lcikKIyAtNCB0byA0IGZvciBlYWNoIHdvcmQKIXBpcCBpbnN0YWxsIHZhZGVyU2VudGltZW50CmBgYAoKYGBge3B5dGhvbn0KZnJvbSB2YWRlclNlbnRpbWVudC52YWRlclNlbnRpbWVudCBpbXBvcnQgU2VudGltZW50SW50ZW5zaXR5QW5hbHl6ZXIKCnNhID0gU2VudGltZW50SW50ZW5zaXR5QW5hbHl6ZXIoKQpgYGAKCmBgYHtweXRob259CiMgUHJldmlldyB0aGUgbGV4aWNvbgpzYS5sZXhpY29uCmBgYAoKYGBge3B5dGhvbn0KIyBvdmVyYWxsIHBvbGFyaXR5IHNjb3JlcyBhcmUgLTEgdG8gMQpteV9uZWdhdGl2ZV9zZW50ZW5jZSA9ICJJIGFic29sdXRlbHkgaGF0ZSBWaWN0b3JpYW4gbm92ZWxzLiBUaGV5IGFyZSB0aGUgd29yc3QuIgoKc2EucG9sYXJpdHlfc2NvcmVzKG15X25lZ2F0aXZlX3NlbnRlbmNlKQpgYGAKCmBgYHtweXRob259Cm15X3Bvc2l0aXZlX3NlbnRlbmNlID0gIlZpY3RvcmlhbiBub3ZlbHMgYXJlIGZhbnRhc3RpYy4gSSBjb21wbGV0ZWx5IGFkb3JlIHRoZW0uIgoKc2EucG9sYXJpdHlfc2NvcmVzKG15X3Bvc2l0aXZlX3NlbnRlbmNlKQpgYGAKCgojIEFjdGl2aXR5IDUKCldyaXRlIGEgdmVyeSBwb3NpdGl2ZSBzZW50ZW5jZSBhbmQgYSB2ZXJ5IG5lZ2F0aXZlIHNlbnRlbmNlLgoKQW5hbHl6ZSB0aGVpciBwb2xhcml0eSBzY29yZXMgd2l0aCBWQURFUi4KCgpgYGB7cHl0aG9ufQpjb21wb3VuZCA9IHNhLnBvbGFyaXR5X3Njb3JlcyhteV9wb3NpdGl2ZV9zZW50ZW5jZSlbJ2NvbXBvdW5kJ10KcHJpbnQoY29tcG91bmQpCmBgYAoKYGBge3B5dGhvbn0KZnJvbSBubHRrLnRva2VuaXplIGltcG9ydCBzZW50X3Rva2VuaXplCmBgYAoKYGBge3B5dGhvbn0Kc2VudGVuY2VzID0gc2VudF90b2tlbml6ZShkb2N1bWVudCkKYGBgCgpgYGB7cHl0aG9ufQpzZW50ZW5jZXNbMDoxMF0KYGBgCgpgYGB7cHl0aG9ufQpzY29yZSA9IFtdCnRleHQgPSBbXQoKCmZvciBzZW50ZW5jZSBpbiBzZW50ZW5jZXM6CiAgdGV4dC5hcHBlbmQoc2VudGVuY2UpCiAgc2NvcmUuYXBwZW5kKHNhLnBvbGFyaXR5X3Njb3JlcyhzZW50ZW5jZSlbJ2NvbXBvdW5kJ10pCgpzY29yZXMgPSBwZC5EYXRhRnJhbWUobGlzdCh6aXAoc2NvcmUsIHRleHQpKSwgY29sdW1ucyA9IFsnc2NvcmUnLCAndGV4dCddKQpzY29yZXMKYGBgCgpgYGB7cHl0aG9ufQpzY29yZXMudG9fY3N2KCcvY29udGVudC9nZHJpdmUvTXlEcml2ZS9zY29yZXMuY3N2JykKYGBgCgpgYGB7cHl0aG9ufQpzbnMucmVscGxvdCgKICAgIGRhdGEgPSBzY29yZXMsCiAgICB4ID0gc2NvcmVzLmluZGV4LAogICAgeSA9ICdzY29yZScsCiAgICBraW5kID0gJ2xpbmUnLAogICAgYXNwZWN0ID0gNAopCmBgYAoKCiMgQWN0aXZpdHkgNgoKUGxvdCB0aGUgcG9sYXJpdHkgc2NvcmVzIChzZW50ZW5jZS1ieS1zZW50ZW5jZSkgb2YgeW91ciBib29rLgoKCg==