Pular para o conteúdo

Análise de sentimento no Twitter em Python

A análise de sentimento no Twitter classifica cada tweet como positivo, negativo ou neutro com um modelo de pontuação. Em 12,3 mil tweets rotulados por pessoas, um modelo RoBERTa treinado com tweets acertou 72,3%; as regras populares do VADER acertaram 53,0%.

Resposta curta: Colete uma amostra de tweets com uma consulta de busca e depois pontue cada um: um modelo transformer é o pontuador mais preciso, e o VADER o mais rápido. A API oficial do X cobra US$ 5,00 por 1.000 posts pela coleta. Com a Sorsa API, o POST /search-tweets devolve cerca de 20 tweets por requisição a partir de US$ 0,07 por 1.000, e 100 requisições grátis cobrem uma primeira execução de 2.000 tweets.

Endpoint
POST /search-tweets
Tamanho da página
cerca de 20 tweets por requisição
Preço
a partir de US$ 0,07 por 1.000

#Como funciona a análise de sentimento no Twitter

A análise de sentimento lê o texto de um tweet e devolve um de três rótulos, em geral com uma pontuação de confiança, e depois conta os rótulos em algumas centenas ou alguns milhões de tweets para medir o que as pessoas sentem sobre um assunto. Todo projeto segue os mesmos cinco passos:

  1. Colete os tweets que mencionam o assunto, com uma consulta de busca e uma janela de datas.

  2. Limpe o texto: substitua @menções e links, descarte retweets e cópias.

  3. Pontue cada tweet com um modelo: positivo, neutro ou negativo.

  4. Confira o modelo em algumas centenas de tweets que você mesmo rotulou.

  5. Agregue os rótulos em um número por dia, por produto ou por conta.

    1 O tweet, como coletado @nadia_reviews_gear que ótimo, a atualização quebrou o Bluetooth DE NOVO https://t.co/k3v9q2 2 Limpo para o modelo @user que ótimo, a atualização quebrou o Bluetooth DE NOVO http Maiúsculas e pontuação ficam. 3 O RoBERTa pontua Negativo 86.0% Neutro 12.5% Positivo 1.5% 4 Rotule e depois conte negativo “que ótimo” lido como sarcasmo Sentimento líquido do dia: % positivo menos % negativo
    O modelo pontua cada tweet por conta própria; o número que você relata vem da soma dos rótulos.

As marcas usam a análise nas menções depois de um lançamento ou de uma queda, as equipes de suporte nas respostas aos seus posts, os analistas num ticker ou num token, e os pesquisadores num debate ou numa eleição. Ela mede para onde uma multidão pende, não o que uma pessoa quis dizer: um modelo lê as palavras, então sarcasmo e tweets ambíguos ("great camera, awful battery") são onde ele mais falha.

Duas decisões moldam o resultado mais do que qualquer outra coisa: quais tweets você coleta e em qual pontuador você confia. As próximas seções tratam delas nessa ordem.

#Pegue os tweets com a Sorsa API

Para a etapa de coleta, use a Sorsa API, uma API e scraper do Twitter (X): uma requisição de busca devolve cerca de 20 tweets com toda a sintaxe de busca do X, a partir de US$ 0,07 por 1.000 tweets, a 20 requisições por segundo em todos os planos. Você precisa de uma chave de API e de nenhuma conta de desenvolvedor do X, e a Sorsa API nunca pede um login do X, então nenhuma conta sua corre risco.

Escolha o endpoint pela pergunta que você faz:

  1. Pegue uma chave. Cadastre-se e copie a sua chave de API no painel. As primeiras 100 requisições são grátis, sem cartão.

  2. Escreva a consulta. Dê forma à amostra antes de pagar por ela: lang:en mantém um idioma para um modelo em inglês, -filter:retweets descarta cópias, -from: deixa de fora os posts da própria marca, e since: com until: fixa a janela. A nossa lista de operadores de busca do Twitter tem o resto, e a ferramenta grátis Busca avançada do Twitter mostra o que uma consulta devolve antes de você escrever código.

  3. Envie uma requisição de teste. Uma requisição devolve cerca de 20 tweets e um cursor para a página seguinte. Um cursor é um token que aponta para a próxima página de resultados.

    Terminal
    curl -X POST "https://api.sorsa.io/v3/search-tweets" \
      -H "ApiKey: YOUR_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{"order": "latest",
           "query": "\"battery life\" headphones lang:en -filter:retweets"}'
    
    Response200 OK
    {
      "tweets": [
        {
          "id": "2116943508275302411",
          "full_text": "Two full days of battery on these headphones",
          "created_at": "2026-11-01T18:42:09Z",
          "lang": "en",
          "is_reply": false,
          "likes_count": 31,
          "reply_count": 4,
          "retweet_count": 2,
          "user": {
            "id": "1834470112963551232",
            "username": "nadia_reviews_gear",
            "followers_count": 2318
          }
        }
      ],
      "next_cursor": "DAADDAABCgABHWAk1xBVYAoKAAIdYCTSHxWQ"
    }
    
  4. Reúna as páginas numa tabela. Devolva o next_cursor até ele voltar vazio e guarde uma linha por ID de tweet. Um 429 significa mais de 20 requisições em um segundo, então espere e tente de novo; um 403 significa chave ausente ou sem requisições.

    Python
    import time
    
    import pandas as pd
    import requests
    
    URL = "https://api.sorsa.io/v3/search-tweets"
    HEADERS = {"ApiKey": "YOUR_API_KEY"}
    
    
    def collect(query, limit=2000):
        body = {"query": query, "order": "latest"}
        rows = {}
        while len(rows) < limit:
            r = requests.post(URL, headers=HEADERS, json=body, timeout=30)
            if r.status_code == 429:
                time.sleep(1)
                continue
            r.raise_for_status()
            page = r.json()
            for t in page.get("tweets", []):
                rows[t["id"]] = {
                    "id": t["id"],
                    "created_at": t["created_at"],
                    "text": t["full_text"],
                    "lang": t.get("lang"),
                    "is_reply": t.get("is_reply", False),
                    "likes": t.get("likes_count", 0),
                    "author": t["user"]["username"],
                }
            if not page.get("next_cursor"):
                break
            body["next_cursor"] = page["next_cursor"]
        return pd.DataFrame(rows.values())
    
    
    df = collect('"battery life" headphones lang:en -filter:retweets')
    print(len(df), "tweets")
    

Quanto custam os tweets

Na Sorsa API uma amostra de sentimento custa a partir de US$ 0,07 por 1.000 tweets pela busca; a API oficial do X cobra US$ 5,00 por 1.000 leituras de posts.

Tweets a analisar

API oficial do X

US$ 500

para 100 mil tweets

US$ 0,005 por post

Sorsa API

a partir deUS$ 7

para 100 mil tweets

a partir de US$ 0,07 por 1.000

Na API oficial do X a conta também cresce com os autores: a partir de 22 de novembro de 2026, o X cobra o perfil devolvido com cada post como uma leitura de usuário, US$ 0,010 a mais por post (aviso do X (abre em uma nova aba)), e o plano de pagamento por uso dela para em 3 milhões de leituras de posts por mês (lista de preços do X (abre em uma nova aba)). Na Sorsa API todo tweet traz o perfil completo do autor, e requisições com falha nunca são cobradas.

As páginas de uma consulta vêm uma depois da outra, porque cada uma precisa do cursor da anterior. Para uma amostra grande, divida a janela em dias e rode os dias lado a lado, até 20 requisições por segundo com uma chave. A mesma busca volta até 2006, o que o nosso guia de dados históricos do Twitter cobre para séries temporais longas.

#Limpe os tweets do jeito que o modelo espera

Limpe menos do que a maioria dos tutoriais: substitua @menções por @user e links por http, descarte retweets e cópias exatas, e mantenha emojis, letras maiúsculas e pontuação. O modelo RoBERTa foi treinado com texto preparado exatamente assim, e o VADER lê maiúsculas, pontos de exclamação e emojis como sentimento mais forte.

Python
import re


def prepare(text):
    text = re.sub(r"@\w+", "@user", text)
    return re.sub(r"https?://\S+", "http", text)


df = df[df["lang"] == "en"]
df = df[~df["text"].str.startswith("RT @")]
df["clean"] = df["text"].map(prepare)
df = df.drop_duplicates(subset="clean")

As cópias exatas importam mais do que parece: sorteios e campanhas de bots publicam a mesma frase centenas de vezes, e uma única campanha pode virar a pontuação de um dia. Para quase-duplicatas e um conjunto de referência com rótulos manuais, o nosso guia para montar um dataset do Twitter para machine learning tem o código.

Bom saber

A regex de limpeza que muitos tutoriais copiam, [^a-zA-Z0-9\s], apaga todos os emojis e todos os pontos de exclamação. Os dois carregam sentimento: nos exemplos do próprio VADER, uma linha com três emojis e nenhuma outra palavra de opinião pontua +0,70.

#Quatro jeitos de pontuar sentimento, testados em 12,3 mil tweets

No conjunto de teste de sentimento do TweetEval, 12,3 mil tweets que pessoas rotularam como positivos, neutros ou negativos, o modelo RoBERTa acertou 72,3%, uma regressão logística treinada com 45,6 mil tweets rotulados 59,6%, o VADER 53,0% e o TextBlob 48,3%. Rodamos os quatro em 2 de novembro de 2026, em 4 threads de CPU; a tabela traz as pontuações completas.

MétodoAcuráciaRecall macroChamados de positivos (pessoas: 19,3%)Tweets por segundo
RoBERTa (cardiffnlp, latest)72,3%73,4%20,0%7
TF-IDF + regressão logística59,6%60,1%21,1%34,0 mil
VADER, faixa de ±0,0553,0%57,0%38,9%27,6 mil
TextBlob, sinal da polaridade48,3%49,4%37,2%6.867
  • RoBERTa (cardiffnlp, latest)

    Acurácia
    72,3%
    Recall macro
    73,4%
    Chamados de positivos (pessoas: 19,3%)
    20,0%
    Tweets por segundo
    7
  • TF-IDF + regressão logística

    Acurácia
    59,6%
    Recall macro
    60,1%
    Chamados de positivos (pessoas: 19,3%)
    21,1%
    Tweets por segundo
    34,0 mil
  • VADER, faixa de ±0,05

    Acurácia
    53,0%
    Recall macro
    57,0%
    Chamados de positivos (pessoas: 19,3%)
    38,9%
    Tweets por segundo
    27,6 mil
  • TextBlob, sinal da polaridade

    Acurácia
    48,3%
    Recall macro
    49,4%
    Chamados de positivos (pessoas: 19,3%)
    37,2%
    Tweets por segundo
    6.867
Rotulados certo, de 12,3 mil tweets rotulados por pessoas RoBERTa (Cardiff NLP) modelo treinado com 124 mi de tweets 72.3% TF-IDF + regressão logística treinada com 45,6 mil tweets rotulados 59.6% VADER lista de palavras e regras, faixa ±0,05 53.0% TextBlob léxico de adjetivos, sinal da polaridade 48.3% chamar todo tweet de neutro: 48,3%
O modelo treinado com tweets vence por uma boa margem. O VADER e o TextBlob são instantâneos, mas erram cerca de metade dos rótulos.

A acurácia é a parcela de tweets rotulados do mesmo jeito que as pessoas os rotularam. Para ter uma escala, chamar todos os tweets de neutros dá 48,3%, porque quase metade dos tweets de teste é neutra, então o VADER acrescenta menos de 5 pontos sobre não fazer nada. O recall macro é a pontuação do próprio TweetEval: a média de quantos tweets negativos, neutros e positivos cada método encontrou, de modo que um método não ganha chamando tudo de neutro. Duas ressalvas: o modelo RoBERTa foi ajustado na divisão de treino do TweetEval, então este teste é o campo de casa dele, e a regressão logística aprendeu da mesma divisão. No seu próprio assunto, espere que ambos percam alguns pontos e confira-os como diz o passo 4. As velocidades vêm de um servidor compartilhado de 4 núcleos que estava ocupado com outros trabalhos, então trate-as como um piso.

RoBERTa: o mais preciso

O modelo twitter-roberta-base-sentiment-latest (abre em uma nova aba) da Cardiff NLP é um modelo RoBERTa treinado com cerca de 124 milhões de tweets de 2018 a 2021 e depois ajustado para três rótulos. Ele roda numa CPU comum e não precisa de chave de API; na velocidade que medimos num servidor ocupado, 10 mil tweets levam cerca de 23 minutos, então rode-o em lotes durante a noite ou numa GPU para amostras grandes.

Python
from transformers import pipeline

scorer = pipeline(
    "sentiment-analysis",
    model="cardiffnlp/twitter-roberta-base-sentiment-latest",
)
out = scorer(df["clean"].tolist(), batch_size=32, truncation=True)
df["label"] = [o["label"] for o in out]
df["confidence"] = [round(o["score"], 3) for o in out]
Output
positive 0.978  Battery life on these headphones is great, two full days
positive 0.859  Oh great, another update that breaks Bluetooth. Love ...
neutral  0.789  The firmware update rolls out to all devices on Monday.
positive 0.960  not bad at all tbh, @user was right http
negative 0.860  @user oh great, the update broke Bluetooth AGAIN http

Para tweets em outros idiomas, o modelo twitter-xlm-roberta-base-sentiment (abre em uma nova aba) da mesma equipe foi treinado com cerca de 198 milhões de tweets e ajustado em 8 idiomas, entre eles espanhol, português, francês e árabe. Para emoções em vez de polaridade, o modelo de emoções deles devolve 11 rótulos, como raiva, medo e alegria.

VADER: regras instantâneas, uma faixa neutra fraca

O VADER é uma lista de cerca de 7.500 palavras pontuadas mais regras para maiúsculas, pontos de exclamação, "but" e negação, feita para redes sociais. Ele pontuou cerca de 27,6 mil tweets por segundo num único núcleo, o que o torna uma boa primeira olhada em um milhão de tweets. O ponto fraco dele é a faixa neutra: chamou 38,9% dos tweets de teste de positivos, o dobro dos 19,3% das pessoas.

Python
from vaderSentiment.vaderSentiment import SentimentIntensityAnalyzer

vader = SentimentIntensityAnalyzer()


def vader_label(text, band=0.05):
    c = vader.polarity_scores(text)["compound"]
    if c >= band:
        return "positive"
    return "negative" if c <= -band else "neutral"


df["vader"] = df["text"].map(vader_label)
TweetVADER (compound)RoBERTa
Battery life on these headphones is great, two full dayspositivo (+0,62)positivo (0,98)
Oh great, another update that breaks Bluetooth. Love that for me.positivo (+0,85)positivo (0,86)
The firmware update rolls out to all devices on Monday.neutro (+0,00)neutro (0,79)
not bad at all tbh, @kai_builds_tools was right https://t.co/x1y2z3 (abre em uma nova aba)positivo (+0,43)positivo (0,96)
@nadia_reviews_gear oh great, the update broke Bluetooth AGAIN https://t.co/k3v9q2 (abre em uma nova aba)positivo (+0,32)negativo (0,86)
  • Battery life on these headphones is great, two full days

    VADER (compound)
    positivo (+0,62)
    RoBERTa
    positivo (0,98)
  • Oh great, another update that breaks Bluetooth. Love that for me.

    VADER (compound)
    positivo (+0,85)
    RoBERTa
    positivo (0,86)
  • The firmware update rolls out to all devices on Monday.

    VADER (compound)
    neutro (+0,00)
    RoBERTa
    neutro (0,79)
  • not bad at all tbh, @kai_builds_tools was right https://t.co/x1y2z3 (abre em uma nova aba)

    VADER (compound)
    positivo (+0,43)
    RoBERTa
    positivo (0,96)
  • @nadia_reviews_gear oh great, the update broke Bluetooth AGAIN https://t.co/k3v9q2 (abre em uma nova aba)

    VADER (compound)
    positivo (+0,32)
    RoBERTa
    negativo (0,86)

O sarcasmo derrota os dois pontuadores algumas vezes. Os dois leem "Love that for me" como elogio; o RoBERTa percebeu o sarcasmo no último tweet, onde o VADER viu "great" e o pontuou como positivo.

Regressão logística: treine com os seus próprios rótulos

Um modelo TF-IDF com regressão logística aprende com tweets que você mesmo rotula, então se ajusta às palavras do seu assunto: "sick" numa thread de tênis, "bullish" numa de cripto. Treinado com 45,6 mil tweets do TweetEval em 13 segundos, chegou a 59,6%. Compensa quando você tem alguns milhares de rótulos e um vocabulário que os modelos gerais não conhecem.

Python
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.linear_model import LogisticRegression
from sklearn.pipeline import make_pipeline

model = make_pipeline(
    TfidfVectorizer(ngram_range=(1, 2), min_df=2,
                    sublinear_tf=True),
    LogisticRegression(max_iter=2000,
                       class_weight="balanced"),
)
model.fit(train_texts, train_labels)
df["lr"] = model.predict(df["clean"])

O TextBlob, o quarto método, pontua um léxico de adjetivos em inglês que os autores dele testaram em críticas de filmes, e só chama um tweet de neutro quando a polaridade é exatamente zero. Ele fez 48,3%, o mesmo que chamar todos os tweets de neutros, então não acrescenta nada em tweets. Um modelo de linguagem grande é uma quinta opção: com o tweet e os três rótulos no prompt, ele pode captar sarcasmo que as listas de palavras perdem, mas custa dinheiro por tweet e pode responder diferente numa nova execução. Confira-o com a mesma amostra rotulada à mão antes de confiar nele num dataset inteiro.

#A faixa neutra decide a sua manchete

Com o VADER, o limiar que você escolhe move o resultado mais do que os tweets. Na faixa de ±0,05 da documentação do VADER, ele chama 38,9% dos tweets de teste de positivos; amplie a faixa para ±0,45 e a parcela de positivos cai para 21,4% enquanto a acurácia sobe para 58,1%. Mova o controle deslizante para ver cada passo.

-0.05 a +0.05
53.0% de 12.3K tweets rotulados corretamente
38.9% chamados de positivos, contra 19.3% pelas pessoas
Positivo 38.9%
Neutro 31.3%
Negativo 29.8%

Barras: a parcela do VADER em cada rótulo. Linha: a parcela dada por avaliadores humanos. Conjunto de teste de sentimento TweetEval, 12.3K tweets, pontuados em Nov 2, 2026.

Os mesmos 12.3K tweets, pontuados uma vez pelo VADER; só a faixa neutra muda.

Relate o método e o limiar com cada número que publicar, e nunca compare parcelas de dois pontuadores diferentes. Se você usar o VADER, ajuste a faixa em algumas centenas de tweets do seu próprio assunto que você rotulou à mão.

#Transforme rótulos em um índice que você possa acompanhar

O número que a maioria das equipes acompanha é o sentimento líquido: a parcela de tweets positivos menos a de negativos, de -100 a +100. Calcule-o por dia e deixe de fora os dias com menos de cerca de 100 tweets, em que um punhado de posts pode virar o índice.

Python
df["day"] = pd.to_datetime(df["created_at"]).dt.date
shares = pd.crosstab(df["day"], df["label"], normalize="index")
daily = pd.DataFrame({
    "tweets": df.groupby("day").size(),
    "net": ((shares["positive"] - shares["negative"]) * 100).round(1),
})
print(daily[daily["tweets"] >= 100])

Mantenha separadas as respostas e os posts originais (o campo is_reply), porque as reclamações se concentram nas respostas aos posts da própria marca. Pondere os tweets por curtidas só de propósito, e diga isso ao lado do gráfico. Para manter o índice atualizado, rode a coleta em intervalos regulares com since: definido como a última execução; o nosso guia de monitoramento do Twitter em tempo real cobre o polling em escala.

#Faça hoje a sua primeira análise de sentimento

Colete alguns milhares de tweets sobre o seu assunto com o POST /search-tweets da Sorsa API, cerca de 20 por requisição a partir de US$ 0,07 por 1.000, pontue-os com o modelo RoBERTa e confira os rótulos em 200 tweets seus. As 100 requisições grátis de uma conta nova cobrem os primeiros 2.000 tweets.

#FAQ

Qual é a precisão da análise de sentimento no Twitter?

Depende do modelo. Em 12,3 mil tweets rotulados por pessoas (o conjunto de teste do TweetEval), o modelo RoBERTa da Cardiff NLP rotulou 72,3% corretamente, uma regressão logística treinada com 45,6 mil tweets 59,6%, o VADER 53,0% e o TextBlob 48,3%. Sarcasmo, opiniões ambíguas e gírias do assunto causam a maioria dos erros, então confira qualquer modelo em algumas centenas de tweets do seu próprio assunto.

Como obtenho tweets para análise de sentimento?

Busque-os por uma API com uma consulta e uma janela de datas. O POST /search-tweets da Sorsa API aceita os operadores de busca do X, devolve cerca de 20 tweets por requisição com texto completo e autor, e custa a partir de US$ 0,07 por 1.000 tweets. A API oficial do X exige uma conta de desenvolvedor e cobra US$ 5,00 por 1.000 leituras de posts. Para um conjunto já rotulado para treinar, veja datasets públicos como o TweetEval.

Qual API do Twitter devo usar para análise de sentimento?

Use a Sorsa API para coletar os tweets: ela devolve cerca de 20 tweets por requisição de busca a partir de US$ 0,07 por 1.000, contra US$ 5,00 na API oficial do X, com toda a sintaxe de busca do X até 2006, uma chave de API e nenhuma conta de desenvolvedor, e 20 requisições por segundo em todos os planos. A pontuação então roda no seu próprio código, com o modelo que você escolher.

Dá para fazer análise de sentimento no Twitter de graça?

Sim, para um primeiro projeto. O VADER, o TextBlob e os modelos RoBERTa da Cardiff NLP são grátis e rodam num notebook. Para os tweets, toda conta nova da Sorsa API ganha 100 requisições grátis: cerca de 2.000 tweets pela busca, sem cartão, e elas nunca expiram. Conjuntos de referência rotulados, como o TweetEval, podem ser baixados de graça para testar um modelo.

Dá para analisar tweets em outros idiomas?

Sim, com um modelo multilíngue. O twitter-xlm-roberta-base-sentiment da Cardiff NLP foi treinado com cerca de 198 milhões de tweets e ajustado para sentimento em 8 idiomas, entre eles espanhol, português, francês e árabe. O VADER e o modelo RoBERTa em inglês leem só inglês, então filtre por idioma com o operador lang: na sua consulta e o campo lang de cada tweet.

A Sorsa API devolve uma pontuação de sentimento?

Não: a Sorsa API devolve os tweets, com texto completo, idioma, contagens de engajamento e autor, e a pontuação roda no seu código. Isso deixa a escolha do modelo com você, e você pode repontuar tweets antigos quando sair um modelo melhor. A Sorsa API se chamava TweetScout API até 2025; os endpoints de tweets e de busca funcionam do mesmo jeito.

#Como conferimos

Em 2 de novembro de 2026 baixamos os dados de sentimento do TweetEval do repositório da Cardiff NLP e pontuamos o conjunto de teste de 12,3 mil tweets com o VADER 3.3.2, o TextBlob 0.20.1, um modelo TF-IDF com regressão logística (scikit-learn 1.9.1) treinado nos 45,6 mil tweets de treino e o twitter-roberta-base-sentiment-latest (transformers 5.22.1, PyTorch 2.15 em 4 threads de CPU); as saídas de exemplo desta página vêm da mesma execução. Os formatos de requisição e resposta seguem a referência de API da Sorsa em produção, e os preços da API oficial do X vêm de docs.x.com, lido no mesmo dia.

Pela equipe da Sorsa API. Construímos e operamos a Sorsa API, a API e scraper somente leitura do Twitter (X), em produção desde 2022 (antiga TweetScout API), com mais de 6 bilhões de requisições atendidas. Sobre a Sorsa API

O que mudou
  • Reescrito: quatro métodos pontuados em 12,3 mil tweets rotulados por pessoas, um controle deslizante do limiar do VADER, o jeito de 2026 de coletar tweets, preços atuais da API do X.
  • Primeira publicação.