Adicionando semântica a um croissant
Um arquivo RoboCroissant informa quais arquivos uma base de conhecimento tem e quais colunas eles contêm. Esta habilidade adiciona o que os dados significam: quais colunas juntas descrevem um gene ou uma doença, o que uma linha afirma, qual prefixo de identificador as ids de uma coluna usam, o que os códigos representam. Ela escreve isso em um novo croissant usando construções do Croissant 1.1 e registra o motivo de cada afirmação.
Você produz um plano (JSON, por layout), e os scripts aplicam e verificam o plano. Você não edita o croissant manualmente.
Entradas e saídas
- Entrada: um croissant (
croissant.jsonoucroissant.json.gz) e um diretório de saída, além dosemantics_answers.jsondos mantenedores ao lado do croissant, se houver. - Saída, no diretório de saída:
semantics_plan.json— o plano (formato:reference/plan-format.md)croissant.semantic.json(ou.json.gzse a entrada estiver compactada) — o resultadocheck_report.md— saída decheck.py(echeck_report.load_errors.txt, erros completos do mlcroissant, quando os registros falham ao carregar)notes.md— decisões, layouts omitidos e por quê, e perguntas para os mantenedores da base de conhecimento
O croissant de entrada nunca é modificado. Coloque downloads, scripts auxiliares e outros trabalhos temporários
em OUT/work/, não em outro lugar.
Scripts
Todos em scripts/, executados diretamente (são arquivos uv run --script e instalam suas próprias
dependências). Use --help em qualquer um deles.
| Script | Uso |
|---|---|
inventory.py CROISSANT [--layout ID] [--json F] [--common-columns] | Lista layouts (conjuntos de colunas distintos), do maior para o menor; descreve as colunas, conjuntos de registros e arquivos de um layout; lista as colunas que a maioria dos conjuntos de registros compartilha |
sample.py CROISSANT --layout ID | Lê linhas reais de três dos arquivos do layout; mostra os valores de exemplo de cada coluna e sua forma (CURIs e seus prefixos, ids simples, listas, códigos) |
dialects.py list/show/detect/read | Formatos de arquivo conhecidos (VCF, GAF, MITAB, CTD, ...) como dialetos computáveis; qual deles lê os arquivos de um layout; lê registros usando apenas o que um croissant diz sobre o arquivo |
vocab.py class/slot/search/associations/prefix/identify/term/ols/infores | Consulta classes e slots Biolink (com sugestões de aproximação), classes de associação para um par sujeito/objeto, prefixos de identificadores (Biolink + Bioregistry), quais prefixos se encaixam em ids simples, termos de ontologia por id ou texto, e ids infores para nomes de fontes |
apply_plan.py CROISSANT PLAN OUT | Escreve o plano em um novo croissant |
check.py CROISSANT PLAN OUT --report R --load-records | --plan-only primeiro: termos, prefixos, dialetos e unidades em segundos. Em seguida, a verificação completa: verifica termos, prefixos, códigos e dialetos em relação ao Biolink e dados amostrados, executa o validador MLCommons, lê alguns registros através do mlcroissant (das primeiras linhas de cada arquivo, não downloads completos) e relata a cobertura |
Fluxo de trabalho
-
Levantamento. Se houver um
semantics_answers.jsonao lado do croissant, leia-o primeiro: ele contém as respostas dos mantenedores da base de conhecimento para perguntas anteriores (veja "Respostas do Mantenedor" abaixo). Não faça essas perguntas novamente;apply_plan.pyecheck.pyaplicam as respostas ao seu plano automaticamente. Em seguida,inventory.py CROISSANT. Anote a base de conhecimento (nome, descrição, url no croissant) e como os conjuntos de registros se distribuem entre os layouts. Bases de conhecimento grandes têm centenas de layouts; trabalhe a partir do topo da lista.Encontre o próprio id infores da base de conhecimento agora (
vocab.py infores NOME; tente seu nome completo, sua sigla e sua url) e defina-o comoinforesdo plano. Ele nomeia o recurso cujos arquivos são estes, e os construtores de grafos o citam como a fonte de tudo o que é lido deles: sem ele, a etapa de transformação não construirá a base de conhecimento. Quando várias entradas coincidirem, escolha a do recurso que publica estes arquivos, não de um serviço que os re-serve (infores:reactome, nãoinfores:automat-reactome).check.pyo compara com o que o resto do seu plano diz: uma única constanteaggregatorouprovided_bynomeia a base de conhecimento também (os ortólogos do HCOP são agregados porinfores:hgnc), e uma incompatibilidade é um aviso a ser resolvido.Quando nenhum existir, proponha um:
infores:e o nome curto da base de conhecimento em palavras minúsculas separadas por hífens (infores:bioplex,infores:expression-atlas), com"infores_proposed": trueno plano. Em seguida, escreva sua entrada de catálogo comvocab.py infores-entry CROISSANT --id infores:NOME, adicionando--knowledge-levele--agent-typequando a documentação os tornar claros, e coloque-a emnotes.mdsob um cabeçalho Infores id para registrar, próximo ao topo. Diga lá que o usuário deve registrá-lo com um pull request para o registro infores (o comando imprime onde), e que o id pode mudar na revisão.check.pymantém um aviso em um id proposto até que ele seja registrado; não o explique detalhadamente. -
Escolha os layouts a serem feitos. Mire nos layouts que cobrem a maioria dos conjuntos de registros e o conteúdo principal (associações e as principais tabelas de entidades) — normalmente os 5 a 15 principais, ou até que os layouts restantes sejam menores (arquivos tipo readme, logs, contagens por versão). Se houver muitos layouts pequenos (
inventory.pydirá), os conjuntos de registros provavelmente compartilham colunas principais: useinventory.py --common-columnse planeje essas colunas uma vez commatch.has_columns. Tudo o que você deixar de fora vai para a listaskippeddo plano com um motivo. Fazer menos layouts bem é melhor do que muitos mal. -
Para cada layout, observe os dados antes de decidir qualquer coisa.
inventory.py CROISSANT --layout IDpara colunas, descrições e nomes de arquivos. Uma coluna marcada comoMIXEDtem tipos atômicos diferentes em diferentes conjuntos de registros (o pipeline os infere por arquivo); decida seu tipo a partir dos dados e definaatomic.- Para tabelas,
dialects.py detect CROISSANT --layout IDdescobre como os arquivos são escritos (linhas de comentário, cabeçalho ou nenhum, delimitador) entre formatos conhecidos. Formatos bem conhecidos (VCF, GAF, MITAB) têm especificações publicadas; confie neles em vez de redescobrir o formato. Se nada se encaixar, descreva o dialeto inline (reference/dialects.md). Em seguida, amostre com--dialect NOMEpara que as linhas sejam lidas da maneira que o formato diz, não adivinhada. sample.py CROISSANT --layout IDpara valores reais. Ele lê três arquivos do layout (o de aparência mais recente pelo nome, o maior, o menor), porque um arquivo — geralmente um snapshot antigo ou um subconjunto filtrado — pode esconder valores (placeholdersN/A, valores de código extras, outros tipos de id).--files Namostra mais deles;--record-set IDamostra um arquivo específico. Se a amostragem falhar (um arquivo enorme, um arquivo, um conjunto de arquivos), diga isso nobasisdo plano e diminua a confiança.- Para colunas de código (tipos, evidência, relações, fontes), uma amostra perde valores
raros.
sample.py CROISSANT --record-set ID --profile COL1,COL2lê o arquivo inteiro e conta cada valor distinto; repita--record-setpara somar vários arquivos. Mapeie a partir do perfil, não da amostra. - Seja gentil com os servidores da base de conhecimento. Execute um comando de amostragem ou verificação de cada vez
por base de conhecimento, nunca muitos em paralelo: os hosts bloqueiam rajadas com um desafio de bot, e então
toda requisição posterior falha. Os scripts controlam suas próprias requisições e armazenam downloads em cache (em
~/.cache/croissant-semantics/downloads;--refreshbaixa novamente), então reexecutar é barato (uma cópia em cache sob um--max-mbmaior atende a um menor). Se um script relatar um desafio de bot ou um HTTP 403, pare de amostrar aquele host, não tente contorná-lo, e diga emnotes.mdquais verificações não puderam ser executadas. Os scripts então recusam aquele host por uma hora, entre execuções, e trabalham a partir de arquivos em cache. - Planilhas (xlsx e xls legado), bancos de dados SQLite e arquivos parquet também são amostrados e perfilados: a
planilha ou tabela é aquela com que o nome do conjunto de registros termina ("file.xlsx — Sheet1",
"file.xlsx: Sheet1"), e a amostragem falha em vez de adivinhar quando não consegue identificar. Eles são lidos
por inteiro, então aumente
--max-mbse necessário (também nocheck.py). O mlcroissant não pode ler planilhas ou bancos de dados, portanto seus registros não são carregados. - XML, RDF (Turtle, RDF/XML, OWL), FASTA e outros arquivos que não são tabelas não podem ser amostrados:
os scripts dizem isso. Se um layout for importante, verifique seus ids com um pequeno script em
OUT/work/(uv run --with rdflibpara RDF; faça streaming de XML comxml.etree.ElementTree.iterparse) e diga como emnotes.md. Seus campos geralmente não têmextract, então nenhuma ferramenta pode lê-los: um problema do gerador a ser relatado. --profilecom--layoutperfiliza--filesconjuntos de registros do layout (padrão 3, ouall) em vez de nomear cada um com--record-set.--prefixesconta o prefixo ou tag de cada valor, para todas as colunas perfiladas ou apenas as listadas (--prefixes COL1,COL2);--by COLfaz tabulação cruzada contra outra coluna (com quais tipos de objeto cada código ocorre);--split SEPconta os itens de células de lista;--per-fileperfiliza cada conjunto de registros individualmente (para verificar se os ids são únicos por arquivo);--stop-mb Npara cada arquivo após N MB, para arquivos de muitos GB (as contagens então cobrem apenas o início; em um arquivo classificado por espécie ou id, isso pode ser apenas um grupo, então diga isso).- Perfilize colunas de id dos layouts principais (
--profile COL --shapes) antes de confiar nelas: a verificação de dados lê as primeiras linhas de alguns arquivos, portanto uma coluna cujas linhas posteriores faltam ids, ou contêm outra família de ids, passa. Várias bases de conhecimento tinham 20-30% de linhas sem um id após centenas de linhas que todas tinham um. - Uma entrada
match.has_columnsque cobre muitos layouts é amostrada porcheck.pyem apenas alguns de seus arquivos. Amostre os layouts que ela abrange e que diferem (--record-set-name,--files) antes de confiar nela. - Os scripts usam o armazenamento de certificados do sistema operacional. Se os downloads ainda falharem com um erro de certificado, relate-o com a saída; não desative a verificação.
- Se a documentação estiver atrás de uma verificação de bot ("verify you are human", um desafio Cloudflare ou
ALTCHA), não tente contorná-la; planeje a partir de dados e nomes, e limite a confiança a
mediumpara significados que apenas a documentação poderia confirmar. A proveniência do croissant pode citar páginas que desde então foram colocadas atrás de uma verificação: cite apenas o que você pôde ler. - Em um arquivo enorme, as primeiras linhas podem ser não representativas (o CTD de 3 GB
genes_diseasescomeça com milhares de linhas inferidas). Perfilize um arquivo menor do mesmo layout (o subconjunto curado) em vez de fazer streaming de tudo. - Para selecionar conjuntos de registros pelo nome, use
--record-set-name REGEX(em vez de--layout) em vez de construir uma lista de argumentos--record-setno shell (o zsh não divide variáveis em palavras).--per-filemostra cada arquivo amostrado separadamente, para layouts cujos arquivos diferem (um tipo de id por arquivo). - A verificação de dados lê as primeiras linhas de alguns arquivos. As linhas posteriores de uma coluna podem diferir (nós
em branco após 200 IRIs, um código raro): confirme formas de id e códigos com
--profile, que lê arquivos inteiros. inventory.pylista arquivos de documentação enviados com os dados (README.pdf dentro de um zip, um dicionário de dados) após os layouts. Leia os relevantes:sample.py CROISSANT --dump ARQUIVOimprime um arquivo como texto,--member NOMEum membro de um arquivo (um zip é lido por inteiro, então aumente--max-mbpara um grande) (ele lista os membros de um zip quando o nome está errado),--sheet NOMEuma planilha de uma planilha.sample.pysinaliza colunas cujo tipo declarado não se encaixa nos valores (uma colunasc:Integercontendo27152464|29518214) e arquivos cujas linhas são mais largas ou mais estreitas que o cabeçalho. Ambos são geralmente problemas de pipeline: corrija tipos comatomice os relate.- Quando os scripts não conseguem ler uma fonte, busque os arquivos você mesmo (um de cada vez, em
OUT/work/) e aponte os scripts para eles com--url-map OLD=file:///caminho/absoluto/para que suas verificações ainda sejam executadas, em vez de escrever seus próprios perfiladores. Os downloads são armazenados em cache, e~/.cache/croissant-semantics/downloads/index.tsvmapeia cada arquivo em cache para sua URL. - Se os "nomes de colunas" de um layout são na verdade dados (sem linha de cabeçalho, então o pipeline pegou a
primeira linha de dados como nomes, e cada arquivo se tornou seu próprio layout), pule-o e relate-o em
notes.mdcomo um problema de pipeline. - Se as URLs dos dados não existirem mais (HTTP 404), a base de conhecimento provavelmente mudou para uma versão mais
recente. Encontre as URLs atuais em sua página de download e passe
--url-map OLD=NEWparasample.pyecheck.py(por exemplo,--url-map 202607=202610). Quando mais do que a versão mudar (outro caminho ou nome de arquivo), mapeie URLs inteiras, uma--url-map URL_ANTIGA=URL_NOVApor arquivo. Quando as próprias URLs contiverem=(strings de consulta), escrevaURL_ANTIGA=>URL_NOVA. Diga isso emnotes.md; também é um problema de pipeline. Uma URL de endpoint SPARQL que retorna JSON onde o croissant descreve uma tabela geralmente precisa de&format=csv(outext/csv) mapeado. - Arquivos: membros de arquivos zip e tar são amostrados. Um zip é baixado por inteiro (até
--max-mb); um tar é transmitido até que o membro seja encontrado, portanto um membro profundamente dentro de um tar enorme pode exceder--max-mb. Um arquivo que falha uma vez não é tentado novamente, e a amostragem para após falhas repetidas. Se necessário, extraia um membro emOUT/work/você mesmo e registre o que verificou e como emnotes.md. - Se os dados precisarem de login ou chave de API (HTTP 401/403, ou o
conditionsOfAccessdo croissant disser isso), não procure por credenciais. Planeje a partir da documentação e apenas dos nomes das colunas:sourceédocumentationouagent,confidenceno máximomedium, enotes.mddiz que nada foi verificado contra os dados. - Procure por um dicionário de dados enviado que um layout não tem; ignore layouts de tabela e enumeração. Se houver um arquivo de dicionário de dados separado, leia-o.
- Ao planejar uma única coluna que contém
|ou outra lista de valores, declare o tipo de célula comosc:List.
-
Para cada layout, decida a semântica.
- Combine colunas em entidades Biolink com
entity: ENTIDADE(vejareference/plan-format.md). Cada entidade tem uma ou mais colunas de id (com@idou@typenoentity, e umidentifiernomatch.has_columns), e outras colunas para rótulos (nomes, descrições) e atributos (espécie, tipo de célula, ...). Definacolumns: ALLpara uma entidade de coluna única; isso captura colunas queinventory.pyainda não viu (de layouts para os quais você escreveu um plano sem entidade, e elas aparecerão depois). - Tipo de linha: quando um layout descreve associações (gene-doença, variante-gene), dê a ele um
row_typeBiolink. As classes de associação ligam umsubjecte umobject(vejareference/plan-format.md). Quando não houver associação, definarow_typecomo a entidade da linha. - Identificadores de entrada: cada coluna de id precisa de um prefixo de identificador. Use
vocab.pyidentifypara encontrá-lo a partir dos valores da coluna. Quando o prefixo não for conhecido pelo Biolink, useidentifiers.orge definaprefix_in_biolink: falseno prefixo. Quando um valor não for um CURIE e não houver prefixo (ids simples), definaexamplee confie no propósito da coluna. - Códigos: coloque cada coluna de código em um
code_sete mapeie seus valores usandocodes. - Unidades: defina a unidade na coluna e use
vocab.py termpara encontrá-la no UO. - Colunas de string com poucos valores distintos podem ser colunas de código: se
--profileas mostrar repetindo, crie umcode_setpara elas. - Para uma coluna de string com muitos valores, verifique se os valores são ids que pertencem a
outra entidade: declare
references: ENTIDADEcom o prefixo da outra entidade. Não crie uma entidade para a outra tabela aqui; isso é para o layout dela. - Colunas com nomes como
ICD10_CODEpodem conter códigos de ontologia. Usevocab.py identifypara encontrá-los e mapeie para uma ontologia Biolink. - Colunas com nomes como
p-valueouscoredevem ter umdata_typenumérico eunit. - Para colunas booleanas e de data, defina
data_typeadequadamente. - Colunas de descrição longa devem ser marcadas como
description. - Colunas de nome devem ser marcadas como
name. - Quando uma coluna tiver vários propósitos, escolha o principal e anote o resto em
notes.md. - Colunas computadas derivadas de outros campos não precisam de semântica: marque-as como
derived. - Colunas de chave estrangeira que referenciam uma entidade diferente da linha devem ser marcadas como
foreign_keycomreferences: ENTIDADE. - Colunas de array devem ter
is_array: true.
- Combine colunas em entidades Biolink com
-
Escreva o plano. Siga
reference/plan-format.mdexatamente. O plano cobre todos os layouts que você decidiu fazer e lista aqueles que você omitiu com um motivo. Executecheck.py --plan-onlycom frequência; ele verifica a estrutura e sabe quais consultas de vocabulário são lentas. As opções do plano que você não usar devem ser omitidas, não definidas como nulas. -
Aplique e verifique.
apply_plan.py CROISSANT PLAN OUTproduz o novo croissant.check.py CROISSANT PLAN OUTverifica tudo. Execute--plan-onlyprimeiro, depois a verificação completa. Execute com--load-recordsquando quiser que alguns registros sejam carregados (principalmente para relatar cobertura).- Quando a verificação falhar, corrija o plano (e a amostragem, se você perdeu um valor) e reaplique. Não edite o croissant de saída.
- Quando a verificação emitir avisos, decida se eles merecem uma correção do plano ou uma anotação em
notes.md. - Após a verificação completa passar sem erros fatais, escreva
notes.md. Deve ter:- Infores id to register se você propôs um.
- Pipeline problems: erros no croissant de entrada que afetam a semântica.
- Decisions: escolhas não óbvias no plano, como você resolveu ambiguidades.
- Skipped layouts: cada um com um motivo.
- Questions for maintainers: perguntas para as quais apenas os mantenedores da base de conhecimento sabem a resposta.
- Verification notes: quaisquer verificações que você não pôde executar e por quê.
Respostas do Mantenedor
O arquivo semantics_answers.json contém respostas dos mantenedores da base de conhecimento para perguntas
feitas em uma execução anterior. Ele pode conter:
prefix_for: COLUNA -> PREFIXOpara mapear uma coluna de id a um prefixo.code_set_for: COLUNA -> lista de códigospara mapear códigos no formato{código: {id: ontologia_id, label: rótulo, parents: [ids_pai]}}.entity_for: COLUNA -> ENTIDADEpara definir a entidade de uma coluna.row_type_for: LAYOUT -> TIPOpara definir o tipo de linha de um layout.infores: IDpara definir o id infores.url_map: URL_ANTIGA -> URL_NOVApara mapear URLs antigas para novas.dialect: LAYOUT -> DIALETOpara definir o dialeto de um layout.skip: LAYOUT -> motivopara pular um layout.
apply_plan.py e check.py aplicam essas respostas automaticamente ao seu plano, se presentes. Você não precisa
incluí-los em seu plano; eles são aplicados por cima.
Notas
- Confiança: Cada declaração semântica pode ter uma confiança:
high(verificada contra dados reais),medium(de documentação ou heurística forte),low(adivinhada). Defina a confiança no plano. - Fonte: Cada declaração pode ter uma fonte:
data,documentation,agent(você),inferred,maintainer. Defina a fonte no plano. - Base: O plano deve ter um campo
basisque descreve o que você examinou para fazer cada declaração. - O plano é um JSON com chaves
layouts,infores,basis,skipped. Cada layout tem chavesid,entity,row_type,match,columns,code_sets,dialect.