Análisis de sentimientos en Twitter con Python
El análisis de sentimientos en Twitter etiqueta cada tweet como positivo, negativo o neutral con un modelo de puntuación. En 12,300 tweets etiquetados por personas, un modelo RoBERTa entrenado con tweets acertó el 72.3%; las populares reglas de VADER acertaron el 53.0%.
Respuesta corta: Recopila una muestra de tweets con una consulta de búsqueda y puntúa cada uno: un modelo transformer es el que puntúa con más precisión, VADER el más rápido. La API oficial de X cobra $5.00 por 1,000 posts por la recopilación. Con Sorsa API, POST /search-tweets devuelve unos 20 tweets por solicitud desde $0.07 por 1,000, y las 100 solicitudes gratis cubren una primera ejecución de 2,000 tweets.
- Endpoint
POST /search-tweets- Tamaño de página
- unos 20 tweets por solicitud
- Precio
- desde $0.07 por 1,000
#Cómo funciona el análisis de sentimientos en Twitter
El análisis de sentimientos lee el texto de un tweet y devuelve una de tres etiquetas, normalmente con una puntuación de confianza, y luego cuenta las etiquetas en unos cientos o unos millones de tweets para medir qué siente la gente sobre un tema. Todo proyecto sigue los mismos cinco pasos:
-
Recopila los tweets que mencionan el tema, con una consulta de búsqueda y una ventana de fechas.
-
Limpia el texto: reemplaza las @menciones y los enlaces, elimina los retweets y las copias.
-
Puntúa cada tweet con un modelo: positivo, neutral o negativo.
-
Comprueba el modelo con unos cientos de tweets que etiquetaste tú mismo.
-
Agrega las etiquetas en un número por día, por producto o por cuenta.
El modelo puntúa cada tweet por separado; el número que reportas sale de sumar las etiquetas.
Las marcas lo aplican a las menciones después de un lanzamiento o una caída, los equipos de soporte a las respuestas a sus posts, los analistas a un ticker o un token, y los investigadores a un debate o una elección. Mide hacia dónde se inclina una multitud, no lo que quiso decir una persona: un modelo lee las palabras, así que el sarcasmo y los tweets mixtos ("great camera, awful battery") son donde más falla.
Dos decisiones pesan más que cualquier otra en el resultado: qué tweets recopilas y en qué puntuador confías. Las siguientes secciones las tratan en ese orden.
#Obtén los tweets con Sorsa API
Para el paso de recopilación, usa Sorsa API, una API y scraper de Twitter (X): una solicitud de búsqueda devuelve unos 20 tweets con toda la sintaxis de búsqueda de X, desde $0.07 por 1,000 tweets, a 20 solicitudes por segundo en todos los planes. Necesitas una clave API y ninguna cuenta de desarrollador de X, y Sorsa API nunca te pide un login de X, así que ninguna cuenta tuya corre riesgo.
Elige el endpoint según la pregunta que haces:
- Opinión sobre un tema, producto o marca:
POST /search-tweets(se abre en una pestaña nueva). - Lo que la gente dice a una cuenta o sobre ella, con un mínimo de likes o respuestas:
POST /mentions(se abre en una pestaña nueva), que cubre nuestra guía de la API de menciones de Twitter. - Reacciones bajo un post:
POST /comments(se abre en una pestaña nueva), las mismas respuestas que lee nuestra guía de cómo ver los comentarios en X. - IDs de tweets que ya tienes:
POST /tweet-info-bulk(se abre en una pestaña nueva), 100 tweets por solicitud, desde $0.014 por 1,000.
-
Consigue una clave. Regístrate y copia tu clave API del panel. Las primeras 100 solicitudes son gratis, sin tarjeta.
-
Escribe la consulta. Da forma a la muestra antes de pagarla:
lang:enconserva un solo idioma para un modelo en inglés,-filter:retweetselimina las copias,-from:deja fuera los posts de la propia marca, ysince:conuntil:fija la ventana. Nuestra lista de operadores de búsqueda de Twitter tiene el resto, y la herramienta gratuita de búsqueda avanzada de Twitter muestra lo que devuelve una consulta antes de que escribas código. -
Envía una solicitud de prueba. Una solicitud devuelve unos 20 tweets y un cursor a la página siguiente. Un cursor es un token que apunta a la página siguiente 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"}'Respuesta200 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" } -
Reúne las páginas en una tabla. Envía
next_cursorde vuelta hasta que llegue vacío, y conserva una fila por ID de tweet. Un 429 significa más de 20 solicitudes en un segundo, así que espera y reintenta; un 403 significa que falta la clave o que no quedan solicitudes.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")
Cuánto cuestan los tweets
En Sorsa API una muestra de sentimientos cuesta desde $0.07 por 1,000 tweets mediante búsqueda; la API oficial de X cobra $5.00 por 1,000 lecturas de posts.
API oficial de X
$500
para 100K tweets
$0.005 por post
Sorsa API
desde$7
para 100K tweets
desde $0.07 por 1,000
En la API oficial de X la factura además crece con los autores: a partir del 22 de noviembre de 2026, X cobra el perfil que llega con cada post como una lectura de usuario, $0.010 más por post (aviso de X (se abre en una pestaña nueva)), y su plan de pago por uso se detiene en 3 millones de lecturas de posts al mes (lista de precios de X (se abre en una pestaña nueva)). En Sorsa API cada tweet trae el perfil completo de su autor, y las solicitudes fallidas nunca se cobran.
Las páginas de una consulta llegan una tras otra, porque cada una necesita el cursor de la anterior. Para una muestra grande, divide la ventana en días y ejecuta los días en paralelo, hasta 20 solicitudes por segundo con una sola clave. La misma búsqueda llega hasta 2006, algo que nuestra guía de datos históricos de Twitter trata para series de tiempo largas.
#Limpia los tweets como espera el modelo
Limpia menos de lo que hacen la mayoría de los tutoriales: reemplaza las @menciones por @user y los enlaces por http, elimina los retweets y las copias exactas, y conserva los emojis, las mayúsculas y la puntuación. El modelo RoBERTa se entrenó con texto preparado exactamente así, y VADER lee las mayúsculas, los signos de exclamación y los emojis como un sentimiento más fuerte.
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")
Las copias exactas importan más de lo que parece: los sorteos y las campañas de bots publican la misma frase cientos de veces, y una sola campaña puede mover la puntuación de un día. Para los casi duplicados y un conjunto de referencia con etiquetas hechas a mano, nuestra guía para crear un dataset de Twitter para machine learning tiene el código.
Para tener en cuenta
La expresión regular de limpieza que copian muchos tutoriales,
[^a-zA-Z0-9\s], borra todos los emojis y todos los signos de exclamación. Ambos llevan sentimiento: en los propios ejemplos de VADER, una línea con tres emojis y ninguna otra palabra de opinión puntúa +0.70.
#Cuatro formas de puntuar el sentimiento, probadas en 12,300 tweets
En el conjunto de prueba de sentimientos de TweetEval, 12,300 tweets que personas etiquetaron como positivos, neutrales o negativos, el modelo RoBERTa acertó el 72.3%, una regresión logística entrenada con 45,600 tweets etiquetados el 59.6%, VADER el 53.0% y TextBlob el 48.3%. Ejecutamos los cuatro el 2 de noviembre de 2026, en 4 hilos de CPU; la tabla tiene las puntuaciones completas.
| Método | Precisión | Recall macro | Clasificados como positivos (personas: 19.3%) | Tweets por segundo |
|---|---|---|---|---|
| RoBERTa (cardiffnlp, latest) | 72.3% | 73.4% | 20.0% | 7 |
| TF-IDF + regresión logística | 59.6% | 60.1% | 21.1% | 34.0K |
| VADER, banda de ±0.05 | 53.0% | 57.0% | 38.9% | 27.6K |
| TextBlob, signo de la polaridad | 48.3% | 49.4% | 37.2% | 6,867 |
RoBERTa (cardiffnlp, latest)
- Precisión
- 72.3%
- Recall macro
- 73.4%
- Clasificados como positivos (personas: 19.3%)
- 20.0%
- Tweets por segundo
- 7
TF-IDF + regresión logística
- Precisión
- 59.6%
- Recall macro
- 60.1%
- Clasificados como positivos (personas: 19.3%)
- 21.1%
- Tweets por segundo
- 34.0K
VADER, banda de ±0.05
- Precisión
- 53.0%
- Recall macro
- 57.0%
- Clasificados como positivos (personas: 19.3%)
- 38.9%
- Tweets por segundo
- 27.6K
TextBlob, signo de la polaridad
- Precisión
- 48.3%
- Recall macro
- 49.4%
- Clasificados como positivos (personas: 19.3%)
- 37.2%
- Tweets por segundo
- 6,867
La precisión es la proporción de tweets etiquetados como los etiquetaron las personas. Para tener una escala, llamar neutral a todos los tweets da 48.3%, porque casi la mitad de los tweets de prueba son neutrales, así que VADER suma menos de 5 puntos frente a no hacer nada. El recall macro es la puntuación propia de TweetEval: el promedio de cuántos tweets negativos, neutrales y positivos encontró cada método, de modo que un método no puede ganar llamando neutral a todo. Dos salvedades: el modelo RoBERTa se ajustó con la partición de entrenamiento de TweetEval, así que esta prueba es su terreno, y la regresión logística aprendió de esa misma partición. En tu propio tema, espera que los dos pierdan unos puntos, y compruébalos como indica el paso 4. Las velocidades salen de un servidor compartido de 4 núcleos que estaba ocupado con otras tareas, así que tómalas como un mínimo.
RoBERTa: el más preciso
El modelo twitter-roberta-base-sentiment-latest (se abre en una pestaña nueva) de Cardiff NLP es un modelo RoBERTa entrenado con unos 124 millones de tweets de 2018 a 2021 y ajustado después para tres etiquetas. Funciona en una CPU normal y no necesita clave API; a la velocidad que medimos en un servidor ocupado, 10K tweets toman unos 23 minutos, así que para muestras grandes ejecútalo por lotes durante la noche o en una GPU.
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]
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 en otros idiomas, el modelo twitter-xlm-roberta-base-sentiment (se abre en una pestaña nueva) del mismo equipo se entrenó con unos 198 millones de tweets y se ajustó en 8 idiomas, entre ellos español, portugués, francés y árabe. Para emociones en lugar de polaridad, su modelo de emociones devuelve 11 etiquetas como ira, miedo y alegría.
VADER: reglas instantáneas, una línea neutral débil
VADER es una lista de unas 7,500 palabras puntuadas más reglas para mayúsculas, signos de exclamación, "but" y negación, hecha para redes sociales. Puntuó unos 27,600 tweets por segundo en un solo núcleo, lo que lo vuelve una buena primera mirada a un millón de tweets. Su punto débil es la banda neutral: llamó positivos al 38.9% de los tweets de prueba, el doble del 19.3% que marcaron las personas.
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)
| Tweet | VADER (compound) | RoBERTa |
|---|---|---|
| Battery life on these headphones is great, two full days | positive (+0.62) | positive (0.98) |
| Oh great, another update that breaks Bluetooth. Love that for me. | positive (+0.85) | positive (0.86) |
| The firmware update rolls out to all devices on Monday. | neutral (+0.00) | neutral (0.79) |
| not bad at all tbh, @kai_builds_tools was right https://t.co/x1y2z3 (se abre en una pestaña nueva) | positive (+0.43) | positive (0.96) |
| @nadia_reviews_gear oh great, the update broke Bluetooth AGAIN https://t.co/k3v9q2 (se abre en una pestaña nueva) | positive (+0.32) | negative (0.86) |
Battery life on these headphones is great, two full days
- VADER (compound)
- positive (+0.62)
- RoBERTa
- positive (0.98)
Oh great, another update that breaks Bluetooth. Love that for me.
- VADER (compound)
- positive (+0.85)
- RoBERTa
- positive (0.86)
The firmware update rolls out to all devices on Monday.
- VADER (compound)
- neutral (+0.00)
- RoBERTa
- neutral (0.79)
not bad at all tbh, @kai_builds_tools was right https://t.co/x1y2z3 (se abre en una pestaña nueva)
- VADER (compound)
- positive (+0.43)
- RoBERTa
- positive (0.96)
@nadia_reviews_gear oh great, the update broke Bluetooth AGAIN https://t.co/k3v9q2 (se abre en una pestaña nueva)
- VADER (compound)
- positive (+0.32)
- RoBERTa
- negative (0.86)
El sarcasmo vence a los dos puntuadores algunas veces. Los dos leen "Love that for me" como elogio; RoBERTa captó el sarcasmo del último tweet, donde VADER vio "great" y lo puntuó como positivo.
Regresión logística: entrénala con tus propias etiquetas
Un modelo TF-IDF con regresión logística aprende de tweets que etiquetas tú mismo, así que se ajusta a las palabras de tu tema: "sick" en un hilo de zapatillas, "bullish" en uno de cripto. Entrenado con 45,600 tweets de TweetEval en 13 segundos, llegó al 59.6%. Vale la pena cuando tienes unos miles de etiquetas y un vocabulario que los modelos generales no conocen.
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"])
TextBlob, el cuarto método, puntúa un léxico de adjetivos en inglés que sus autores probaron con reseñas de películas, y llama neutral a un tweet solo cuando su polaridad es exactamente cero. Obtuvo 48.3%, lo mismo que llamar neutral a todos los tweets, así que no aporta nada con tweets. Un modelo de lenguaje grande es una quinta opción: si le das el tweet y las tres etiquetas, puede captar el sarcasmo que las listas de palabras se pierden, pero cuesta dinero por tweet y puede responder distinto en una nueva ejecución. Compruébalo con la misma muestra etiquetada a mano antes de confiar en él para un dataset completo.
#La banda neutral decide tu titular
Con VADER, el umbral que eliges mueve el resultado más que los propios tweets. Con la banda de ±0.05 de la documentación de VADER, llama positivos al 38.9% de los tweets de prueba; si amplías la banda a ±0.45, la proporción de positivos baja al 21.4% mientras la precisión sube al 58.1%. Mueve el control deslizante para ver cada paso.
Barras: la proporción de VADER en cada etiqueta. Línea: la proporción que dieron los evaluadores humanos. Conjunto de prueba de sentimiento de TweetEval, 12.3K tweets, evaluado el 2 de nov de 2026.
Los mismos 12.3K tweets, evaluados una vez por VADER; solo cambia la banda neutra.
Reporta el método y su umbral con cada número que publiques, y nunca compares proporciones de dos puntuadores distintos. Si usas VADER, ajusta la banda con unos cientos de tweets de tu propio tema que hayas etiquetado a mano.
#Convierte las etiquetas en una puntuación que puedas seguir
El número que siguen la mayoría de los equipos es el sentimiento neto: la proporción de tweets positivos menos la de negativos, de -100 a +100. Cuéntalo por día y deja fuera los días con menos de unos 100 tweets, en los que un puñado de posts puede mover la puntuación.
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])
Mantén separadas las respuestas y los posts originales (el campo is_reply), porque las quejas se concentran en las respuestas a los posts de una marca. Pondera los tweets por likes solo a propósito, y dilo junto al gráfico. Para mantener la puntuación al día, ejecuta la recopilación con un horario y since: fijado en la última ejecución; nuestra guía de monitoreo de Twitter en tiempo real cubre el sondeo a escala.
#Haz hoy tu primer análisis de sentimientos
Recopila unos miles de tweets sobre tu tema con POST /search-tweets de Sorsa API, unos 20 por solicitud desde $0.07 por 1,000, puntúalos con el modelo RoBERTa y comprueba las etiquetas en 200 tweets tuyos. Las 100 solicitudes gratis de una cuenta nueva cubren los primeros 2,000 tweets.
#Preguntas frecuentes
¿Qué tan preciso es el análisis de sentimientos en Twitter?
Depende del modelo. En 12,300 tweets etiquetados por personas (el conjunto de prueba de TweetEval), el modelo RoBERTa de Cardiff NLP etiquetó correctamente el 72.3%, una regresión logística entrenada con 45,600 tweets el 59.6%, VADER el 53.0% y TextBlob el 48.3%. El sarcasmo, las opiniones mixtas y la jerga del tema causan la mayoría de los errores, así que comprueba cualquier modelo con unos cientos de tweets de tu propio tema.
¿Cómo obtengo tweets para un análisis de sentimientos?
Búscalos mediante una API con una consulta y una ventana de fechas. POST /search-tweets de Sorsa API acepta los operadores de búsqueda de X, devuelve unos 20 tweets por solicitud con texto completo y autor, y cuesta desde $0.07 por 1,000 tweets. La API oficial de X necesita una cuenta de desarrollador y cobra $5.00 por 1,000 lecturas de posts. Para un conjunto ya etiquetado con el que entrenar, mira datasets públicos como TweetEval.
¿Qué API de Twitter debo usar para el análisis de sentimientos?
Usa Sorsa API para recopilar los tweets: devuelve unos 20 tweets por solicitud de búsqueda desde $0.07 por 1,000, frente a $5.00 en la API oficial de X, con toda la sintaxis de búsqueda de X hasta 2006, una clave API y ninguna cuenta de desarrollador, y 20 solicitudes por segundo en todos los planes. La puntuación se ejecuta después en tu propio código con el modelo que elijas.
¿Puedo hacer análisis de sentimientos en Twitter gratis?
Sí, para un primer proyecto. VADER, TextBlob y los modelos RoBERTa de Cardiff NLP son gratis y funcionan en una laptop. Para los tweets, cada cuenta nueva de Sorsa API recibe 100 solicitudes gratis: unos 2,000 tweets por búsqueda, sin tarjeta, y nunca vencen. Los conjuntos de referencia etiquetados, como TweetEval, se pueden descargar gratis para probar un modelo.
¿Puedo analizar tweets en otros idiomas?
Sí, con un modelo multilingüe. twitter-xlm-roberta-base-sentiment, de Cardiff NLP, se entrenó con unos 198 millones de tweets y se ajustó para sentimientos en 8 idiomas, entre ellos español, portugués, francés y árabe. VADER y el modelo RoBERTa en inglés leen solo inglés, así que filtra por idioma con el operador lang: en tu consulta y el campo lang de cada tweet.
¿Sorsa API devuelve una puntuación de sentimiento?
No: Sorsa API devuelve los tweets, con texto completo, idioma, conteos de engagement y autor, y la puntuación se ejecuta en tu código. Así la elección del modelo es tuya, y puedes volver a puntuar tweets viejos cuando salga un modelo mejor. Sorsa API se llamó TweetScout API hasta 2025; los endpoints de tweets y de búsqueda funcionan de la misma manera.
#Cómo lo comprobamos
El 2 de noviembre de 2026 descargamos los datos de sentimientos de TweetEval del repositorio de Cardiff NLP y puntuamos el conjunto de prueba de 12,300 tweets con VADER 3.3.2, TextBlob 0.20.1, un modelo TF-IDF con regresión logística (scikit-learn 1.9.1) entrenado con los 45,600 tweets de entrenamiento, y twitter-roberta-base-sentiment-latest (transformers 5.22.1, PyTorch 2.15 en 4 hilos de CPU); los ejemplos de salida de esta página salen de la misma ejecución. La forma de las solicitudes y las respuestas sigue la referencia de la API en vivo de Sorsa API, y los precios de la API oficial de X salen de docs.x.com, leído el mismo día.
Fuentes
- TweetEval benchmark and data, Cardiff NLP (se abre en una pestaña nueva)
- twitter-roberta-base-sentiment-latest model card (se abre en una pestaña nueva)
- twitter-xlm-roberta-base-sentiment model card (se abre en una pestaña nueva)
- VADER sentiment README (se abre en una pestaña nueva)
- X API pricing (se abre en una pestaña nueva)
- X notice on billing post expansions, Oct 2026 (se abre en una pestaña nueva)
- Sorsa API reference: Search Tweets (se abre en una pestaña nueva)