AI-Powered Sentiment Analysis

Using the ellmer Package in R

Sabin Ku Shah

What is ellmer?

ellmer is an R package that lets you talk to large language models (like GPT-4o) directly from your R session.

  • 🤖 Connect to OpenAI, Anthropic, and more
  • 🔗 Works seamlessly with tidyverse pipelines
  • ⚡ Enables LLM-powered data transformations
  • 📦 Simple, clean API for chat-based models
install.packages("ellmer")
library(ellmer)

The Problem We’re Solving

How do customers feel about the products they review?

Traditional sentiment analysis gives you:

  • 😐 Positive / Negative / Neutral labels

AI-powered analysis gives you:

  • 🎭 Nuanced emotions (e.g., Frustrated, Delighted)
  • 💬 Human-like vibe checks (e.g., “Pleasantly surprised but cautious”)

Our Dataset: Amazon Reviews

The dataset contains Amazon product reviews with the following key columns:

Column Description
reviewerName Who wrote the review
overall Star rating (1–5)
reviewText The actual review content
reviewTime Date of the review
helpful_yes / helpful_no Helpfulness votes
wilson_lower_bound Bayesian helpfulness score

We sampled 100 rows for our live analysis.

Dataset Preview

First 6 rows of the Amazon Reviews dataset
Reviewer Stars Review Text Date
Dare to satisfy me 5 What can I say about it works as promised and just what I needed for my new cell phone what more do you need 2013-11-06
R. Briggs 5 I purchased this because my Samsumg Galaxy S3 was getting full of pictures. It installed easy, works great and I have had no speed issues when writing or reading from it, 2013-03-20
Beau Hunter “Beau” 5 Figured there was not going to be any issues with SanDisk; produce arrived in well packaged - removed it, formatted it on computer, and installed. Working fine! 2014-10-01
FrankieBoy 5 I got the 64gb card in and i just placed it in the sony cyber tx66 camera and and it ran it’s preparation program for 2 seconds, and low and behold, it works perfectly. after shooting and taking hd movie and highest res pictures i used sony software download and it recognized the card at about 59.8GB. this camera could probably take the 128 micro card 2012-10-25
Ben Myers 5 fast and giv, works great 2014-05-07
Ali G Sandoval 5 Best price anywhere!!! 2014-07-14

(100 rows sampled for this demo)

Workflow Overview

📦 Load Data
    ↓
🔑 Connect to OpenAI via ellmer
    ↓
🧠 Define AI Analysis Function
    ↓
🔁 Apply to Every Review (map_chr)
    ↓
💾 Save Results
    ↓
📊 Explore & Present Insights

Step 1 — Load Libraries & Data

library(tidyverse)
library(ellmer)

# Load the dataset and sample 100 rows for demo speed
df <- read_csv("amazon_reviews.csv") %>% 
  sample_n(100)

glimpse(df)
Rows: 100
Columns: 12
$ reviewerName        <chr> "Dare to satisfy me", "R. Briggs", ...
$ overall             <dbl> 5, 5, 5, 4, 3, ...
$ reviewText          <chr> "What can I say about it works as..."
$ reviewTime          <date> 2013-11-06, 2013-03-20, ...
$ helpful_yes         <dbl> 0, 0, 0, ...
$ wilson_lower_bound  <dbl> 0, 0, 0, ...

Step 2 — Connect to OpenAI

# Set your OpenAI API Key as an environment variable
Sys.setenv(OPENAI_API_KEY = "sk-proj-...")

# Create a "chat brain" using GPT-4o-mini (fast & cost-effective)
chat_brain <- chat_openai(model = "gpt-4o-mini")

Tip

Why GPT-4o-mini?
It’s faster and cheaper than GPT-4o for high-volume tasks, while still being highly capable for structured analysis.

Step 3 — Define the AI Function

analyze_reviews_ai <- function(text) {
  
  # Craft a structured prompt for consistent output
  prompt <- paste0(
    "Analyze this Amazon review: '", text, "'. ",
    "Provide a response in this exact format: ",
    "Emotion: [1 word] | Vibe: [Short phrase describing the customer's mood]"
  )
  
  return(chat_brain$chat(prompt))
}

Example prompt sent to GPT:

“Analyze this Amazon review: ‘Works great, fast delivery!’.
Provide a response in this exact format:
Emotion: [1 word] | Vibe: [Short phrase describing the customer’s mood]”

Step 4 — Run the Analysis

# Apply the AI function to every review using map_chr
df_final <- df %>%
  mutate(
    ai_insight = map_chr(reviewText, ~analyze_reviews_ai(.x), 
                         .progress = TRUE)
  )

# Save the results so we don't re-run the API calls
save(df_final, file = "ai_results.RData")

Note

⏱️ Timing: ~2 seconds per row × 100 rows ≈ ~3–4 minutes total.
The .progress = TRUE argument shows a live progress bar.

Sample Output

Sample AI-generated insights
Reviewer Review AI Insight
Dare to satisfy me 5 Works as promised, just what I needed! Emotion: Satisfied | Vibe: Relieved and pleasantly surprised
R. Briggs 5 Easy install, works great, no speed issues. Emotion: Pleased | Vibe: Confident and straightforward
FrankieBoy 5 Ran perfectly in my camera. Highly recommend! Emotion: Delighted | Vibe: Enthusiastic early adopter
TechMom2014 3 It’s fine I guess. Does the job. Emotion: Indifferent | Vibe: Lukewarm and unenthusiastic
GadgetGuru 4 Good value but packaging could be better. Emotion: Content | Vibe: Practical but mildly critical

Why This Matters

Traditional NLP:

  • Binary labels (pos/neg)
  • Keyword matching
  • Misses sarcasm & nuance
  • Requires training data

ellmer + LLM approach:

  • Rich emotional context
  • Zero-shot understanding
  • Handles sarcasm & subtlety
  • No training data needed

Key Takeaways

  1. ellmer bridges R and LLMs — no Python needed
  2. map_chr + a prompt function = scalable AI pipelines in tidyverse
  3. Structured prompts ensure consistent, parseable outputs
  4. GPT-4o-mini is the sweet spot for cost vs. quality on bulk tasks
  5. Save your results — don’t re-run expensive API calls unnecessarily

Thank You!

Resources:

Questions?

# Get started in 3 lines:
library(ellmer)
brain <- chat_openai("gpt-4o-mini")
brain$chat("Hello, R world!")