SENTIMENT

The SENTIMENT function provides a unified interface for several sentiment analysis models, ranging from fast lexicon-based analyzers to state-of-the-art transformer models.

The function returns an Excel Data Type containing scores and classifications.

Available Analyzers:

Lexicon & ML Engines:

  1. Pattern (Default): Fast, lexicon-based. Returns Polarity (-1 to 1) and Subjectivity (0 to 1).
  2. Naive Bayes: A machine learning model trained on movie reviews. Returns a Classification (Positive/Negative) and probabilities.
  3. VADER: Specifically tuned for social media, slang, and emojis. Returns a Compound score (-1 to 1).

Transformer (BERT) Engines:

These models run entirely in the browser using transformers.js: 4. Movie Reviews (DistilBERT): Fast and accurate for general English sentiment. 5. Product Reviews (Multilingual BERT): Optimized for reviews across multiple languages. 6. Finance News (FinBERT): Specifically trained for financial sentiment. 7. Twitter Messages (RoBERTa): Tuned for social media, slang, and emojis.

Usage:

  • The primary value shown in the cell depends on the analyzer (e.g., Polarity for Pattern, Label for BERT).
  • Access detailed scores using the . operator (e.g., =A1.Score, =A1.Subjectivity).

Excel Usage

=SENTIMENT(text, sentiment_model)
  • text (list[list], required): Single text cell or 2D text range to analyze.
  • sentiment_model (str, optional, default: “pattern”): The sentiment analysis engine to use.

Returns (list[list]): 2D array of sentiment data types.

Example 1: Pattern (Default) - Opinionated Text

Inputs:

text sentiment_model
I absolutely love the new design! pattern

Excel formula:

=SENTIMENT("I absolutely love the new design!", "pattern")

Expected output:

{"type":"Double","basicValue":0.335227,"properties":{"Polarity":{"type":"Double","basicValue":0.335227},"Subjectivity":{"type":"Double","basicValue":0.527273}}}

Example 2: VADER - Social Media Style

Inputs:

text sentiment_model
The service was GREAT!!! :) vader

Excel formula:

=SENTIMENT("The service was GREAT!!! :)", "vader")

Expected output:

{"type":"Double","basicValue":0.8661,"properties":{"Compound":{"type":"Double","basicValue":0.8661},"Positive":{"type":"Double","basicValue":0.744},"Neutral":{"type":"Double","basicValue":0.256},"Negative":{"type":"Double","basicValue":0}}}

Example 3: Movie Review (BERT)

Inputs:

text sentiment_model
This film is a masterpiece of modern cinema. bert_movie

Excel formula:

=SENTIMENT("This film is a masterpiece of modern cinema.", "bert_movie")

Expected output:

{"type":"String","basicValue":"POSITIVE","properties":{"Label":{"type":"String","basicValue":"POSITIVE"},"Score":{"type":"Double","basicValue":0.999829}}}

Example 4: Financial News (BERT)

Inputs:

text sentiment_model
Company shares plummeted after the disappointing earnings report. bert_finance

Excel formula:

=SENTIMENT("Company shares plummeted after the disappointing earnings report.", "bert_finance")

Expected output:

{"type":"String","basicValue":"negative","properties":{"Label":{"type":"String","basicValue":"negative"},"Score":{"type":"Double","basicValue":0.906089}}}

Python Code

Show Code
import nltk
from textblob import TextBlob
from textblob.sentiments import PatternAnalyzer, NaiveBayesAnalyzer
from vaderSentiment.vaderSentiment import SentimentIntensityAnalyzer as VaderSIA
from transformers_js_py import import_transformers_js

async def sentiment(text, sentiment_model='pattern'):
    """
    Multi-engine sentiment analysis (Lexicon, ML, or Transformer-based).

    See: https://textblob.readthedocs.io/en/dev/

    This example function is provided as-is without any representation of accuracy.

    Args:
        text (list[list]): Single text cell or 2D text range to analyze.
        sentiment_model (str, optional): The sentiment analysis engine to use. Valid options: Pattern, Naive Bayes, VADER, Movie Reviews (BERT), Product Reviews (BERT), Finance News (BERT), Twitter Messages (BERT). Default is 'pattern'.

    Returns:
        list[list]: 2D array of sentiment data types.
    """
    try:
        def to2d(value):
            return [[value]] if not isinstance(value, list) else value

        def validate_grid(value):
            if not isinstance(value, list) or not value or not all(isinstance(row, list) for row in value):
                return None, "Error: text must be a non-empty 2D list"
            if len({len(row) for row in value}) != 1:
                return None, "Error: text must be a rectangular 2D list"
            return value, None

        text_grid, error = validate_grid(to2d(text))
        if error:
            return error

        # Mapping for BERT models
        bert_models = {
            "bert_movie": "Xenova/distilbert-base-uncased-finetuned-sst-2-english",
            "bert_product": "Xenova/bert-base-multilingual-uncased-sentiment",
            "bert_finance": "Xenova/finbert",
            "bert_twitter": "Xenova/twitter-roberta-base-sentiment-latest"
        }

        # Setup engines
        engine = None
        pipe = None

        if sentiment_model == "vader":
            engine = VaderSIA()
        elif sentiment_model == "naive_bayes":
            nltk.download("movie_reviews", quiet=True)
            nltk.download("punkt", quiet=True)
            nltk.download("punkt_tab", quiet=True)
            engine = NaiveBayesAnalyzer()
        elif sentiment_model == "pattern":
            engine = PatternAnalyzer()
        elif sentiment_model in bert_models:
            transformers = await import_transformers_js()
            pipeline = transformers.pipeline
            pipe = await pipeline("sentiment-analysis", bert_models[sentiment_model])

        result = []
        for row in text_grid:
            out_row = []
            for cell in row:
                if cell is None or (isinstance(cell, str) and not cell.strip()):
                    out_row.append("")
                    continue
                if not isinstance(cell, str):
                    out_row.append("Error: text must contain only strings")
                    continue

                data = {}
                if sentiment_model == "vader":
                    scores = engine.polarity_scores(cell)
                    data = {
                        "type": "Double",
                        "basicValue": float(scores["compound"]),
                        "properties": {
                            "Compound": {"type": "Double", "basicValue": float(scores["compound"])},
                            "Positive": {"type": "Double", "basicValue": float(scores["pos"])},
                            "Neutral": {"type": "Double", "basicValue": float(scores["neu"])},
                            "Negative": {"type": "Double", "basicValue": float(scores["neg"])}
                        }
                    }
                elif sentiment_model == "naive_bayes":
                    blob = TextBlob(cell, analyzer=engine)
                    sent = blob.sentiment
                    data = {
                        "type": "String",
                        "basicValue": str(sent.classification),
                        "properties": {
                            "Classification": {"type": "String", "basicValue": str(sent.classification)},
                            "P-Positive": {"type": "Double", "basicValue": float(sent.p_pos)},
                            "P-Negative": {"type": "Double", "basicValue": float(sent.p_neg)}
                        }
                    }
                elif sentiment_model == "pattern":
                    p, s = engine.analyze(cell)
                    data = {
                        "type": "Double",
                        "basicValue": float(p),
                        "properties": {
                            "Polarity": {"type": "Double", "basicValue": float(p)},
                            "Subjectivity": {"type": "Double", "basicValue": float(s)}
                        }
                    }
                elif sentiment_model in bert_models:
                    raw_result = await pipe(cell)
                    if hasattr(raw_result, "to_py"):
                        prediction = raw_result.to_py()[0]
                    else:
                        prediction = raw_result[0]

                    label = str(prediction["label"])
                    score = float(prediction["score"])

                    data = {
                        "type": "String",
                        "basicValue": label,
                        "properties": {
                            "Label": {"type": "String", "basicValue": label},
                            "Score": {"type": "Double", "basicValue": score}
                        }
                    }
                out_row.append(data)
            result.append(out_row)

        return result
    except Exception as e:
        return f"Error: {str(e)}"

Online Calculator

Single text cell or 2D text range to analyze.
The sentiment analysis engine to use.