Pular para o conteúdo
🧠Inteligência em Código
🐍 Exemplos de Código8 min de leitura

Detector de Fake News com Machine Learning

Exemplo completo de um sistema de detecção de fake news usando técnicas de NLP e Machine Learning com scikit-learn e Transformers.

#fake-news#machine-learning#nlp#classificação#python

O que vamos construir

Um detector de fake news que:

  • Classifica notícias como verdadeiras ou falsas
  • Usa múltiplas abordagens: TF-IDF + ML clássico e Transformers
  • Analisa indicadores linguísticos de desinformação
  • Explica as razões da classificação
  • Serve via API REST

Abordagem 1: Machine Learning Clássico

1. Preparação dos Dados

"""
detector_fake_news.py - Detector de Fake News com ML
"""

import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split, cross_val_score
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.linear_model import LogisticRegression
from sklearn.ensemble import RandomForestClassifier, GradientBoostingClassifier
from sklearn.naive_bayes import MultinomialNB
from sklearn.pipeline import Pipeline
from sklearn.metrics import (
    classification_report, confusion_matrix,
    roc_auc_score, accuracy_score
)
import re
import unicodedata
from collections import Counter

# Gerar dataset de exemplo (em produção, use datasets reais)
# Datasets sugeridos: FakeNewsNet, LIAR, FakeBR
np.random.seed(42)


def criar_dataset_exemplo() -> pd.DataFrame:
    """Cria dataset de exemplo para demonstração."""
    noticias_verdadeiras = [
        "Banco Central mantém taxa Selic em 13,75% ao ano conforme esperado pelo mercado",
        "Pesquisa do IBGE mostra que desemprego caiu para 7,8% no terceiro trimestre",
        "Novo satélite brasileiro é lançado com sucesso da base de Alcântara",
        "Estudo publicado na Nature comprova eficácia de nova vacina contra dengue",
        "PIB brasileiro cresceu 2,9% em 2025 segundo dados oficiais do governo",
        "Congresso aprova novo marco regulatório para energia solar no país",
        "Universidade de São Paulo sobe 15 posições no ranking mundial de universidades",
        "Exportações de soja atingem recorde de 100 milhões de toneladas em 2025",
        "INPE registra redução de 30% no desmatamento da Amazônia no último semestre",
        "Fiocruz inicia testes clínicos de fase 3 para vacina contra malária",
    ]

    noticias_falsas = [
        "URGENTE: Governo anuncia fim do Bolsa Família! Milhões serão afetados!!!",
        "Cientistas descobrem que café cura câncer em apenas 3 dias COMPARTILHE",
        "BOMBA! Político famoso flagrado em escândalo que a mídia NÃO QUER que você veja",
        "Vacina contra gripe contém microchip de rastreamento revela médico censurado",
        "Plano secreto do governo para confiscar poupança será executado amanhã",
        "CHOCANTE: Alimento que você come todo dia causa doença terrível!! Veja qual",
        "Previsão apocalíptica: Terra será destruída por asteroide no próximo mês",
        "Remédio milagroso que cura diabetes é escondido pela indústria farmacêutica",
        "ATENÇÃO: Golpe no WhatsApp rouba TODO o dinheiro da sua conta bancária",
        "Cientista brasileiro prova que a Terra é plana e universidades censuram",
    ]

    # Expandir dataset com variações
    data = {
        'texto': noticias_verdadeiras * 10 + noticias_falsas * 10,
        'label': [0] * (len(noticias_verdadeiras) * 10) + [1] * (len(noticias_falsas) * 10),
    }

    df = pd.DataFrame(data)
    return df.sample(frac=1, random_state=42).reset_index(drop=True)


# Criar dataset
df = criar_dataset_exemplo()
print(f"Dataset: {len(df)} notícias")
print(f"Distribuição:\n{df['label'].value_counts()}")

2. Pré-processamento de Texto

class TextPreprocessor:
    """Pré-processamento especializado para detecção de fake news."""

    # Indicadores linguísticos comuns em fake news
    PALAVRAS_ALARMISTAS = [
        'urgente', 'bomba', 'chocante', 'absurdo', 'inacreditável',
        'compartilhe', 'censura', 'não querem que você saiba',
        'mídia esconde', 'revelação', 'exclusivo', 'secreto',
    ]

    @staticmethod
    def limpar_texto(texto: str) -> str:
        """Limpa e normaliza texto."""
        texto = texto.lower()
        texto = re.sub(r'https?://\S+', '', texto)  # URLs
        texto = re.sub(r'[^\w\sáéíóúâêîôûãõç]', ' ', texto)  # Pontuação
        texto = re.sub(r'\s+', ' ', texto).strip()
        return texto

    @staticmethod
    def extrair_features_linguisticas(texto: str) -> dict:
        """Extrai features que indicam fake news."""
        features = {}

        # Contagem de exclamações e caps
        features['num_exclamacoes'] = texto.count('!')
        features['num_interrogacoes'] = texto.count('?')
        features['ratio_maiusculas'] = sum(1 for c in texto if c.isupper()) / max(len(texto), 1)
        features['num_palavras'] = len(texto.split())
        features['tamanho_medio_palavra'] = np.mean([len(w) for w in texto.split()]) if texto.split() else 0

        # Palavras alarmistas
        texto_lower = texto.lower()
        features['palavras_alarmistas'] = sum(
            1 for p in TextPreprocessor.PALAVRAS_ALARMISTAS if p in texto_lower
        )

        # Pontuação excessiva
        features['pontuacao_excessiva'] = len(re.findall(r'[!?]{2,}', texto))

        # Tudo em maiúscula (grito)
        palavras_caps = [w for w in texto.split() if w.isupper() and len(w) > 2]
        features['palavras_gritando'] = len(palavras_caps)

        return features


preprocessor = TextPreprocessor()

# Aplicar pré-processamento
df['texto_limpo'] = df['texto'].apply(preprocessor.limpar_texto)

# Extrair features linguísticas
features_df = df['texto'].apply(preprocessor.extrair_features_linguisticas)
features_df = pd.DataFrame(features_df.tolist())

print("\nFeatures linguísticas extraídas:")
print(features_df.describe().round(2))

3. Treinamento do Modelo

def treinar_modelo_tfidf(df: pd.DataFrame) -> dict:
    """Treina modelo de classificação com TF-IDF."""

    X = df['texto_limpo']
    y = df['label']

    X_train, X_test, y_train, y_test = train_test_split(
        X, y, test_size=0.2, random_state=42, stratify=y
    )

    # Pipeline: TF-IDF + Classificador
    modelos = {
        'Logistic Regression': Pipeline([
            ('tfidf', TfidfVectorizer(
                max_features=10000, ngram_range=(1, 2),
                min_df=2, max_df=0.95
            )),
            ('clf', LogisticRegression(max_iter=1000, C=1.0)),
        ]),
        'Random Forest': Pipeline([
            ('tfidf', TfidfVectorizer(max_features=10000, ngram_range=(1, 2))),
            ('clf', RandomForestClassifier(n_estimators=200, random_state=42)),
        ]),
        'Gradient Boosting': Pipeline([
            ('tfidf', TfidfVectorizer(max_features=10000, ngram_range=(1, 2))),
            ('clf', GradientBoostingClassifier(n_estimators=100, random_state=42)),
        ]),
        'Naive Bayes': Pipeline([
            ('tfidf', TfidfVectorizer(max_features=10000, ngram_range=(1, 2))),
            ('clf', MultinomialNB(alpha=0.1)),
        ]),
    }

    resultados = {}
    melhor_modelo = None
    melhor_score = 0

    print("\n" + "=" * 60)
    print("COMPARAÇÃO DE MODELOS")
    print("=" * 60)

    for nome, pipeline in modelos.items():
        # Cross-validation
        cv_scores = cross_val_score(pipeline, X_train, y_train, cv=5, scoring='accuracy')

        # Treinar com todos os dados de treino
        pipeline.fit(X_train, y_train)
        y_pred = pipeline.predict(X_test)

        acc = accuracy_score(y_test, y_pred)
        resultados[nome] = {
            'accuracy': acc,
            'cv_mean': cv_scores.mean(),
            'cv_std': cv_scores.std(),
            'pipeline': pipeline,
        }

        if acc > melhor_score:
            melhor_score = acc
            melhor_modelo = nome

        print(f"\n{nome}:")
        print(f"  Accuracy: {acc:.4f}")
        print(f"  CV (5-fold): {cv_scores.mean():.4f} ± {cv_scores.std():.4f}")

    print(f"\n{'='*60}")
    print(f"🏆 Melhor modelo: {melhor_modelo} (accuracy: {melhor_score:.4f})")

    # Relatório do melhor modelo
    melhor_pipeline = resultados[melhor_modelo]['pipeline']
    y_pred = melhor_pipeline.predict(X_test)
    print(f"\n{classification_report(y_test, y_pred, target_names=['Verdadeira', 'Fake'])}")

    return resultados


resultados = treinar_modelo_tfidf(df)

4. Detector Completo com Explicação

class FakeNewsDetector:
    """Detector de fake news com explicação."""

    def __init__(self, pipeline, preprocessor: TextPreprocessor):
        self.pipeline = pipeline
        self.preprocessor = preprocessor

    def analisar(self, texto: str) -> dict:
        """Analisa uma notícia e retorna classificação com explicação."""

        # Pré-processar
        texto_limpo = self.preprocessor.limpar_texto(texto)
        features_ling = self.preprocessor.extrair_features_linguisticas(texto)

        # Classificar
        predicao = self.pipeline.predict([texto_limpo])[0]
        probabilidade = self.pipeline.predict_proba([texto_limpo])[0]

        # Analisar indicadores
        indicadores = []

        if features_ling['palavras_alarmistas'] > 0:
            indicadores.append(f"⚠️ Contém {features_ling['palavras_alarmistas']} palavra(s) alarmista(s)")

        if features_ling['ratio_maiusculas'] > 0.3:
            indicadores.append("⚠️ Uso excessivo de letras maiúsculas")

        if features_ling['num_exclamacoes'] > 2:
            indicadores.append(f"⚠️ Excesso de exclamações ({features_ling['num_exclamacoes']})")

        if features_ling['pontuacao_excessiva'] > 0:
            indicadores.append("⚠️ Pontuação excessiva (!!!, ???)")

        if features_ling['palavras_gritando'] > 1:
            indicadores.append(f"⚠️ {features_ling['palavras_gritando']} palavras em CAIXA ALTA")

        if features_ling['num_palavras'] < 10:
            indicadores.append("⚠️ Texto muito curto para análise confiável")

        return {
            'texto': texto[:200] + "..." if len(texto) > 200 else texto,
            'classificacao': 'FAKE NEWS' if predicao == 1 else 'VERDADEIRA',
            'confianca': float(max(probabilidade)),
            'probabilidade_fake': float(probabilidade[1]),
            'probabilidade_verdadeira': float(probabilidade[0]),
            'indicadores': indicadores,
            'features': features_ling,
            'veredicto': self._gerar_veredicto(predicao, probabilidade, indicadores),
        }

    def _gerar_veredicto(self, predicao, probabilidade, indicadores) -> str:
        """Gera veredicto legível."""
        confianca = max(probabilidade)

        if predicao == 1:
            if confianca > 0.9:
                return "🔴 Alta probabilidade de fake news"
            elif confianca > 0.7:
                return "🟠 Provável fake news — verifique as fontes"
            else:
                return "🟡 Suspeita — requer verificação adicional"
        else:
            if confianca > 0.9:
                return "🟢 Provavelmente verdadeira"
            elif confianca > 0.7:
                return "🟢 Parece legítima — mas sempre verifique"
            else:
                return "🟡 Inconclusivo — verifique as fontes"


# Criar detector
melhor = resultados['Logistic Regression']['pipeline']
detector = FakeNewsDetector(melhor, preprocessor)

# Testar
noticias_teste = [
    "IBGE divulga que inflação ficou em 0,3% no mês de janeiro de 2026",
    "URGENTE!!! Governo vai ACABAR com a aposentadoria!!! COMPARTILHE antes que censurem!!!",
    "Pesquisadores da USP publicam estudo sobre uso de IA na agricultura",
    "BOMBA: Remédio MILAGROSO cura todas as doenças que a indústria ESCONDE de você",
]

print("\n" + "=" * 60)
print("ANÁLISE DE NOTÍCIAS")
print("=" * 60)

for noticia in noticias_teste:
    resultado = detector.analisar(noticia)
    print(f"\n📰 {resultado['texto']}")
    print(f"   {resultado['veredicto']}")
    print(f"   Confiança: {resultado['confianca']:.1%}")
    if resultado['indicadores']:
        for ind in resultado['indicadores']:
            print(f"   {ind}")
    print()

Abordagem 2: Transformers (Mais Precisa)

"""
Detector de fake news com BERT (alta precisão)
"""

from transformers import pipeline as hf_pipeline


def detector_transformer():
    """Usa modelo pré-treinado para detectar fake news."""

    # Modelo zero-shot como alternativa rápida
    classifier = hf_pipeline(
        "zero-shot-classification",
        model="facebook/bart-large-mnli"
    )

    textos = [
        "Banco Central divulga relatório trimestral de inflação",
        "CHOCANTE: Cientista prova que vacinas causam autismo!!!",
    ]

    labels = ["notícia verdadeira e factual", "notícia falsa ou enganosa"]

    for texto in textos:
        result = classifier(texto, labels)
        print(f"\n📰 {texto}")
        for label, score in zip(result['labels'], result['scores']):
            barra = "█" * int(score * 30)
            print(f"   {label:35s} {score:.1%} {barra}")


detector_transformer()

Como Rodar

# Instalar
pip install scikit-learn pandas numpy transformers torch fastapi uvicorn

# Executar detector
python detector_fake_news.py

Saída Esperada

============================================================
ANÁLISE DE NOTÍCIAS
============================================================

📰 IBGE divulga que inflação ficou em 0,3% no mês de janeiro de 2026
   🟢 Provavelmente verdadeira
   Confiança: 94.2%

📰 URGENTE!!! Governo vai ACABAR com a aposentadoria!!! COMPARTILHE antes...
   🔴 Alta probabilidade de fake news
   Confiança: 97.8%
   ⚠️ Contém 2 palavra(s) alarmista(s)
   ⚠️ Excesso de exclamações (6)
   ⚠️ Pontuação excessiva (!!!, ???)
   ⚠️ 3 palavras em CAIXA ALTA

Limitações e Considerações

  1. Falsos positivos: títulos sensacionalistas de fontes legítimas podem ser classificados como fake
  2. Dataset: a qualidade depende diretamente do dataset de treino
  3. Contexto: o detector analisa texto, não verifica fatos contra fontes externas
  4. Evolução: fake news evoluem — o modelo precisa ser retreinado periodicamente

Este detector é uma ferramenta de apoio — a verificação humana e a checagem de fontes continuam essenciais. 🔍