Sentiment Headline Lexicon

This is a sentiment lexicon I built from about 85k stock news headlines for a homework assignment (lexicon based sentiment analysis, so no ML model here, just word weights). Instead of using a hand built dictionary like TextBlob or VADER, this one is learned straight from the labeled headlines: every word gets scored by how often it showed up next to an "up" move vs a "down" move in the training data.

How it works

For every word that showed up in at least 5 training headlines, I compute a smoothed log odds score:

weight(word) = log( P(word | next return up) / P(word | next return down) )

using only the training slice of the data (chronologically 2019-08-01 to 2020-10-01), counted by how many headlines a word appears in rather than raw word counts, so one headline repeating a word a bunch of times can't skew things.

Tokenizing for this specific upload used a plain regex clean plus sklearn's stopword list. The course notebook itself uses spaCy lemmatization instead (that's what the assignment asked for), and gets basically the same result, 0.5968 there vs 0.5988 here, so either one reproduces the lexicon fine.

Using it

import json
from huggingface_hub import hf_hub_download

path = hf_hub_download(repo_id="ShubhamOza/sentiment-headline-lexicon", filename="lexicon.json")
lexicon = json.load(open(path))

def score(tokens):
    weights = [lexicon[t] for t in tokens if t in lexicon]
    return sum(weights) / len(weights) if weights else 0.0

score(["downgrade", "cut", "target", "price"])   # negative
score(["beat", "estimate", "record", "revenue"])  # positive

Score >= 0 means predict "up", below 0 means "down".

Does it actually work

Same test used for TextBlob / VADER / Loughran-McDonald in the course notebook: threshold 0, full 91,851 headline corpus.

TextBlob 0.5212, VADER 0.5225, Loughran-McDonald 0.5207, just guessing "up" every time 0.5324, this lexicon 0.5988.

That last number is a little unfair though, since about 92% of that corpus is the same data the lexicon trained on. Split out by time it looks more like this:

partition n accuracy majority baseline
train 84,643 0.6081 0.5316
test (before the training window) 4,811 0.5049 0.5053
inference (after training, Oct 2020) 2,397 0.4589 0.6154

So out of sample it's close to a coin flip on test, and actually worse than baseline on inference. That tracks with market efficiency, if headline word choice reliably predicted next day stock moves out of sample, that edge wouldn't stick around for long. It still beats the other lexicons fair and square under their own evaluation though, just don't take it as a trading signal.

Limitations

  • Some of what it "learns" is really company or ticker name drift picked up from the training window, not actual language sentiment
  • Trained on Reuters/Eikon headlines for S&P/DOW/NASDAQ names, July 2019 to Oct 2020, probably doesn't transfer well outside that
  • Not meant to be used for actual trading

Source

Built for a lexicon based sentiment homework, extending the "Build our own lexicon" part of an NLP course notebook that already covers TextBlob, VADER and Loughran-McDonald as baselines. Companion dataset: ShubhamOza/sentiment-headline-scores

Downloads last month

-

Downloads are not tracked for this model. How to track
Inference Providers NEW
This model isn't deployed by any Inference Provider. 🙋 Ask for provider support