Polarity Checker

An NLP pipeline that scores sentiment and subjectivity in open-ended survey responses, built for the Arlington 2050 planning project.

Overview

Built a program using pandas and spaCy that detects the polarity of open-ended responses, as an applied exercise in data vectorization and natural language processing.

It grew out of a broader interest in sentiment analysis. I used it to analyze real survey data collected from Arlington residents at the county fair.

Resources

Arlington 2050: the source data

The process

Everything ran through Python, using pandas to move data between Excel files and code.

import pandas as pd

Load the survey export and assign it to a variable:

array1 = pd.read_excel("CountyFair.xlsx")

Rename the columns so they're easier to work with:

ds = array1.rename(columns={
  "Unnamed: 1": "Year2050",
  "Unnamed: 2": "Translation1",
  "Unnamed: 3": "Getting_Here",
  "Unnamed: 4": "Translation2"
})

From there, spaCy handles the NLP side:

import spacy
from wordcloud import WordCloud, STOPWORDS
import matplotlib.pyplot as plt
from spacytextblob.spacytextblob import SpacyTextBlob

Some responses came in Spanish. This pass swaps in the English translation column wherever one exists:

nlp = spacy.load('en_core_web_sm')
nlp.add_pipe('spacytextblob')

string_list = ds['Year2050'].tolist()
spanish_list = ds['Translation1'].tolist()
IndexCounter = 0
for n in spanish_list:
    workingstring = str(n)
    if workingstring != 'nan':
        string_list[IndexCounter] = workingstring
    IndexCounter += 1

Building a word cloud

First, pull every word out of the responses, excluding stop words and punctuation:

text = ds['Year2050'].str.cat(sep='')
doc = nlp(text)
words = [token.text for token in doc if not token.is_stop and not token.is_punct]

Then generate the cloud itself:

wordcloud = WordCloud(width=800, height=400, background_color='white',
                      max_words=100, contour_width=3, contour_color='steelblue'
                     ).generate(" ".join(words))

plt.figure(figsize=(10, 5))
plt.imshow(wordcloud, interpolation='bilinear')
plt.axis("off")
plt.show()

The result surfaces the survey's major themes at a glance — housing, parks, and community came up the most.

Polarity and subjectivity histograms

Next, compute polarity and subjectivity for every response:

pol_list = []
sub_list = []
for t in range(2, len(string_list)):
    text = string_list[t]
    doc = nlp(text)
    pol_list.append(doc._.blob.polarity)
    sub_list.append(doc._.blob.subjectivity)

With the plotting libraries in place:

import seaborn as sns
import numpy as np

Subjectivity

plt.figure(figsize=(10, 6))
sns.histplot(data=sub_list)
plt.title('Subjectivity of Postcard Responses from County Fair')
plt.xlabel('In a range from 0 to 1')
plt.ylabel('Frequency')
plt.grid(True)
plt.show()

Polarity

plt.figure(figsize=(10, 6))
sns.histplot(data=pol_list)
plt.title('Polarity of Postcard Responses from County Fair')
plt.xlabel('In a range from -1 to 1')
plt.ylabel('Frequency')
plt.grid(True)
plt.show()

Related techniques worth knowing

Dimensionality reduction

Vector embeddings

An example, checking vector stats for common words versus nonsense strings:

import spacy
nlp = spacy.load("en_core_web_lg") 
tokens = nlp("dog cat banana afskfsd")

for token in tokens:
    print(token.text, token.has_vector, token.vector_norm, token.is_oov)

Summary

Some of what's covered here is genuinely college-level material, but the Arlington 2050 project made it concrete: it's a real introduction to how language gets represented mathematically, which is a core part of how AI systems interpret text. It was a solid first pass at natural language processing and real-world data visualization.

← Back to portfolio