Skip to main content
O dicionário naive_bayes (NAIVE_BAYES) classifica texto com um modelo multinomial de Naive Bayes, o modelo de eventos padrão para texto: ele atribui uma pontuação a cada classe com base na frequência com que os n-gramas da entrada aparecem nela. Você fornece uma tabela de contagens de n-gramas por classe, que ele compila em um modelo uma única vez, no momento do carregamento, e depois usa para classificar qualquer texto informado. Ele é adequado para classificação de texto rápida e leve, como análise de sentimento, rotulagem de tópicos ou spam e detecção de idioma ou sistema de escrita. Você consulta o dicionário com uma de três funções: A função dictGet simples também classifica (consulte Notas). Outra função, naiveBayesNgrams, não classifica — ela divide o texto em n-gramas da mesma forma que o dicionário, para que você possa montar os dados de treinamento a partir de texto bruto (consulte criar dados de treinamento a partir de texto bruto).

Início rápido

Aqui, criamos um modelo unigrama (n = 1) em modo token para análise de sentimento. 1. Crie uma tabela de origem com contagens de n-gram por classe:
2. Insira os dados de treinamento — palavras individuais (unigramas) e a frequência com que cada uma ocorre na classe positiva (1) e negativa (0):
3. Crie o dicionário com o layout NAIVE_BAYES:
PRIMARY KEY ngram faz da coluna ngram a chave — mas, para um dicionário NAIVE_BAYES, essa “chave” é o texto que você fornece para classificar, e não um valor armazenado que você procura (veja Estrutura do dicionário). O LAYOUT configura o modelo: class_attribute 'class_id' marca class_id como o rótulo da classe (portanto, o outro atributo, count, é a contagem de ocorrências por classe), n 1 usa unigramas e mode 'token' divide o texto em palavras separadas por espaços em branco (veja Parâmetros de layout). 4. ClassifiquenaiveBayesClassifier retorna o ID da classe:
1 corresponde à classe positiva, com base nos dados de treinamento que inserimos na etapa 2.
Da mesma forma, 0 corresponde à classe negativa. O mesmo resultado com dictGet:
Obtenha a probabilidade da predição ou de cada classe:
A previsão é a classe 0 (negativa), com probabilidade 0.64.
naiveBayesClassifierWithAllProbs retorna todas as classes em ordem da mais provável para a menos provável, com probabilidades cuja soma é 1.0 — aqui, 0.64 para a classe negativa e 0.36 para a positiva.

Como funciona

Treinamento (no carregamento). Cada linha de origem é uma observação (n-gram, class, count). Quando o dicionário é carregado, as linhas são compiladas no modelo uma única vez. Linhas duplicadas de (n-gram, class) são somadas, e linhas com count = 0 são ignoradas. Classificação (no momento da consulta). Para classificar uma string, o modelo:
  1. Divide a string em n-grams de acordo com mode e n (consulte Modos de tokenização).
  2. Calcula a pontuação de cada classe combinando o prior da classe com a frequência com que os n-grams da entrada foram vistos nessa classe.
  3. Ordena as classes por pontuação. A classe com a maior pontuação é a predição retornada por naiveBayesClassifier; naiveBayesClassifierWithProb e naiveBayesClassifierWithAllProbs também retornam probabilidades — dessa classe ou de todas elas.
Há dois fatores que afetam a pontuação de cada classe. O primeiro é alpha, usado para suavização. A suavização impede que o modelo atribua pontuação zero a uma classe só porque um n-gram não apareceu nessa classe durante o treinamento. Um alpha menor faz o modelo depender mais dos dados de treinamento, então uma classe pode receber uma pontuação muito maior do que as outras, mas isso também pode deixar o modelo sensível demais quando os dados de treinamento são escassos ou desbalanceados. Um alpha maior faz com que as contagens de n-grams tenham menos peso, tornando as pontuações das diferentes classes mais parecidas. Se alpha for muito grande, a informação dos n-grams quase não influencia, e a pontuação passa a ser determinada principalmente pelo prior da classe (descrito a seguir). O segundo fator é o prior da classe — o que o modelo assume sobre a probabilidade de cada classe antes de analisar o texto. Ele funciona como uma pontuação inicial que cada classe recebe antes que qualquer n-gram seja considerado; assim, um prior mais alto torna uma classe mais propensa a ser prevista. A forma como ele é definido depende de priors_mode. Por padrão (proportional), uma classe com contagem total maior de n-grams nos dados de treinamento começa com uma pontuação mais alta. Com uniform, todas as classes começam em igualdade, então apenas os n-grams decidem. Com explicit, você define manualmente o ponto de partida de cada classe. Consulte Modos de prior. Um n-gram que nunca apareceu em nenhum ponto dos dados de treinamento é ignorado: ele não faz parte do vocabulário do modelo, portanto não ajuda nem prejudica nenhuma classe. O algoritmo segue o modelo multinomial Naive Bayes para classificação de texto; consulte Manning, Raghavan & Schütze, Introduction to Information Retrieval, ch. 13 (Text Classification and Naive Bayes).

Estrutura do dicionário

Um dicionário NAIVE_BAYES tem uma estrutura fixa:
  • A PRIMARY KEY é uma única coluna String — o n-gram. No momento da consulta, essa “chave” é o texto que você fornece para classificar, não uma chave de busca armazenada.
  • Junto com ela, declare exatamente dois atributos de inteiros sem sinal: o rótulo da classe e a contagem de ocorrências. Os IDs de classe sempre usam UInt32 internamente, então um rótulo de classe deve caber em UInt32 (no máximo 4294967295), mesmo que você declare o atributo como UInt64. Um valor maior é rejeitado quando o dicionário é carregado, não quando você o cria. O mesmo vale para os tipos declarados: se um ID de classe de origem ou uma contagem não couber no tipo de atributo declarado, o carregamento falhará em vez de o valor ser truncado silenciosamente.
  • O parâmetro de layout class_attribute indica qual atributo é o rótulo da classe; o outro passa a ser automaticamente a contagem. Os dois atributos podem ser declarados em qualquer ordem.
A tabela de origem armazena contagens pré-agregadas: uma linha por (n-gram, class) com o número de vezes que esse n-gram apareceu nessa classe. Você gera essas contagens tokenizando seu corpus e agrupando o resultado, seja no seu próprio pipeline de treinamento ou no ClickHouse a partir de texto bruto rotulado (veja Criar dados de treinamento a partir de texto bruto). O dicionário apenas consome esses dados. Atualizando o modelo. Como o modelo é um dicionário baseado em uma tabela, faça o retreinamento atualizando a tabela e recarregando-a:

Parâmetros de layout

Você pode definir o dicionário com a DDL CREATE DICTIONARY (como no início rápido acima) ou em um arquivo de configuração XML; veja layouts de dicionário para saber onde esse arquivo deve ficar. O exemplo abaixo define todas as opções de layout para que você possa ver todas elas — apenas class_attribute, n e mode são obrigatórios, e a tabela acima fornece os valores padrão para o restante. Em um arquivo de configuração, os priors são escritos como elementos prior repetidos (um por classe, como mostrado abaixo), os tokens de preenchimento para byte e codepoint são números (a configuração não pode conter bytes brutos) e um literal token recebe escape de XML quando necessário, então <s> se torna &lt;s&gt;.

Modos de tokenização

mode define o que é um “token” e, portanto, como são os n-gramas. Os n-gramas de origem devem ter sido gerados com o mesmo mode e n.
  • byte — cada token é um único byte; não se assume UTF-8. Com n = 2, 'abc' gera os bigramas de bytes 'ab', 'bc'. Bom para detectar idioma ou codificação em sequências arbitrárias de bytes, e para quaisquer dados em que sinais abaixo do nível de caractere sejam importantes. Normalmente é usado com n >= 2.
  • codepoint — cada token é um ponto de código Unicode; a entrada é interpretada como UTF-8. Com n = 1, 'café' gera os pontos de código 'c', 'a', 'f', 'é'. Bom para detectar escrita e idioma, e para texto curto ou CJK, em que limites de palavras por espaço em branco não são confiáveis. (Os n-gramas de origem devem ser UTF-8 válidos; a entrada da consulta é decodificada de forma tolerante — veja Notas.)
  • token — cada token é uma palavra delimitada por espaços em branco ASCII (espaço, tabulação, quebra de linha, retorno de carro, avanço de página, tabulação vertical; sequências são reduzidas a um único separador). Espaços em branco Unicode não ASCII, como U+00A0 (espaço inseparável) ou U+2003 (espaço em), não são separadores e permanecem dentro de um token. Espaço em branco é a única coisa que separa — nada é convertido para minúsculas nem removido — então 'Hello, World!' se torna os tokens 'Hello,' e 'World!' (a vírgula, o ! e as letras maiúsculas são mantidos), e com n = 2 eles formam o único bigrama 'Hello, World!'. Bom para classificação no nível de palavras em idiomas separados por espaços — sentimento, tópico, spam, idioma de uma frase.

Modos de prior

O prior é a crença do modelo sobre cada classe antes de ele analisar o texto. priors_mode define como ele é configurado.
  • proportional (padrão) — o prior de cada classe é proporcional à sua contagem total de n-gramas nos dados de treinamento — a soma da coluna count para essa classe, não o número de linhas nem de documentos de treinamento — portanto, as classes vistas com mais frequência começam com maior probabilidade. Escolha-o quando as proporções das classes no treinamento (pela contagem total de n-gramas) corresponderem às frequências esperadas no momento da consulta. Nada a informar — ele é derivado das contagens de origem.
  • uniform — todas as classes começam com a mesma probabilidade, então nenhuma sai na frente e a previsão vem inteiramente dos n-gramas da entrada. Escolha-o quando as classes estiverem balanceadas ou quando as frequências de treinamento não refletirem a frequência com que cada classe aparece no momento da consulta. Nada a informar.
  • explicit — você fornece os priors com priors [(0, 0.6), (1, 0.4)]: um par (classe, probabilidade) por classe, cada probabilidade maior que 0 e no máximo 1, somando 1.0 no total. Escolha-o quando você souber as taxas-base reais e elas forem diferentes das do treinamento — por exemplo, apenas 1% do tráfego em produção é spam, embora o conjunto de treinamento tenha sido balanceado. Calcule-os com base na participação esperada de cada classe no mundo real.

Tokens de fronteira (padding)

O padding fica desativado por padrão. Ele só importa para n > 1, quando pode melhorar a precisão ao permitir que o modelo use sinais no início e no fim do texto. Por que isso ajuda. Com n > 1, os n-grams no meio do texto recebem contexto completo à esquerda e à direita, mas os primeiros e os últimos tokens não. Adicionar tokens de fronteira cria n-grams que marcam “início do texto” e “fim do texto”, para que o modelo possa aprender padrões ligados à posição — por exemplo, uma palavra que é distintiva quando começa uma mensagem, ou um caractere típico no fim de uma palavra. O que você deve fazer:
  1. Decida separadamente para cada lado. start_token e end_token são independentes — defina um, ambos ou nenhum. Um valor vazio significa que aquele lado não recebe padding.
  2. Escolha valores raros que não entrem em conflito com dados reais, por exemplo 0x01 / 0xFF para byte, U+10FFFE / U+10FFFF para codepoint, ou <s> / </s> para token.
  3. Produza os n-grams de treinamento com o mesmo padding. O Dicionário aplica padding à entrada da consulta, mas nunca à sua fonte, então os tokens de fronteira já precisam estar incorporados aos n-grams que você carrega. A maneira mais fácil de garantir que eles correspondam é gerar a fonte com naiveBayesNgrams, passando os mesmos start_token e end_token (além de n e mode) que você fornece ao layout — ele emite exatamente os n-grams com padding que o Dicionário produz no momento da consulta.
O formato do token de padding depende do modo:
  • byte — um número para o valor do byte, em decimal ou hexadecimal 0x (portanto, '1' e '0x01' são iguais):
  • codepoint — um número para o ponto de código UTF-8, em decimal ou hexadecimal 0x (portanto, '1114110' e '0x10FFFE' são iguais):
  • token — a string literal do token:

Crie dados de treinamento a partir de texto bruto

Se você partir de texto bruto rotulado, em vez de contagens pré-agregadas, use a função naiveBayesNgrams para dividi-lo em n-grams. Forneça a ela os mesmos n, mode, start_token e end_token do seu layout, e ela produzirá exatamente os n-grams que o dicionário espera, para que os dados de treinamento correspondam ao que o modelo vê em tempo de consulta. Dada uma tabela com linhas (class_id, text), construa a fonte (ngram, class_id, count) com um GROUP BY:
training_data agora é uma fonte válida para um dicionário NAIVE_BAYES (aqui, unigramas de token; altere os argumentos n e mode para corresponder ao seu layout). O dicionário tokeniza a entrada da consulta exatamente como ela é fornecida; portanto, se o texto de treinamento estiver em minúsculas, mas o texto da consulta não, os n-gramas não corresponderão e a precisão do modelo será prejudicada.
Priors e contagens de documentosO prior proportional (o padrão) é ponderado pela contagem total de n-gramas de cada classe, não pelo número de documentos. Se você quiser o prior clássico de frequência de documentos (documents_in_class / total_documents), calcule-o a partir da tabela bruta docs e passe-o com priors_mode 'explicit':
Em seguida, crie o dicionário a partir de training_data, passando o prior explícito calculado acima, e classifique novas avaliações:
A classe 1 é positiva e 0 é negativa, portanto ambas as avaliações foram classificadas corretamente.

Mais exemplos

Modo byte — bigramas de bytes (n = 2, mode 'byte'; classe 0 = sequências de letras ad, classe 1 = letras xz):
Modo de ponto de código — detecção do sistema de escrita por caractere (n = 1, mode 'codepoint'; classe 0 = latino, 1 = cirílico):
Leia novamente os dados de treinamento com store_source:
Detecção de idioma a partir de raw text — palavras curtas com padding nas bordas (n = 2, mode 'codepoint'; classe 0 = inglês, 1 = espanhol). Os n-grams de treinamento são gerados a partir de palavras brutas com naiveBayesNgrams, e os tokens de fronteira — passados tanto para a função quanto para o layout — permitem que o modelo use a primeira e a última letra de cada palavra:

Notas

  • Semântica computacional de dicionário. Este é um dicionário computacional: dictGet(dict, '<class_attribute>', text) classifica text (a chave é uma entrada a ser classificada, não uma chave armazenada), o atributo de contagem não é consultável, e dictHas sempre retorna 1.
  • Validação da origem no carregamento. Todo n-grama de origem deve corresponder ao n e ao mode configurados (no modo codepoint, também deve ser UTF-8 válido); qualquer incompatibilidade faz o carregamento falhar. Como linhas com contagem zero são ignoradas (consulte Como funciona), uma origem vazia ou que contenha apenas contagens zero não tem nada com que treinar e falha ao carregar.
  • A tokenização no momento da consulta é tolerante. Ao contrário da validação da origem, a entrada da consulta nunca é rejeitada. No modo codepoint, bytes que não são UTF-8 válidos são decodificados da melhor forma possível, em vez de fazer a consulta falhar; no modo token, apenas espaços em branco ASCII separam palavras (espaços em branco Unicode, como U+00A0, permanecem dentro de um token). Entradas malformadas ainda são classificadas — normalmente com base nas probabilidades a priori, já que seus n-gramas não corresponderão aos usados no treinamento.
Última modificação em 23 de julho de 2026