NCM Classifier — sugestão de posição NCM para produtos do agro

Aviso. Este modelo dá sugestões, não decisões fiscais. A responsabilidade pela classificação fiscal permanece com quem emite a nota. Na dúvida, consulte um profissional habilitado.

Identificação

Modelo AmandaGondra/ncm-classifier
Versão v0.1.0 (publicado em 2026-11-03)
Autora Amanda Gondra
Arquitetura TF-IDF (palavras 1–2 e caracteres 3–5) + regressão logística com classes balanceadas, calibração por temperatura e regra legal da posição 31.05
Modelo pré-treinado nenhum (treinado do zero com scikit-learn 1.9.1)
Código https://github.com/amanda-gondra/ncm-classifier, commit a03a54f1d0973966b0babc8fb846e681197b07e2
Formato model.skops (sem pickle)

Descrição

A partir da descrição comercial de um produto agropecuário ("Ureia agrícola saco 50 kg", "Arame farpado 500 m"), o modelo sugere as três posições NCM mais prováveis (4 dígitos), com a confiança calibrada da primeira. Quando a confiança fica abaixo de um limiar, marca a sugestão para revisão manual.

O problema: quem vende para o produtor rural precisa informar a NCM na nota fiscal, e as descrições comerciais raramente usam a linguagem da tabela.

Etapas da inferência, iguais às da avaliação:

  1. Normalização do texto: minúsculas, sem acentos, fórmulas NPK, unidades e abreviações padronizadas.
  2. Probabilidades da regressão logística.
  3. Calibração por temperatura: softmax(log p / T), com T = 0.4012.
  4. Regra 31.05, do texto legal da posição: mercadorias do Capítulo 31 em embalagens de até 10 kg vão para a 31.05.
  5. Três sugestões e revisão: volta o top-3; a sugestão vai para revisão quando a confiança final for menor que 0.6525.

Uso pretendido

  • Público: quem emite nota de produtos agropecuários (lojas, revendas, cooperativas) e quer um ponto de partida para a classificação. Também serve como exemplo de engenharia de ML.
  • Cenários: sugerir a NCM numa tela de cadastro de produtos; triar descrições para revisão.
  • Fora do uso pretendido: decidir a NCM sem revisão humana; produtos fora das posições abaixo; classificação em 8 dígitos (subitem).

Posições cobertas (nível de posição, 4 dígitos):

Grupo Posições
Animais e produtos de origem animal 01.02, 01.03, 01.04, 01.05, 04.07, 05.11
Sementes, grãos e forragens 07.13, 10.05, 10.06, 10.07, 12.01, 12.09, 12.13, 12.14
Rações, suplementos e sal 23.02, 23.04, 23.09, 25.01
Adubos 31.01, 31.02, 31.03, 31.04, 31.05
Defensivos agrícolas 38.08
Ferramentas, arames e cercas 72.17, 73.13, 73.14, 73.17, 82.01, 85.43
Máquinas e implementos agrícolas 84.24, 84.32, 84.33, 84.34, 84.36, 87.01, 87.16

37 posições no total.

Dados de treinamento

  • Linhas: 900 (marketplace: 241, ncm_official: 359, public_reference: 1, synthetic: 299).
  • Fontes:
    • descrições comerciais reais de anúncios e catálogos;
    • descrições da própria tabela NCM oficial;
    • descrições sintéticas, geradas com um LLM e revisadas uma a uma.
  • Rotulagem: feita à mão, com a regra legal anotada em cada linha. A fonte comprova a descrição, não a classificação.
  • Pré-processamento: a normalização descrita acima. Quase-duplicatas dos testes foram removidas do treino (Jaccard de 5-gramas de caracteres ≥ 0,8), e nenhuma fonte do treino coincide com uma fonte de teste.
  • Dados sintéticos: foram escritos depois do primeiro teste (test_v1) existir. Por isso foi criado um segundo teste independente (test_v2); nele, o ganho dos sintéticos foi menor, mas se manteve.
  • Versão dos dados: SHA-256 do arquivo de treino 2c075ec49ffcbba81b6e324c36e9bf9d06439d54c603cbe2dc790622b3f85a18.
  • Parte publicada: só as linhas oficiais e sintéticas estão em AmandaGondra/ncm-classifier-dataset. As descrições de anúncios não são redistribuídas.

Avaliação

Protocolo

  • Escolha do C: validação cruzada estratificada em 5 dobras no treino (impressão digital das dobras: 59611f6771f10d2c601009368dd868d2f83dcc91e3353a3340e1c2803f438cd0). C = 3.0, macro F1 médio de 0.8638.
  • Calibração: temperatura e limiar de revisão ajustados nas probabilidades fora da dobra do treino. Fora da dobra: 0.1489 [0.1267–0.1722] enviado para revisão e 0.9504 [0.9347–0.9648] de top-1 nos aceitos.
  • Testes: dois testes congelados e escritos à mão antes do treino, com checksum, nunca usados para treino ou escolha:
    • test_v1: 146 linhas, todas as 37 posições;
    • test_v2: 74 linhas, de fontes novas.
  • Intervalos: bootstrap com 1000 reamostragens, intervalo percentil de 95%, semente 0.

Resultados (calibrado + regra 31.05)

Métrica test_v1 test_v2
top-1 0.9452 [0.9041–0.9795] 0.9459 [0.8919–0.9865]
top-3 0.9932 [0.9795–1.0000] 1.0000 [1.0000–1.0000]
macro F1 0.9447 [0.8942–0.9782] 0.9198 [0.8621–0.9867]
macro precisão 0.9588 [0.9032–0.9858] 0.9219 [0.8533–0.9929]
macro recall 0.9488 [0.9122–0.9804] 0.9271 [0.8822–0.9881]
ECE bruto → calibrado 0.4502 → 0.0753 0.4554 → 0.0624
Enviado para revisão 0.1096 [0.0616–0.1644] 0.1351 [0.0676–0.2162]
top-1 dos aceitos 0.9846 [0.9615–1.0000] 1.0000 [1.0000–1.0000]
Linhas 146 74

As métricas macro tiram a média sobre as posições presentes em cada teste. ECE é o erro de calibração da confiança do top-1, em 10 faixas.

Por capítulo

Linhas, acerto da posição e acerto do capítulo (os dois primeiros dígitos):

Capítulo test_v1: linhas / posição / capítulo test_v2: linhas / posição / capítulo
01 15 / 0.933 / 1.000 12 / 1.000 / 1.000
04 3 / 1.000 / 1.000 2 / 1.000 / 1.000
05 4 / 1.000 / 1.000 —
07 4 / 0.750 / 0.750 1 / 1.000 / 1.000
10 11 / 0.818 / 0.818 2 / 1.000 / 1.000
12 15 / 1.000 / 1.000 6 / 1.000 / 1.000
23 14 / 0.857 / 1.000 7 / 0.857 / 0.857
25 4 / 1.000 / 1.000 2 / 0.500 / 0.500
31 21 / 0.905 / 0.952 13 / 1.000 / 1.000
38 6 / 1.000 / 1.000 1 / 0.000 / 0.000
72 4 / 1.000 / 1.000 —
73 11 / 1.000 / 1.000 7 / 0.857 / 1.000
82 3 / 1.000 / 1.000 1 / 1.000 / 1.000
84 20 / 1.000 / 1.000 12 / 1.000 / 1.000
85 4 / 1.000 / 1.000 3 / 1.000 / 1.000
87 7 / 1.000 / 1.000 5 / 1.000 / 1.000

Comparação com BERTimbau

Um fine-tuning do BERTimbau, com os mesmos dados, dobras, calibração e regra, empatou na qualidade: o top-1 dos dois testes juntos foi igual, e o intervalo da diferença pareada vai de −3,6 a +4,1 pontos. Ele custa ~50× mais por previsão em CPU. Os detalhes e o modelo estão em AmandaGondra/ncm-classifier-bertimbau.

Como usar

pip install -r requirements.txt   # instala o pacote ncm-classifier na versão v0.1.0
from huggingface_hub import snapshot_download
from ncm_classifier.inference.predictor import NcmPredictor

path = snapshot_download("AmandaGondra/ncm-classifier", revision="v0.1.0")
predictor = NcmPredictor.from_directory(path)

for prediction in predictor.predict(["Ureia agrícola, pacote 1 kg"]):
    print(prediction.to_dict())

Cada resultado traz:

  • suggestions: três posições, da mais provável para a menos provável, com a probabilidade calibrada de cada uma. Leia como "provavelmente a primeira; confira as outras duas se a descrição for ambígua".
  • confidence: probabilidade calibrada da primeira sugestão.
  • needs_review: true quando a confiança está abaixo do limiar. Nesse caso, a sugestão deve ser conferida por uma pessoa.
  • rule_31_05: true quando a regra da embalagem de até 10 kg mudou a sugestão.

O carregador só aceita, além do scikit-learn e do NumPy, a função de normalização do próprio projeto. Qualquer outro tipo no arquivo faz o carregamento falhar.

Limitações e riscos

  • O modelo dá sugestões, não decisões fiscais. Ele pode errar, inclusive com confiança alta.
  • A responsabilidade pela classificação fiscal permanece com quem emite a nota. A revisão por um profissional habilitado pode ser necessária.
  • A qualidade depende da descrição. Textos curtos ("Chocadeira"), siglas ("TSP") e marcas sem contexto erram mais.
  • Composição e aplicação mudam a NCM. Por exemplo, sal mineral é 23.09 e sal comum é 25.01; adubos dependem da composição e da embalagem. Produtos assim podem exigir análise técnica.
  • Embalagem não declarada: quando o texto não diz o peso, o rótulo segue a convenção de granel (mais de 10 kg). A regra 31.05 só lê pesos escritos em grafias reconhecidas ("5 kg", "500 g"); grafias como "5k" passam sem a regra.
  • A tabela NCM muda. O escopo segue a tabela vigente em 30/10/2026 (Resolução Gecex nº 926/2026).
  • Testes pequenos. Com 220 linhas, os intervalos de confiança são largos.
  • Escopo restrito: 37 posições, nível de 4 dígitos. Fora delas, o modelo sempre sugere uma das 37, mesmo que nenhuma sirva.

Licença

  • Código e modelo: MIT.
  • Dados: o treino inclui descrições de anúncios de terceiros, que não são redistribuídas. O modelo guarda delas apenas estatísticas de palavras e trechos curtos. A parte publicada dos dados tem licença própria, descrita no dataset card.
  • Este documento não é parecer jurídico.
Downloads last month
-
Inference Providers NEW
This model isn't deployed by any Inference Provider. 🙋 Ask for provider support

Dataset used to train AmandaGondra/ncm-classifier