Inspetor de .npy e .npz do NumPy
Um .npy é um cabeçalho minúsculo seguido de um bloco cru de números, e esse cabeçalho é a única parte de que esta ferramenta precisa: seis bytes mágicos, uma versão, um comprimento e um literal de dicionário Python —não JSON— com descr, fortran_order e shape. Como só o primeiro quilobyte é lido, um array de dois gigabytes abre tão rápido quanto um de dois quilobytes, e é exatamente esse o ponto: descobrir o que há dentro antes de decidir se vale a pena carregar. O descr é decodificado do mesmo jeito que o numpy faria. O primeiro caractere é a ordem de bytes —< pequena, > grande, | não se aplica— e um arquivo big-endian é sinalizado, porque lê-lo errado não se parece com um erro: os números simplesmente saem sendo outros números. Depois vêm a classe e o tamanho do item: booleanos b1, inteiros de i1 a i8 e de u1 a u8, floats f2, f4 e f8, complexos c8 e c16, cadeias de bytes S<n> que mantêm NULs internos e perdem os finais, texto U<n> guardado como UCS-4 de modo que três caracteres ocupam doze bytes, datas M8 e m8 com a unidade entre colchetes, V<n> cru, e O, que significa que o array foi escrito com allow_pickle=True e que carregá-lo executa o que foi serializado — por isso o aviso aparece em destaque e não de passagem. Um dtype estruturado chega como uma lista de tuplas (nome, formato) ou (nome, formato, shape), que ainda pode ser aninhada; os deslocamentos não são guardados em lugar nenhum, são a soma acumulada dos tamanhos, e é por isso que um dtype alinhado carrega campos de preenchimento sem nome no próprio descr — que também aparecem aqui, com o intervalo que ocupam. O resto é conta que você pode conferir: elementos a partir do shape, bytes esperados como elementos vezes tamanho do item, e os bytes realmente presentes depois do cabeçalho, de forma que um arquivo cortado por uma cópia falha ou um disco cheio aparece como falta e não como um cabeçalho de aparência impecável. Os primeiros valores são decodificados na própria página para os dtypes numéricos simples, na ordem em que estão no arquivo, então um array em ordem Fortran é lido coluna a coluna. Um .npz é um zip de membros .npy, listados com dtype, shape, os dois tamanhos e se foram comprimidos. O que ela não faz: desserializar um pickle, dizer o que os números significam ou verificar se os dados prestam; ela relata o que o arquivo afirma e onde essa afirmação briga com o tamanho.
Como usar
- Solte um .npy ou um .npz na caixa. Só o cabeçalho é lido, então o tamanho do arquivo não importa.
- Veja primeiro o dtype, o shape e a contagem de elementos: é a resposta para "o que há aqui dentro" e custa uma leitura.
- Compare Dados esperados com Dados presentes: menos significa arquivo truncado, mais significa que algo foi acrescentado depois do array.
- Se o dtype for estruturado, abra a tabela de campos: ela dá formato, deslocamento e tamanho de cada um, inclusive o preenchimento sem nome que um dtype alinhado insere.
- Num .npz, clique no nome de um membro para inspecionar aquele array; a lista mostra quanto cada membro ocupa dentro do arquivo e já descompactado.
Perguntas frequentes
- O que exatamente há no cabeçalho de um .npy?
- Seis bytes mágicos (\x93NUMPY), uma versão de dois bytes, um comprimento de cabeçalho e então o cabeçalho: um literal de dicionário Python com exatamente três chaves, descr, fortran_order e shape. Não é JSON e JSON.parse não consegue lê-lo: as strings usam aspas simples, os booleanos são True e False, o shape é uma tupla escrita (3,) e não (3), e há uma vírgula sobrando antes da chave de fechamento. O literal é preenchido com espaços para que os dados do array comecem num múltiplo de 64 bytes, que é o que permite ao numpy mapear o arquivo em memória com cargas alinhadas. Aqui o descr aparece exatamente como está escrito, para você comparar com o que o numpy informa sem se perguntar se algo foi normalizado no caminho.
- Por que meu array de strings ocupa quatro vezes o número de caracteres?
- Porque o dtype U do numpy guarda UCS-4: cada caractere são quatro bytes fixos, seja qual for, então o tamanho do item é quatro vezes o comprimento declarado. Um campo U32 custa 128 bytes por elemento mesmo que todos os valores sejam "ok". As cadeias de bytes (S) custam um byte por caractere, mas trazem a própria surpresa: os NULs finais são removidos na leitura, então um valor que realmente termina em byte zero não sobrevive à ida e volta, enquanto os NULs internos ficam. Se um conjunto de dados está inesperadamente grande, a causa costuma ser um dtype U, e a saída normal é guardar o texto como S com uma codificação explícita, ou manter as strings num array separado.
- O dtype diz object. O que isso significa e por que o aviso?
- Um array de objetos não guarda valores, guarda ponteiros, então o numpy serializa tudo com pickle ao salvar e desserializa ao carregar. Desserializar não é analisar: pode construir objetos arbitrários e chamar código arbitrário, e é por isso que numpy.load recusa arrays de objetos a menos que você passe allow_pickle=True. Um .npy cujo descr é |O é tanto um programa quanto um dado, e a segurança dele é a de quem o escreveu. Esta página nunca desserializa nada: informa o dtype e o tamanho do pickle e para por aí. Se o array guarda strings comuns ou listas irregulares, quase sempre vale reescrevê-lo com um dtype de largura fixa ou como vários arrays dentro de um .npz.
- O que fortran_order muda de fato?
- Apenas a ordem em que os mesmos números aparecem no arquivo. Com fortran_order False o último eixo varia mais rápido (C, por linhas); com True é o primeiro (por colunas), que é o que sai de np.asfortranarray ou de dados vindos de Fortran ou MATLAB. O shape e o dtype são idênticos nos dois casos, então um leitor que ignore a flag não falha: ele transpõe o array em silêncio, o que é bem pior que uma exceção. A prévia aqui segue o arquivo e não a disposição lógica, então um array 2×3 em ordem Fortran é lido como coluna 0, coluna 1 e coluna 2.
- Por que existem três versões do formato?
- A 1.0 guarda o comprimento do cabeçalho em dois bytes, o que o limita a 65535 bytes. A 2.0 usa quatro bytes para o caso raro em que isso não basta: um dtype estruturado com alguns milhares de campos consegue, e o cabeçalho pode ter centenas de quilobytes. A 3.0 é igual à 2.0, mas declara o cabeçalho como UTF-8 em vez de Latin-1, e o numpy só a escreve quando um nome de campo tem um caractere que o Latin-1 não comporta. O numpy sempre escolhe a menor versão que couber, então um arquivo 2.0 ou 3.0 já diz algo por si só. Vale saber também que o próprio carregador do numpy recusa qualquer cabeçalho acima de 10000 bytes a menos que max_header_size seja aumentado, de modo que um arquivo 2.0 legítimo pode não abrir no Python e abrir aqui.
- O arquivo é enviado para algum lugar? Dá para abrir um array enorme?
- Nada é enviado, e dá. O arquivo é lido pela File API do navegador e só em fatias: o primeiro quilobyte para o cabeçalho e alguns quilobytes a mais para a prévia de valores. Um array de 2 GB nunca fica na memória, que é exatamente o caso para o qual isto existe: alguém te passa um arquivo, você quer o dtype e o shape, e carregá-lo custaria minutos e quase toda a RAM. Num .npz só são lidos o diretório zip no fim do arquivo e o cabeçalho de cada membro, então listar um arquivo são duas leituras mais uma por membro. Como nada é transmitido, você pode desconectar a rede depois que a página carregar e tudo continua funcionando.
Ferramentas relacionadas
Inspetor de arquivos TAR
Abra um .tar, .tar.gz ou .tgz e liste cada entrada — permissões, dono, tamanho, data e destino do link — sem extrair nada.
Inspetor de fluxos xz (.xz)
Leia um contêiner .xz: cabeçalho do fluxo, cada cabeçalho de bloco e sua cadeia de filtros, o índice e o rodapé, com o tamanho real sem descomprimir nada.
Inspetor de arquivos gzip (.gz)
Leia o cabeçalho de um .gz campo a campo, percorra todos os membros e verifique o trailer recalculando o CRC32 e o tamanho real no navegador.
Inspetor de bancos de dados SQLite
Abra um arquivo .sqlite ou .db no navegador e leia sua estrutura: tamanho de página, codificação, modo de journal e as linhas reais de cada tabela.
Inspetor de bibliotecas estáticas .a
Leia um arquivo .a no navegador: membros com tamanhos e datas, os símbolos que cada objeto define e precisa, e se o índice de símbolos ficou desatualizado.
Visualizador CSV com Ordenação
Veja dados CSV / TSV como tabela ordenável e pesquisável — abra um arquivo ou cole linhas, sem planilha.