Skip to content
Tutorials6 min read

Criando uma tarefa de análise de sentimento

Construa uma tarefa completa de classificação de sentimento com botões de rádio, tooltips e atalhos de teclado para uma rotulagem eficiente.

Potato Team

A análise de sentimento é uma das tarefas mais comuns de PLN, e coletar rótulos limpos para ela no Potato é simples. Este tutorial monta uma interface de anotação de sentimento que você pode realmente colocar diante dos anotadores, com os atalhos de teclado e as verificações de qualidade que aceleram a rotulagem.

Visão geral do projeto

Estamos anotando publicações de redes sociais. A interface abrange:

  • Classificação de sentimento em três classes (Positive, Negative, Neutral)
  • Avaliações de confiança para cada anotação
  • Explicações textuais opcionais
  • Atalhos de teclado para agilidade
  • Medidas de controle de qualidade

Configuração completa

Aqui está o config.yaml completo:

yaml
annotation_task_name: "Social Media Sentiment Analysis"
 
# Data configuration
data_files:
  - "data/tweets.json"
 
item_properties:
  id_key: id
  text_key: text
 
# Annotation interface
annotation_schemes:
  # Primary sentiment label
  - annotation_type: radio
    name: sentiment
    description: "What is the overall sentiment of this post?"
    labels:
      - name: Positive
        tooltip: "Expresses happiness, satisfaction, or approval"
        key_value: "1"
      - name: Negative
        tooltip: "Expresses sadness, frustration, or disapproval"
        key_value: "2"
      - name: Neutral
        tooltip: "Factual, objective, or lacks emotional content"
        key_value: "3"
    label_requirement:
      required: true
 
  # Confidence rating
  - annotation_type: likert
    name: confidence
    description: "How confident are you in your sentiment label?"
    size: 5
    min_label: "Not confident"
    max_label: "Very confident"
    label_requirement:
      required: true
 
  # Optional explanation
  - annotation_type: text
    name: explanation
    description: "Why did you choose this label? (Optional)"
    rows: 4
    label_requirement:
      required: false
    placeholder: "Explain your reasoning..."
 
# Guidelines
annotation_instructions: |
  ## Sentiment Annotation Guidelines
 
  ### Your Task
  Classify the sentiment expressed in each social media post.
 
  ### Labels
 
  **Positive**: The author expresses positive emotions or opinions
  - Happiness, excitement, gratitude
  - Praise, recommendations, approval
  - Examples: "Love this!", "Best day ever!", "Highly recommend"
 
  **Negative**: The author expresses negative emotions or opinions
  - Anger, frustration, sadness
  - Complaints, criticism, disapproval
  - Examples: "Terrible service", "So disappointed", "Worst experience"
 
  **Neutral**: Factual or lacking clear sentiment
  - News, announcements, questions
  - Mixed or balanced opinions
  - Examples: "The store opens at 9am", "Has anyone tried this?"
 
  ### Tips
  - Focus on the author's sentiment, not the topic
  - Sarcasm should be labeled based on intended meaning
  - When unsure, lower your confidence rating
 
# User management
automatic_assignment:
  on: true
  sampling_strategy: random
  labels_per_instance: 1
  instance_per_annotator: 100

Formato dos dados de exemplo

Crie data/tweets.json:

json
{"id": "t001", "text": "Just got my new laptop and I'm absolutely loving it! Best purchase of the year! #happy"}
{"id": "t002", "text": "Waited 2 hours for customer service and they still couldn't help me. Never shopping here again."}
{"id": "t003", "text": "The new coffee shop on Main Street opens tomorrow at 7am."}
{"id": "t004", "text": "This movie was okay I guess. Some good parts, some boring parts."}
{"id": "t005", "text": "Can't believe how beautiful the sunset was tonight! Nature is amazing."}

Executando a tarefa

Inicie o servidor de anotação:

bash
potato start config.yaml

Acesse http://localhost:8000 e faça login para começar a anotar.

Veja o que seus anotadores enxergam assim que o servidor estiver no ar:

Interface de anotação de análise de sentimento com botões de rádio para os rótulos Positive, Negative e NeutralA interface de classificação de sentimento mostrando rótulos em botões de rádio, escala de confiança e campo de explicação opcional

Entendendo a interface

Área principal de anotação

A interface exibe:

  1. O texto a ser anotado (com URLs, menções e hashtags destacados)
  2. Botões de rádio de sentimento com tooltips
  3. Escala Likert de confiança
  4. Caixa de texto de explicação opcional

Fluxo de trabalho por teclado

Quando os anotadores entram em ritmo, o ciclo mais rápido é:

  1. Ler o texto
  2. Pressionar 1, 2 ou 3 para o sentimento
  3. Clicar no nível de confiança (ou usar o mouse)
  4. Pressionar Enter para enviar

Acompanhamento do progresso

A interface mostra:

  • O progresso atual (por exemplo, "15 / 100")
  • O tempo estimado restante
  • Estatísticas da sessão

Formato de saída

O trabalho de cada anotador é salvo em <output_annotation_dir>/<user>/user_state.json, independentemente do que diga export_annotation_format. Essa configuração acrescenta uma exportação periódica ao lado, então com jsonl o arquivo combinado é <output_annotation_dir>/exports/jsonl/annotations.jsonl, com um registro por anotador por instância:

json
{
  "instance_id": "t001",
  "user_id": "john_doe",
  "labels": {
    "sentiment": {"Positive": "true"},
    "confidence": {"5": "true"},
    "explanation": {"text_box": "Clear expression of happiness with the purchase"}
  },
  "spans": {},
  "links": {}
}

Adicionando controle de qualidade

Verificações de atenção

Adicione itens de padrão-ouro para verificar a atenção dos anotadores. Para o conjunto completo de opções por trás dos esquemas radio e likert usados aqui, consulte a documentação de origem.

yaml
attention_checks:
  enabled: true
  frequency: 10          # Every 10th item
  items_file: data/attention_checks.json
  failure_handling:
    warn_threshold: 2
    block_threshold: 5

Os itens ficam em items_file em vez de diretamente na configuração, e cada um traz a resposta que deve receber:

json
[
  {
    "id": "chk1",
    "text": "I am extremely happy and satisfied! This is the best!",
    "expected_answer": { "sentiment": "Positive" }
  },
  {
    "id": "chk2",
    "text": "This is absolutely terrible and I hate it completely.",
    "expected_answer": { "sentiment": "Negative" }
  }
]

Os itens de padrão-ouro usam gold_label em vez de expected_answer e ficam em gold_standards.items_file. Observe que os dois blocos ficam no nível superior. O Potato lê attention_checks a partir da raiz da configuração, então colocá-lo dentro de um bloco quality_control: faz com que ele não seja lido, sem que nenhum erro seja relatado.

Concordância entre anotadores

Para projetos de pesquisa, habilite múltiplas anotações:

yaml
automatic_assignment:
  on: true
  sampling_strategy: random
  labels_per_instance: 3  # Each item annotated by 3 people
  instance_per_annotator: 50

Analisando os resultados

Exporte e analise suas anotações:

python
import json
from collections import Counter
 
records = []
with open('annotation_output/exports/jsonl/annotations.jsonl') as f:
    for line in f:
        records.append(json.loads(line))
 
def chosen(record, scheme):
    """The label picked for a single-choice scheme: the key whose value is "true"."""
    for name, value in record["labels"].get(scheme, {}).items():
        if value == "true":
            return name
    return None
 
sentiments = Counter(chosen(r, "sentiment") for r in records)
print(f"Sentiment distribution: {dict(sentiments)}")
 
# A likert stores its scale position the same way, as the label name
points = [int(p) for r in records if (p := chosen(r, "confidence"))]
print(f"Average confidence: {sum(points)/len(points):.2f}")

Próximos passos


Explore mais tipos de anotação em nossa documentação.