Court Sentiment
Menu

2025-26 · How it works

How it works

Where the numbers come from, and what they are not. One real comment followed from download to its row, the rule that ties a comment to a player, the prompt word for word, and a check by hand.

Here for how it's built? Jump to Use the data ↓

What this is

Every r/NBA comment of the 2025-26 season that names a tracked player, read by a language model and tied to one player. Here is one, followed from download to its row in the data. The figures down the side are the season's totals at each step.

  1. DownloadArctic Shift · r/NBA7,283,478 comments
    Just feels like a smarter player. Poole will probably have higher highs but Ajay feels more consistent

    One line per comment, the whole regular season and playoffs. A Thunder fan comparing two guards. May 12, 2026.

    The raw record
    {
      "id": "oldhosi",
      "body": "Just feels like a smarter player. Poole will probably have higher highs but Ajay feels more consistent",
      "author_flair_text": ":okc-2: Thunder",
      "score": 1,
      "link_id": "t3_1tav0sz"
    }
    + created_utc and the rest of what Reddit stores. The author's name never leaves the pipeline.

    Deleted, removed and empty bodies drop out first.

  2. Find namesplayers.yaml · 223 players2,110,485 kept
    Just feels like a smarter player. Poole will probably have higher highs but Ajay feels more consistent

    Every name r/NBA uses for a tracked player is matched against the body. “Ajay” is Ajay Mitchell; “Poole” is Jordan Poole. Short names only match as whole words.

    The names found
    {
      "mentioned_players": [
        "Ajay Mitchell",
        "Jordan Poole"
      ],
      "mentioned_text": [
        "Ajay",
        "Poole"
      ]
    }

    5,172,993 comments name no tracked player and stop here. None of them are ever classified.

  3. Ask the classifierAnthropic Batch API100,000 per batch

    The whole prompt goes out with the comment inside it, to claude-haiku-4-5-20251001, in batches of 100,000. The prompt is below, word for word.

    The request
    {
      "custom_id": "oldhosi",
      "params": {
        "model": "claude-haiku-4-5-20251001",
        "max_tokens": 75,
        "temperature": 0,
        "messages": [
          {
            "role": "user",
            "content": "Classify sentiment toward NBA players.\nSlang: nasty/sick/filthy=positive, washed/brick/fraud/cooked=negative, GOAT=positive.\nA trailing \"/s\" tags the comment as sarcasm.\n\nComment: Just feels like a smarter player. Poole will probably have higher highs but Ajay feels more consistent\n\nRespond ONLY with JSON: {\"s\":\"pos|neg|neu\",\"c\":0.0-1.0,\"p\":\"Player Name\"|null}"
          }
        ]
      }
    }
  4. The answerclaude-haiku-4-5-202510012,059,495 usable
    {"s":"pos", "c":0.7, "p":"Ajay"}

    That is the entire response. s is the sentiment, c the model's own confidence from 0 to 1, p who it thinks the comment is about.

    50,990 requests fail or come back as something that can't be read.

  5. Pick the playerthe attribution rule1,787,520 counted
    names foundAjay MitchellJordan Poole
    several names, so ask p"Ajay"→ players.yaml →Ajay Mitchell
    flair":okc-2: Thunder"→ teams.yaml →Oklahoma City Thunder

    p comes back as the model wrote it, so it goes through the same name list as the body did. The flair goes through the team list.

    271,975 usable comments can't be pinned to one player and count for nobody.

  6. One rowsentiment.parquet1 row per comment

    One positive for Ajay Mitchell, from a Thunder fan. At c = 0.7 it counts in the rates but is never quoted: a quote needs 0.9.

    The row
    {
      "comment_id": "oldhosi",
      "mentioned_players": [
        "Ajay Mitchell",
        "Jordan Poole"
      ],
      "mentioned_text": [
        "Ajay",
        "Poole"
      ],
      "sentiment": "pos",
      "confidence": 0.7,
      "sentiment_player": "Ajay",
      "attributed_player": "Ajay Mitchell",
      "fan_team": "Oklahoma City Thunder",
      "score": 1
    }
    + body, created_utc, link_id …

What the numbers mean

MetricDefinitionHow it's computed
Negative rateThe share of a player's comments that were negative.neg_count / comment_count
Positive rateThe share that were positive.pos_count / comment_count
Net sentimentPraise minus criticism, from −1 to +1. One figure for where r/NBA stands overall.(pos_count - neg_count) / comment_count
PolarizationThe share that took a side either way. High means strong opinions.(pos_count + neg_count) / comment_count

Why four? One rate tells you one thing. Chet Holmgren and Naz Reid are praised at nearly the same rate, and that is the only thing their numbers share: the comments around that praise split differently, and a different metric is needed to see it.

Chet Holmgren

Positive rate19.8%
Negative rate50.2%
Net sentiment-30.5
Polarization70.0%
Comments28,500

Naz Reid

Positive rate20.1%
Negative rate30.2%
Net sentiment-10.2
Polarization50.3%
Comments5,719

The positive rate says how much praise a player draws and the negative rate how much criticism; neither says anything about the other. Net sentiment puts the two together, praise minus criticism, one figure for where r/NBA stands on a player overall. Polarization sets the neutral comments aside and asks how much of the conversation took a side at all.

How a comment is read

Whose comment is it

Names are found in the comment before the classifier sees it. After it answers, one rule decides who the comment counts for: one name, that player; several names, whichever tracked player the classifier names; otherwise nobody. Of 2,059,495 usable comments, 1,787,520 count for exactly one player and 271,975 for nobody.

Every case the rule can produce
Every case the attribution rule can produce
CaseCommentNames foundClassifier's pCounts for
No tracked name5,172,993 downloaded comments, plus the deleted and removed ones.nonenever askedNever classified
One nameI never would have guessed like three years ago that a Trae Young trade would net the Hawks zero draft capital.Jan 8, 2026 · ▲ 11,766 · Source ↗

One name found, and the classifier agrees.

Trae Young"Trae Young"Trae Young
One name, the classifier names someone elseWhy are the warriors so awful at handling this stuff? Lol Steph has carried this org for too long man he deserves betterJan 21, 2026 · ▲ 4,315 · Source ↗

One name always wins. The classifier blamed the front office; the rule counts it against the one player it found.

Stephen Curry"Golden State Warriors Organization"Stephen Curry
Several names, the classifier names oneJust feels like a smarter player. Poole will probably have higher highs but Ajay feels more consistentMay 12, 2026 · ▲ 1 · Source ↗

Two names found; p picks one of them, as a nickname, and the name list resolves it.

Ajay MitchellJordan Poole"Ajay"Ajay Mitchell
Several names, no pickLamelo and Ant are going to be insanely entertaining Jun 25, 2026 · ▲ 9,119 · Source ↗

The classifier won’t say who it’s about, so the comment counts for no one.

LaMelo BallAnthony EdwardsnullNobody
Several names, the pick is a tracked player not in the textYear 23. Crazy how Coop or Wemby wasn’t even born when he got drafterNov 19, 2025 · ▲ 1,379 · Source ↗

Neither found name is the subject. “Year 23” is LeBron, and the classifier says so; he is tracked, so it counts for him.

Cooper FlaggVictor Wembanyama"LeBron James"LeBron James
Several names, the pick resolves to nobodyJaylen Brunson is officially a Knicks legend. 45 points to win the Championship. The most points by a Knick in Finals history. Jun 14, 2026 · ▲ 10,644 · Source ↗

The commenter blended two names; p repeats the blend, and no list resolves it.

Jaylen BrownJalen Brunson"Jaylen Brunson"Nobody

The prompt

The entire instruction, word for word. There is no system prompt and no examples. Every comment gets the same lines.

claude-haiku-4-5-20251001temperature 0max 75 tokensprompt v2-production+s-hint
Classify sentiment toward NBA players.Slang: nasty/sick/filthy=positive, washed/brick/fraud/cooked=negative, GOAT=positive.A trailing "/s" tags the comment as sarcasm. Comment: {comment_body} Respond ONLY with JSON: {"s":"pos|neg|neu","c":0.0-1.0,"p":"Player Name"|null}

What comes back

Three keys, and one of them is a number the model gives about itself.

What c is

The model's own estimate of how sure it is, from 0.0 to 1.0. It isn't a measured probability, and nothing checks it.

Where it's used

Once. A positive or negative comment needs c ≥ 0.9 before it can be quoted on a player page.

Where it isn't

The rates. Every usable comment counts once, whatever c came back as.

Reads

Answers from the season, as they stand in the data.

Exhibit 01Negative.CHI flair
#THEY REALLY GAVE CHET THE MAX 🤣🤣🤣 Type of guy to shoot 2 shots in a Game 7. Fucking embarrassing.
{"s":"neg", "c":0.9, "p":"Chet Holmgren"}counts for Chet Holmgren

Mockery in capitals, and a box-score line as the insult. The name is in capitals too and still matches.

Post · THE OKLAHOMA CITY THUNDER HAVE BEEN ELIMINATED FROM 2026 NBA CHAMPIONSHIP CONTENTION▲ 15,367May 31, 2026Source ↗
Exhibit 02Positive.CHA flair
Champagnie was Undrafted out of college and he is playing like 20 minutes a game in the WCF making league minimum money. That’s fucking crazy.
{"s":"pos", "c":0.85, "p":"Champagnie"}counts for Julian Champagnie

Admiration for a minimum-salary player. The answer names him by surname only, and the name list resolves it.

Post · THE OKLAHOMA CITY THUNDER HAVE BEEN ELIMINATED FROM 2026 NBA CHAMPIONSHIP CONTENTION▲ 14,595May 31, 2026Source ↗
Exhibit 03Positive.LAL flair
Incredibly common Hali W
{"s":"pos", "c":0.75, "p":"Tyrese Haliburton"}counts for Tyrese Haliburton

Four words. “W” is the whole verdict, and “Hali” is one of Haliburton’s names.

Post · Tyrese Haliburton: Alex Pretti was murdered.▲ 11,328Jan 25, 2026Source ↗
Exhibit 04Neutral.LAL flair
LeBron James will not sign with the Memphis Grizzlies.
{"s":"neu", "c":0, "p":null}counts for LeBron James

A statement of fact. Neutral, and the classifier names nobody; with one name in the comment it still counts for LeBron, as neutral. Neutral answers come back at 0.0 or 0.5 by habit.

Post · LeBron on playing the Grizzlies: “I’m f***ing 41 years of age. You think I want to do sh** in Memphis on a random Thursday? I’m not the first guy in the NBA to talk about this. You guys got to move the team… go over to Nashville already.”▲ 14,040Apr 2, 2026Source ↗
Exhibit 05Negative.LAC flair
Giddey is going to have that hanging over his head his whole career.
{"s":"neg", "c":0.8, "p":"Josh Giddey"}counts for Josh Giddey

No insult word anywhere. The negative is the implication.

Post · Josh Giddey gets into an argument with fan that called him a p*do: “You’re making jokes you don’t know sh*t about.”▲ 12,789Nov 29, 2025Source ↗
Exhibit 06Neutral.DEN flair
Shai “Quick Andy’s Coming” Gilgeous-Alexander
{"s":"neu", "c":0.5, "p":"Shai Gilgeous-Alexander"}counts for Shai Gilgeous-Alexander

A mock nickname inside his real one. The classifier read it as neutral; a fan would call it a jab. That is the kind of miss the check by hand measures.

Post · [Highlight] Shai draws a questionable foul on De'Aaron Fox▲ 12,533May 25, 2026Source ↗

Where it slips

Answers that a careful read disagrees with. The hand label is a read under a rubric, not the truth; here the two differ.

Where the classifier slips: the answer beside the hand label
CommentThe answerRead by handWhat happened
You've clearly never watched lamelo playApr 14, 2026 · ▲ 15 · Source ↗

{"s":"neu", "c":0.5, "p":"LaMelo Ball"}counts for LaMelo Ballpositive · LaMelo Ball

Quiet approval. A defense of LaMelo against a knock, with no praise word in it, read as neutral. The prompt never says what counts as positive.

Lu Dort really is an inspiration. Despite his clumsiness, he has managed to climb to the top echelon of one of the most athletic leagues in the world. Apr 25, 2026 · ▲ 123 · Source ↗

{"s":"pos", "c":0.85, "p":"Lu Dort"}counts for Lu Dortnegative · Lu Dort

Sarcasm with no tell. The thread, where Dort has just tripped Booker, gives it away; the classifier only sees the comment.

Can’t believe KAT was being compared to those other centers the spurs played in the playoffs like he’ll just be a non factor vs WembyJun 4, 2026 · ▲ 8 · Source ↗

{"s":"neg", "c":0.85, "p":"Karl-Anthony Towns"}counts for Karl-Anthony Townspositive · Karl-Anthony Towns

The doubters quoted. “Non factor” is their word, and the comment pushes back on it; the classifier took it as the verdict and counted it against Towns.

Before a comment is quoted

A positive or negative comment with c ≥ 0.9 can be quoted on a player page, but only after a second, larger model (claude-sonnet-5) reads it and names who the opinion is aimed at. Both of these passed every rule above.

Before a comment is quoted: the verifier's answer
CommentThe answerCounts forThe check says
They traded Luka for Marvin BagleyFeb 4, 2026 · ▲ 8,405 · Source ↗

{"s":"neg", "c":0.9, "p":"Luka Doncic"}Luka Doncicseveral names, the classifier names oneNot a player · not quoted

The scorn is for the trade, not for Luka. The verifier answers null: aimed at a decision, not a player.

The closeup of him, grabbing Jokic after he ran up the floor, looking completely unbothered, goes hard as hell. Jaden’s having an all-time walk the talk series Apr 26, 2026 · ▲ 1,559 · Source ↗

{"s":"pos", "c":0.9, "p":"Jaden"}Nikola Jokicone name, the classifier names someone elseNot him: Jaden McDaniels · not quoted

The praise is for Jaden McDaniels, who is not tracked; the only tracked name in the comment is Jokić, so the rule counts it for him. The verifier names McDaniels.

The verifier's prompt
claude-sonnet-5prompt v1max 75 tokensthinking {"type":"disabled"}
This r/NBA comment was labeled {sentiment_word}. Is that {sentiment_word} sentiment aimed at an NBA player, or at a team, front office, coach, referees, a decision, or a play? If at a player, name them; otherwise answer null.
The target is the player being praised or criticized - not a player who is merely mentioned, sympathized with, or the subject of someone else's decision.
Never name a player who does not appear in the comment.

Comment: {comment_body}

Respond ONLY with JSON: {"t":"Player Name"|null,"c":0.0-1.0}

Checked by hand

68.6%± 5.0agree on the sentimentof 1,000 drawn
95.4%± 2.9agree on the playerof 509 scored
66.0%± 5.0agree on bothdrawn 2026-09-24

A blind random draw of 1,000 counted comments, each read and labeled under a written rubric without the classifier's answer in view; 509 were scored. The margins are at 95%. A label is a careful read, not the truth: where the two disagree, the page says so, and never says which is right.

Why positive runs low. The prompt never says what counts as positive, so mild approval reads as neutral. The LaMelo Ball comment under Where it slips is the pattern: praise with no praise word in it.

What it cannot say. The check is across every player together. It says nothing about any one player's rate, and nothing about a single comment.

Per class, the groups and the draw
ClassClassifier saidLabels saidPrecisionRecall
Negative19418870.9%78.2%
Neutral16414261.3%66.5%
Positive15117975.5%61.8%
GroupSizeWeightLabeledScoredSentimentPlayerBoth
first3500.3535033680.7%98.5%79.2%
ordered6290.6518017361.8%93.2%59.0%
held out210201947.4%100.0%47.4%
rejected
21 rows set aside before scoring
rubric
v1
seed
11
drawn
2026-09-24
needed context
7.1% of labels
unsure
4.5%

The rules

MinimumCommentsWhere it applies
The official minimum5,000A player's place on the leaderboard and a bar in the race. 67 players clear it; the slider lets you lower it, and says so.
A fanbase on a roster200A row in the grudges and flowers lists, a cell in the grid.
A week30A point on a player's season line.
The belt300A week's title for most hated and most loved.
A game20A game's verdict on a player, in his game thread.
Entry to the race500A player's bar appears once his comments reach it.

Receipts. The comments quoted on a player page are the top 10 by score among his positive and negative comments at c ≥ 0.9, up to 500 characters, after the quote check. The check reached 99.9% of the candidates; 77.7% of them were about the player they count for, and only those are shown.

What this is not

  • Sentiment is not hate. A box-score criticism and a personal attack both register as negative. The rates measure the tone of the conversation, not hostility.
  • Every comment weighs the same. A comment with 15,367 upvotes counts once, the same as one with 1. Viral threads carry no extra weight.
  • Flair is a sample. 1,244,249 of the 2,059,495 usable comments carry a team flair. The fanbase views are about those commenters only, and the thinnest fanbase (New Orleans Pelicans) is 8,065 comments.
  • Small samples move. Under the minimums above, one viral thread can swing a rate. That is why the minimums exist and why the slider says so.
  • One subreddit, one season. r/NBA is not the NBA audience, and 2025-26 is not any other year.

Use the data

Comments move left to right and down. The gold line is the funnel, 7,283,478 downloaded to 1,787,520 counted; reference data and media skip classification. The green dashed lines are the two publish paths. GitHub Actions is one more reader of the public data, so the site is built from what was published, never from a laptop.

Everything the site shows is read from one folder of Parquet files at a public URL. The manifest says what was published and under which rules; the schema says every table's columns, types and what may be null.

The leaderboard, from your terminal (DuckDB; the line selects whole on a click):

duckdb -c "SELECT attributed_player, neg_rate, comment_count FROM 'https://courtsentiment.com/data/season=2025-26/player_overall.parquet' WHERE comment_count >= 5000 ORDER BY neg_rate DESC LIMIT 10"

Versions

config players 4.6 · teams 2.3 · season 3.0 · recaps 1.1 · method_examples 2.0sentiment claude-haiku-4-5-20251001 · prompt v2-production+s-hinttarget claude-sonnet-5 · prompt v1snapshots games fetched at 2026-09-12 · posts processed at 2026-10-08 · download daily processed at 2026-10-11schema v13 · generated 2026-10-15T00:27:30.444250+00:00

Star on GitHub