02_data_understanding



NLP Triagem Inteligente Financeira - Data Science Project

Data Understanding | FAQ_BACEN

Realizar a leitura, inspeção e análise exploratória inicial do dataset FAQ_BACEN, entendendo sua estrutura,
distribuição de classes, características textuais e implicações para a tarefa de classificação.


Roberto SSoares - LfLngLrnng

in/roberto-dos-santos-soares
Portifólio: roberto-ssoares

" [+] Faturamento [-] Custo [+] Qualidade de vida "
"Mestre Bruno Jardim"

📌 Objetivo:

  • Ações realizadas neste notebook
    • Carregamento do dataset
    • Inspeção estrutural
    • Verificação de colunas, tipos e amostras
    • Análise de classes
    • Análise do comprimento dos textos
    • Identificação de possíveis riscos para modelagem
    • Exportação inicial para a camada bronze
  • Justificativa técnica
    • A etapa de Data Understanding é essencial para validar se o dataset é adequado ao problema de NLP proposto,
      • identificar desbalanceamentos,
      • ambiguidades semânticas
      • e restrições práticas antes da preparação e modelagem.
  • Resultados esperados
    • Dataset carregado corretamente
    • Estrutura e colunas compreendidas
    • Classes e distribuição conhecidas
    • Características básicas dos textos documentadas
    • Base pronta para a etapa de preparação

📚 Instalando e Carregando os Pacotes¶

import warnings
from pathlib import Path

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

from datasets import load_dataset

warnings.filterwarnings("ignore")
pd.set_option('display.max_colwidth', None)                     # Não limitar a largura da coluna
pd.set_option('display.width', None)                            # Expandir a largura da exibição (evitar quebra de linha horizontal)

✔️ 1. Caminhos de Diretórios

PROJECT_ROOT = Path.cwd().resolve().parents[0]
DATA_DIR = PROJECT_ROOT / "data"
RAW_DIR = DATA_DIR / "00-raw"
BRONZE_DIR = DATA_DIR / "01-bronze"
ARTIFACTS_DIR = PROJECT_ROOT / "artifacts"
FIGURES_DIR = ARTIFACTS_DIR / "figures"

RAW_DIR.mkdir(parents=True, exist_ok=True)
BRONZE_DIR.mkdir(parents=True, exist_ok=True)
FIGURES_DIR.mkdir(parents=True, exist_ok=True)

print("PROJECT_ROOT:", PROJECT_ROOT)
print("RAW_DIR:", RAW_DIR)
print("BRONZE_DIR:", BRONZE_DIR)
print("FIGURES_DIR:", FIGURES_DIR)
PROJECT_ROOT: D:\_DS-Projects\nlp-triagem-inteligente-financeira
RAW_DIR: D:\_DS-Projects\nlp-triagem-inteligente-financeira\data\00-raw
BRONZE_DIR: D:\_DS-Projects\nlp-triagem-inteligente-financeira\data\01-bronze
FIGURES_DIR: D:\_DS-Projects\nlp-triagem-inteligente-financeira\artifacts\figures

✔️ 2. Carregamento do dataset

  • Nesta etapa, carregamos o dataset Itau-Unibanco/FAQ_BACEN diretamente do Hugging Face Hub.

dataset = load_dataset("Itau-Unibanco/FAQ_BACEN")
dataset
DatasetDict({
    train: Dataset({
        features: ['Unnamed: 0', 'questions', 'categories', 'answers'],
        num_rows: 1305
    })
    test: Dataset({
        features: ['Unnamed: 0', 'questions', 'categories', 'answers'],
        num_rows: 373
    })
})
train_df = dataset["train"].to_pandas()
test_df = dataset["test"].to_pandas()

df = pd.concat([train_df.assign(split="train"), test_df.assign(split="test")], ignore_index=True)
print("train shape:", train_df.shape)
print("test shape :", test_df.shape)
print("full shape :", df.shape)
train shape: (1305, 4)
test shape : (373, 4)
full shape : (1678, 5)

✔️ 2. Inspeção estrutural inicial

  • Aqui validamos:
    • ✅ colunas disponíveis
    • ✅ tipos
    • ✅ amostras
    • ✅ presença de valores nulos

df.head(5)
Unnamed: 0 questions categories answers split
0 0 Quais são as condições dos Créditos para Beneficiários do PNCF e PNRA? Programa Nacional de Fortalecimento da Agricultura Familiar - Pronaf Os créditos para Beneficiários do PNCF e PNRA são destinados exclusivamente às famílias beneficiárias do Programa Nacional de Reforma Agrária (PNRA) e do Programa Nacional de Crédito Fundiário (PNCF) enquadradas nos Grupos "A" e "A/C" do Pronaf. Os créditos do Grupo "A" são de investimento e devem ser concedidos mediante apresentação de projeto técnico, admitindo-se, a critério da instituição financeira, a substituição do projeto por proposta simplificada, desde que as inversões programadas envolvam técnicas simples e bem assimiladas pelos agricultores da região ou se trate de crédito destinado à ampliação dos investimentos já financiados. O limite é de R$25.000,00 (vinte e cinco mil reais) por beneficiário, podendo ser dividido em até 3 (três) operações. Os encargos financeiros são de 0,5 % a.a. (cinco décimos por cento ao ano) com o benefício de bônus de adimplência de 40% (quarenta por cento) sobre cada parcela do principal paga até a data de seu respectivo vencimento. Aos beneficiários enquadrados no Grupo “A/C” é autorizada a concessão de até 3 créditos de custeio, sendo o limite de financiamento de até R$7.500,00 e os encargos financeiros taxa efetiva de juros de 1,5% a.a. (um inteiro e cinco décimos por cento ao ano). train
1 1 Quais são os principais tipos de operações de crédito? Empréstimo, financiamento e arrendamento mercantil (leasing) Operação de crédito e seus principais tipos Empréstimo, financiamento e arrendamento mercantil (leasing). Os empréstimos não possuem finalidade específica. Você pode utilizar o valor que pegou emprestado como bem entender.  Nos financiamentos, os recursos financeiros liberados pelo banco devem ser usados com uma finalidade específica, estabelecida em contrato. No arrendamento mercantil, o bem é arrendado, ou seja, o banco (arrendador) é o dono do bem, mas você (arrendatário) tem o direito de usá-lo durante o prazo do contrato. Dessa forma, essas operações também estão vinculadas a uma destinação específica como nos financiamentos. Porém, apesar de o tomador escolher qual será o bem objeto do arrendamento e de poder utilizá-lo durante a vigência do contrato, o bem é propriedade da instituição credora. Veja no quadro abaixo as principais diferenças entre essas operações: train
2 2 Quais os prazos para pagamento de cheques? SEM-CATEGORIA Existem dois prazos que devem ser observados:prazo de apresentação, que é de 30 dias, a contar da data de emissão, para os cheques emitidos na mesma praça do banco sacado; e de 60 dias para os cheques emitidos em outra praça; eprazo de prescrição, que é de 6 meses decorridos a partir do término do prazo de apresentação. Mesmo após o prazo de apresentação, o cheque é pago se houver fundos na conta. Se não houver, o cheque é devolvido pelo motivo 11 (primeira apresentação) ou 12 (segunda apresentação), sendo, neste caso, o seu nome incluído no CCF. Quando apresentado após o prazo de prescrição, o cheque é devolvido pelo motivo 44, não podendo ser pago pelo banco, mesmo que a conta tenha saldo disponível. train
3 3 Quem pode se associar a uma cooperativa de crédito? Cooperativas de crédito  Como me associar a uma cooperativa de crédito? O ingresso nas cooperativas é livre a todos que desejarem utilizar os serviços prestados pela sociedade, desde que estejam alinhados aos propósitos sociais e preencham condições estabelecidas no estatuto. Contudo, a admissão dos associados poderá ser restrita às pessoas que exerçam determinada atividade ou profissão ou estejam vinculadas a determinada entidade.  Importante! As condições de admissão de associados e a área de atuação da cooperativa de crédito devem constar no seu estatuto social. train
4 4 Quem é responsável pelos dados inseridos no SCR? Sistema de Informações de Créditos (SCR) Responsabilidade pelos dados A responsabilidade pelos dados dos clientes é das instituições com as quais eles contrataram as operações de crédito. São elas as responsáveis por todas as inclusões, correções, exclusões, marcações sub judice e registros de medidas judiciais e de manifestações de discordância sobre os dados. train
df.info()

RangeIndex: 1678 entries, 0 to 1677
Data columns (total 5 columns):
 #   Column      Non-Null Count  Dtype
---  ------      --------------  -----
 0   Unnamed: 0  1678 non-null   int64
 1   questions   1678 non-null   str  
 2   categories  1678 non-null   str  
 3   answers     1678 non-null   str  
 4   split       1678 non-null   str  
dtypes: int64(1), str(4)
memory usage: 1.1 MB
null_summary = df.isna().sum().to_frame("qtd_nulos")
null_summary["pct_nulos"] = (null_summary["qtd_nulos"] / len(df) * 100).round(2)
null_summary
qtd_nulos pct_nulos
Unnamed: 0 0 0.0
questions 0 0.0
categories 0 0.0
answers 0 0.0
split 0 0.0

✔️ 3. Padronização inicial das colunas

  • Vamos criar uma versão padronizada com nomes simples para facilitar o pipeline.

df = df.rename(
    columns={
        "questions": "question",
        "categories": "category",
        "answers": "answer",
    }
)

df.columns.tolist()
['Unnamed: 0', 'question', 'category', 'answer', 'split']
df[["question", "category", "answer", "split"]].sample(5, random_state=42)
question category answer split
1601 Além de decretar e acompanhar o regime de resolução, qual o papel do Banco Central? Regimes de Resolução  -  Definições Informações gerais O BC é o responsável pela realização do inquérito para apurar as causas que levaram a instituição ao regime de resolução e a responsabilidade de controladores, administradores, membros do Conselho Fiscal e prestadores de serviços de auditoria independente.  Adicionalmente o BC atua como instância administrativa em recursos contra decisões do liquidante, interventor ou conselho diretor, ou na autorização de atos específicos determinados em lei.  O BC, a título de contribuição, comunica às instituições financeiras, às demais instituições autorizadas a funcionar pelo Banco Central do Brasil, às bolsas de valores, às entidades autorizadas a exercer a atividade de registro de ativos financeiros e de valores mobiliários e à Central Nacional de Indisponibilidade de Bens (CNIB) a indisponibilidade de bens dos controladores e ex-administradores, em decorrência da decretação do regime de resolução.  Importante! Nos termos do art. 38 da Lei 6.024, de 1974, compete ao responsável pelo regime de resolução informar a indisponibilidade de bens dos controladores e ex-administradores, em decorrência da decretação do regime de resolução. Dessa forma, o responsável promoverá as demais comunicações. test
482 Moro no Brasil e possuo aqui uma conta em reais em um banco, mas estou me mudando para outro país. Posso manter essa conta? Contas de brasileiros no exterior e de estrangeiros no Brasil Contas no Brasil de residentes no exterior Não. Você precisará encerrar a sua conta atual e abrir uma conta de domiciliado no exterior, na forma da pergunta 1. train
203 Fiz uma compra em moeda estrangeira pelo cartão de crédito e está sendo cobrado valor convertido em reais com taxa diferente da publicada na página do Banco Central. Isso pode ser feito? Cartão de Crédito Internacional Sim. Veja a seção Taxa de câmbio. train
49 Se eu não tiver acesso à internet, é possível fazer um PIX? SEM-CATEGORIA Em um primeiro momento, você somente poderá fazer um PIX se estiver conectado à internet. Há, no entanto, previsão de disponibilização de uma forma de pagamento off-line para 2021. train
1290 Como faço para consultar meus dados em determinado cadastro? Cadastro Positivo Consulta ao cadastro positivo Qualquer cadastrado deve ter acesso fácil e independente de justificativa a todas as suas informações existentes no banco de dados, inclusive seu histórico e sua nota ou pontuação de crédito. Esse acesso é gratuito, ou seja, não pode ser cobrada nenhuma taxa ou tarifa pela prestação do serviço. Os gestores devem fornecer-lhe essas informações no prazo de 10 dias a partir da data de solicitação. Essa solicitação pode ser feita por quaisquer dos canais: físico, telefônico ou eletrônico. Cabe ao gestor disponibilizar o acesso a esses quatro canais e manter a segurança dos sistemas. train

✔️ 4. Análise das classes

  • A variável-alvo principal do MVP será category.
  • Nesta etapa, queremos entender:
    • quantidade de categorias
    • frequência por classe
    • possíveis sinais de desbalanceamento

n_classes = df["category"].nunique()
print("Número de categorias:", n_classes)

class_counts = (
    df["category"]
    .value_counts()
    .rename_axis("category")
    .reset_index(name="count")
)

class_counts.head(10)
Número de categorias: 242
category count
0 SEM-CATEGORIA 270
1 Crédito Imobiliário 25
2 Registrato 25
3 Sistema de Pagamentos em Moeda Local (SML) 24
4 Cartão de Crédito e Crédito Rotativo 24
5 Tarifas bancárias 22
6 Conta-Salário e Portabilidade Salarial 22
7 Programa Nacional de Fortalecimento da Agricultura Familiar - Pronaf 20
8 CBE - Capitais Brasileiros no Exterior Informando os ativos no exterior 20
9 Censo Anual de Capitais Estrangeiros no País 17
class_counts.describe(include="all")
category count
count 242 242.000000
unique 242 NaN
top SEM-CATEGORIA NaN
freq 1 NaN
mean NaN 6.933884
std NaN 17.608106
min NaN 1.000000
25% NaN 3.000000
50% NaN 4.000000
75% NaN 7.750000
max NaN 270.000000
top_20 = class_counts.head(20)

plt.figure(figsize=(12, 8))
plt.barh(top_20["category"][::-1], top_20["count"][::-1])
plt.title("Top 20 categorias por frequência")
plt.xlabel("Quantidade")
plt.ylabel("Categoria")
plt.tight_layout()
plt.show()
Graph

✔️ 5. Análise textual básica

  • Vamos medir características importantes dos textos:
    • número de caracteres
    • número de palavras
    • tamanho das respostas

df["question_num_chars"] = df["question"].astype(str).str.len()
df["question_num_words"] = df["question"].astype(str).str.split().str.len()

df["answer_num_chars"] = df["answer"].astype(str).str.len()
df["answer_num_words"] = df["answer"].astype(str).str.split().str.len()

df[[
    "question_num_chars",
    "question_num_words",
    "answer_num_chars",
    "answer_num_words"
]].describe()
question_num_chars question_num_words answer_num_chars answer_num_words
count 1678.000000 1678.000000 1678.000000 1678.000000
mean 70.581049 11.555423 516.432062 78.367700
std 33.940286 5.299067 499.196572 75.531005
min 6.000000 1.000000 4.000000 1.000000
25% 47.000000 8.000000 235.000000 37.000000
50% 65.000000 11.000000 398.500000 62.000000
75% 87.000000 14.000000 649.750000 97.000000
max 250.000000 42.000000 11401.000000 1790.000000
plt.figure(figsize=(10, 5))
plt.hist(df["question_num_words"], bins=30)
plt.title("Distribuição do número de palavras nas perguntas")
plt.xlabel("Número de palavras")
plt.ylabel("Frequência")
plt.tight_layout()
plt.show()
Graph
plt.figure(figsize=(10, 5))
plt.hist(df["answer_num_words"], bins=30)
plt.title("Distribuição do número de palavras nas respostas")
plt.xlabel("Número de palavras")
plt.ylabel("Frequência")
plt.tight_layout()
plt.show()
Graph

✔️ 6. Exemplos curtos e longos

  • Essa leitura qualitativa ajuda a entender:
    • perguntas muito curtas
    • perguntas potencialmente ambíguas
    • respostas muito extensas

print("Perguntas mais curtas:")
display(
    df.sort_values("question_num_words", ascending=True)[
        ["question", "category", "question_num_words"]
    ].head(10)
)
Perguntas mais curtas:
question category question_num_words
1062 Alerta Alerta contra golpes envolvendo o nome do Banco Central e de instituições financeiras 1
327 Exemplo prático SEM-CATEGORIA 2
976 Como encaminhar? Acordo Administrativo em Processo de Supervisão (APS) 2
1235 Como acessar? Registrato 2
1634 Onde declarar Trust? CBE - Capitais Brasileiros no Exterior Informando os ativos no exterior 3
1665 Quem pode participar? Sandbox Regulatório Informações Gerais 3
83 Quem pode utilizar? Sistema de Pagamentos em Moeda Local (SML) 3
1568 Quem pode acessar? Registrato 3
692 O que é ACC? Exportações Antecipação de valores e financiamento de exportações 4
1633 Como faço um PIX? SEM-CATEGORIA 4
print("Perguntas mais longas:")
display(
    df.sort_values("question_num_words", ascending=False)[
        ["question", "category", "question_num_words"]
    ].head(10)
)
Perguntas mais longas:
question category question_num_words
1270 O que ocorre no caso de a cédula fragmentada que não tem um único pedaço com mais da metade do tamanho original, mas que todos os pedaços estão colados em sequência e, juntos, têm mais da metade do tamanho total da cédula? Cédulas e Moedas Inadequadas para Circulação 42
614 E no caso de a cédula fragmentada não ter um único pedaço com mais da metade do tamanho original, mas se todos os pedaços estiverem colados em sequência e, juntos, tiverem mais da metade do tamanho total da cédula? SEM-CATEGORIA 39
162 Numa situação em que o valor dos recebíveis constituídos mantidos em garantia esteja dentro do limite de crédito não cancelável incondicional, mas superior ao limite do saldo devedor, quando deverá ser promovida a desconstituição dos ônus e gravames? Operações com Recebíveis Desconstituição de gravames e de ônus sobre os recebíveis de arranjo de pagamento 38
776 Quando há valor excedente de recebíveis constituídos mantido em garantia em relação ao valor máximo garantido que poderá ser mantido permanentemente, durante a vigência da operação, quando deverá ser promovida a desconstituição dos ônus e gravames? Operações com Recebíveis Desconstituição de gravames e de ônus sobre os recebíveis de arranjo de pagamento 36
171 Se a corretora de câmbio for uma agência de turismo, as contas da agência podem ser bloqueadas, paralisando operações não ligadas diretamente ao câmbio? Por exemplo: emissão de passagens de pacotes já fechados pelos clientes. Liquidação Extrajudicial - Corretoras de câmbio 35
318 O que acontece se eu não pagar o valor do saldo devedor da fatura que já tiver sido financiado por 30 dias no crédito rotativo ou não aceitar o financiamento proposto pela instituição financeira? Cartão de Crédito e Crédito Rotativo 34
73 No caso de operações de compra de ativos por ordem de clientes, na liquidação da operação os ativos ainda irão para a custódia da instituição liquidada ou já poderão ser destinados para outro custodiante? Liquidação Extrajudicial - Corretoras de Títulos e Valores Mobiliários 34
1296 O que muda, a partir de 1º de março de 2020, em relação à taxa de câmbio cobrada quando faço compras de bens e serviços no exterior em moeda estrangeira utilizando cartão de crédito? Taxa de câmbio 34
1496 Caso possua uma conta de depósitos à vista, uma conta de poupança ou uma conta de pagamento pré-paga, na mesma ou em outra instituição, eu posso realizar transferência dos recursos para esta conta? Conta-Salário e Portabilidade Salarial 33
86 Como um participante do Sandbox pode ter segurança de que eventuais competidores, que sejam instituições já autorizadas pelo BC, não possam atrapalhar sua atuação por meio da imposição de algum tipo de dificuldade? Sandbox Regulatório Execução e encerramento dos projetos autorizados 33

✔️ 7. Duplicidades

  • Em datasets de FAQ, pode haver:
    • perguntas idênticas
    • respostas repetidas
    • combinações pergunta-categoria duplicadas
  • Precisamos medir isso antes da preparação.

dup_question = df.duplicated(subset=["question"]).sum()
dup_question_category = df.duplicated(subset=["question", "category"]).sum()
dup_full = df.duplicated(subset=["question", "category", "answer"]).sum()

pd.DataFrame(
    {
        "criterio": ["question", "question + category", "question + category + answer"],
        "qtd_duplicados": [dup_question, dup_question_category, dup_full],
    }
)
criterio qtd_duplicados
0 question 0
1 question + category 0
2 question + category + answer 0

✔️ 8. Visão por split

  • Vamos confirmar se train e test estão coerentes em termos de volume e classes.

split_summary = (
    df.groupby("split")
      .agg(
          n_registros=("question", "size"),
          n_categorias=("category", "nunique"),
          avg_question_words=("question_num_words", "mean"),
          avg_answer_words=("answer_num_words", "mean"),
      )
      .round(2)
)

split_summary
n_registros n_categorias avg_question_words avg_answer_words
split
test 373 146 11.92 77.69
train 1305 237 11.45 78.56
cross_tab = pd.crosstab(df["category"], df["split"])
cross_tab.head(20)
split test train
category
Acordo Administrativo em Processo de Supervisão (APS) 0 9
Alerta contra golpes envolvendo o nome do Banco Central e de instituições financeiras 1 5
Aplicações financeiras 3 6
Arranjos de Pagamentos Compras e relações de consumo 1 2
Arranjos de Pagamentos Conceitos importantes 2 3
Arranjos de Pagamentos Informações Gerais 0 3
Arranjos de Pagamentos Interoperabilidade, liquidação centralizada e compulsório 2 3
Arranjos de Pagamentos Supervisão dos arranjos pelo BC 0 7
Atendimento bancário (fila, feriados e outros) 4 6
Bacen Jud e SISBAJUD Informações gerais 0 1
Bacen Jud e SISBAJUD Ordem judicial de bloqueio/desbloqueio de bens e requisição de informações 0 2
Bacen Jud e SISBAJUD SISBAJUD 0 1
Banco Central do Brasil 2 8
CBE - Capitais Brasileiros no Exterior Acesso ao sistema de declaração 1 2
CBE - Capitais Brasileiros no Exterior Declarações de anos anteriores e multas 2 2
CBE - Capitais Brasileiros no Exterior Entrega e Retificação 1 3
CBE - Capitais Brasileiros no Exterior Exportações 0 3
CBE - Capitais Brasileiros no Exterior Informando os ativos no exterior 2 18
CBE - Capitais Brasileiros no Exterior Iniciando a declaração 0 5
CBE - Capitais Brasileiros no Exterior Obrigatoriedade da declaração 2 3

✔️ 9. Primeiras leituras analíticas

  • Nesta etapa registramos interpretações iniciais que serão úteis na preparação e modelagem.

insights = [
    "O dataset possui estrutura adequada para classificação textual supervisionada.",
    "A variável 'category' será utilizada como target principal do MVP.",
    "O tamanho das perguntas tende a ser menor que o das respostas, o que favorece cenários de triagem por texto curto.",
    "Será necessário avaliar desbalanceamento entre categorias antes da modelagem.",
    "A coluna 'answer' pode ser usada depois em tarefas complementares, como recuperação de resposta ou QA.",
]

for i, insight in enumerate(insights, start=1):
    print(f"{i}. {insight}")
1. O dataset possui estrutura adequada para classificação textual supervisionada.
2. A variável 'category' será utilizada como target principal do MVP.
3. O tamanho das perguntas tende a ser menor que o das respostas, o que favorece cenários de triagem por texto curto.
4. Será necessário avaliar desbalanceamento entre categorias antes da modelagem.
5. A coluna 'answer' pode ser usada depois em tarefas complementares, como recuperação de resposta ou QA.

✔️ 10. Exportação para bronze

  • Nesta etapa salvamos uma cópia padronizada do dataset para a camada bronze, preservando a rastreabilidade do trabalho.

bronze_path_parquet = BRONZE_DIR / "faq_bacen_bronze.parquet"
bronze_path_csv = BRONZE_DIR / "faq_bacen_bronze.csv"

df.to_parquet(bronze_path_parquet, index=False)
df.to_csv(bronze_path_csv, index=False)

print("Arquivo salvo em:")
print(bronze_path_parquet)
print(bronze_path_csv)
Arquivo salvo em:
D:\_DS-Projects\nlp-triagem-inteligente-financeira\data\01-bronze\faq_bacen_bronze.parquet
D:\_DS-Projects\nlp-triagem-inteligente-financeira\data\01-bronze\faq_bacen_bronze.csv

✔️ 11. Encerramento do notebook

  • Principais saídas desta etapa
    • dataset carregado e validado
    • colunas padronizadas
    • variável-alvo principal definida
    • distribuição inicial das classes inspecionada
    • características textuais medidas
    • base exportada para bronze
  • Próximo passo
    • No Notebook 03 — Data Preparation, vamos:
      • limpar os textos
      • revisar classes
      • preparar o dataset final para o baseline

Fim

#!uv pip install nbconvert -U -q
!jupyter nbconvert --to html --template-file my-template-html-v10.tpl 02_data_understanding.ipynb