Skip to content

Repository files navigation

SANE — Sentiment Analysis for Named Entities

Python License: MIT Tests Coverage Ruff

A Python library for entity-level sentiment analysis. SANE identifies named entities in text and classifies the sentiment expressed toward each one — rather than scoring the document as a whole.

Example:

"Apple announced great results, but Microsoft disappointed investors."

Entity Type Sentiment Confidence Polarity
Apple ORG positive 0.8529 +0.8409
Microsoft ORG negative 0.9873 −0.9873

How it works

SANE is a custom spaCy pipeline component that chains two models:

  1. NER — spaCy extracts named entities from the text
  2. ABSA — a HuggingFace aspect-based sentiment model classifies sentiment for each entity using the full sentence as context

Installation

uv sync

Usage

Basic usage

import spacy
import sane  # registers the "sane" pipeline component

nlp = spacy.load("en_core_web_md")
nlp.add_pipe("sane", after="ner")

doc = nlp("Apple announced great results, but Microsoft disappointed investors.")

for es in doc._.entity_sentiments:
    print(es.text, es.sentiment, es.polarity)
# Apple     positive  0.8409
# Microsoft negative -0.9753

Accessing full sentiment probabilities

for es in doc._.entity_sentiments:
    print(es.text, es.sentiment_probs)
# Apple     {'positive': 0.8529, 'neutral': 0.1351, 'negative': 0.012}
# Microsoft {'positive': 0.0089, 'neutral': 0.0158, 'negative': 0.9753}

Filtering by entity type

Only process specific entity types (e.g. organisations and people):

nlp = spacy.load("en_core_web_md")
nlp.add_pipe("sane", after="ner", config={"entity_types": ["ORG", "PERSON"]})

doc = nlp("Elon Musk praised Tesla, but critics blamed Washington for the slowdown.")

for es in doc._.entity_sentiments:
    print(f"{es.text} ({es.entity_type}): {es.sentiment}")
# Elon Musk  (PERSON): positive
# Tesla      (ORG):    positive
# Washington is skipped — it is a GPE, not ORG or PERSON

GPU / device selection

# Explicit device
nlp.add_pipe("sane", after="ner", config={"device": "cuda"})

# Auto-select: prefers CUDA → MPS → CPU
nlp.add_pipe("sane", after="ner", config={"device": "auto"})

Using a custom ABSA model

nlp.add_pipe("sane", after="ner", config={
    "model": "my-org/my-absa-model",
    "device": "auto",
    "precision": 6,
})

EntitySentiment fields

Each item in doc._.entity_sentiments is an EntitySentiment dataclass:

Field Type Description
text str Entity surface form
entity_type str spaCy NER label (e.g. "ORG", "PERSON")
start_idx int Character offset (start)
end_idx int Character offset (end)
sentiment "positive" | "neutral" | "negative" Predicted label
confidence float Model confidence for the predicted label
polarity float P(positive) − P(negative) in [−1, 1]
sentiment_probs dict[str, float] Full probability distribution over all labels

Development

# Run tests
pytest

# Run tests with coverage
pytest --cov=src/sane --cov-report=term-missing

# Lint
ruff check src tests

Project Structure

sane/
├── src/sane/       # Package
├── tests/          # Test suite
├── notebooks/      # Research & prototyping
├── docs/           # Planning & design docs
├── data/           # Datasets
└── models/         # Trained models

License

SANE is released under the MIT License.

SANE uses the yangheng/deberta-v3-base-absa-v1.1 model from the PyABSA project by Yang Heng, also distributed under the MIT License. If you use SANE in academic work, please cite PyABSA:

@article{yang-etal-2023-pyabsa,
  title     = {PyABSA: A Modular and Reproducible Framework for Aspect-Based Sentiment Analysis},
  author    = {Yang, Heng and Li, Ke},
  journal   = {arXiv preprint arXiv:2208.01368},
  year      = {2023},
  url       = {https://arxiv.org/abs/2208.01368}
}

About

Sentiment Analysis for Named Entities

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages