NRC Emotional Lexicon

This is the NRC Emotional Lexicon: “The NRC Emotion Lexicon is a list of English words and their associations with eight basic emotions (anger, fear, anticipation, trust, surprise, sadness, joy, and disgust) and two sentiments (negative and positive). The annotations were manually done by crowdsourcing.”

I don’t trust it, but everyone uses it.

import pandas as pd
filepath = "NRC-Emotion-Lexicon-v0.92/NRC-emotion-lexicon-wordlevel-alphabetized-v0.92.txt"
emolex_df = pd.read_csv(filepath,  names=["word", "emotion", "association"], skiprows=45, sep='\t')
emolex_df.head(12)
word emotion association
0 aback anger 0
1 aback anticipation 0
2 aback disgust 0
3 aback fear 0
4 aback joy 0
5 aback negative 0
6 aback positive 0
7 aback sadness 0
8 aback surprise 0
9 aback trust 0
10 abacus anger 0
11 abacus anticipation 0

Seems kind of simple. A column for a word, a column for an emotion, and whether it’t associated or not. You see “aback aback aback aback” because there’s a row for every word-emotion pair.

What emotions are covered?

Let’s look at the ‘emotion’ column. What can we talk about?

emolex_df.emotion.unique()
array(['anger', 'anticipation', 'disgust', 'fear', 'joy', 'negative',
       'positive', 'sadness', 'surprise', 'trust'], dtype=object)
emolex_df.emotion.value_counts()
fear            14182
anger           14182
trust           14182
anticipation    14182
sadness         14182
disgust         14182
surprise        14182
joy             14182
positive        14182
negative        14182
Name: emotion, dtype: int64

How many words does each emotion have?

Each emotion doesn’t have 14182 words associated with it, unfortunately! 1 means “is associated” and 0 means “is not associated.”

We’re only going to care about “is associated.”

emolex_df[emolex_df.association == 1].emotion.value_counts()
negative        3324
positive        2312
fear            1476
anger           1247
trust           1231
sadness         1191
disgust         1058
anticipation     839
joy              689
surprise         534
Name: emotion, dtype: int64

In theory things could be kind of angry or kind of joyous, but it doesn’t work like that. If you want to spend a few hundred dollars on Mechnical Turk, though, your own personal version can.

What if I just want the angry words?

emolex_df[(emolex_df.association == 1) & (emolex_df.emotion == 'anger')].word
30          abandoned
40        abandonment
170             abhor
180         abhorrent
270           abolish
300       abomination
630             abuse
1120         accursed
1130       accusation
1150          accused
1160          accuser
1170         accusing
1470       actionable
1650            adder
2390        adversary
2400          adverse
2410        adversity
2500         advocacy
2840          affront
2920        aftermath
3030       aggravated
3040      aggravating
3050      aggravation
3080       aggression
3090       aggressive
3100        aggressor
3140         agitated
3150        agitation
3190            agony
3570       alcoholism
             ...     
138470        warlike
138530           warp
138600        warrior
138680         wasted
138690       wasteful
139330          wench
139550           whip
139950        willful
140020          wimpy
140030          wince
140220       wireless
140290          witch
140300     witchcraft
140610            wop
140640          words
140870      worthless
140900          wound
140920      wrangling
140960          wrath
140970          wreak
140990          wreck
141000        wrecked
141060         wretch
141090          wring
141210     wrongdoing
141220       wrongful
141230        wrongly
141470           yell
141500           yelp
141640          youth
Name: word, Length: 1247, dtype: object

Reshaping

You can also reshape the data in order to look at it a slightly different way

emolex_words = emolex_df.pivot(index='word', columns='emotion', values='association').reset_index()
emolex_words.head()
emotion word anger anticipation disgust fear joy negative positive sadness surprise trust
0 aback 0 0 0 0 0 0 0 0 0 0
1 abacus 0 0 0 0 0 0 0 0 0 1
2 abandon 0 0 0 1 0 1 0 1 0 0
3 abandoned 1 0 0 1 0 1 0 1 0 0
4 abandonment 1 0 0 1 0 1 0 1 1 0

You can now pull out individual words…

# If you didn't reset_index you could do this more easily
# by doing emolex_words.loc['charitable']
emolex_words[emolex_words.word == 'charitable']
emotion word anger anticipation disgust fear joy negative positive sadness surprise trust
2001 charitable 0 1 0 0 1 0 1 0 0 1

…or individual emotions….

emolex_words[emolex_words.anger == 1].head()
emotion word anger anticipation disgust fear joy negative positive sadness surprise trust
3 abandoned 1 0 0 1 0 1 0 1 0 0
4 abandonment 1 0 0 1 0 1 0 1 1 0
17 abhor 1 0 1 1 0 1 0 0 0 0
18 abhorrent 1 0 1 1 0 1 0 0 0 0
27 abolish 1 0 0 0 0 1 0 0 0 0

…or multiple emotions!

emolex_words[(emolex_words.joy == 1) & (emolex_words.negative == 1)].head()
emotion word anger anticipation disgust fear joy negative positive sadness surprise trust
61 abundance 0 1 1 0 1 1 1 0 0 1
1018 balm 0 1 0 0 1 1 1 0 0 0
1382 boisterous 1 1 0 0 1 1 1 0 0 0
1916 celebrity 1 1 1 0 1 1 1 0 1 1
2004 charmed 0 0 0 0 1 1 1 0 0 0

The useful part is going to be just getting words for a single emotion.

# Angry words
emolex_words[emolex_words.anger == 1].word
3          abandoned
4        abandonment
17             abhor
18         abhorrent
27           abolish
30       abomination
63             abuse
112         accursed
113       accusation
115          accused
116          accuser
117         accusing
147       actionable
165            adder
239        adversary
240          adverse
241        adversity
250         advocacy
284          affront
292        aftermath
303       aggravated
304      aggravating
305      aggravation
308       aggression
309       aggressive
310        aggressor
314         agitated
315        agitation
319            agony
357       alcoholism
            ...     
13847        warlike
13853           warp
13860        warrior
13868         wasted
13869       wasteful
13933          wench
13955           whip
13995        willful
14002          wimpy
14003          wince
14022       wireless
14029          witch
14030     witchcraft
14061            wop
14064          words
14087      worthless
14090          wound
14092      wrangling
14096          wrath
14097          wreak
14099          wreck
14100        wrecked
14106         wretch
14109          wring
14121     wrongdoing
14122       wrongful
14123        wrongly
14147           yell
14150           yelp
14164          youth
Name: word, Length: 1247, dtype: object