Olá pessoal!
O lançamento do curso
“Python Web Developer” está se aproximando, respectivamente, ainda estamos compartilhando artigos interessantes e nos convidando para nossas lições abertas, onde você pode assistir material interessante, conhecer
professores e fazer perguntas.
Vamos lá!
O HDF5 permite armazenamento eficiente de grandes quantidades de dadosAo trabalhar com grandes volumes de dados, sejam experimentais ou simulados, armazená-los em vários arquivos de texto não é muito eficiente. Às vezes, você precisa acessar um subconjunto específico de dados e deseja fazê-lo rapidamente. Nessas situações, o formato HDF5 resolve os dois problemas graças a uma biblioteca interna altamente otimizada. O HDF5 é amplamente utilizado em ambientes científicos e possui uma excelente implementação em Python, projetada para funcionar com o NumPy imediatamente.
O formato HDF5 suporta arquivos de qualquer tamanho e cada arquivo possui uma estrutura interna que permite procurar um conjunto de dados específico. Isso pode ser pensado como um arquivo separado com sua própria estrutura hierárquica, bem como um conjunto de pastas e subpastas. Por padrão, os dados são armazenados em formato binário e a biblioteca é compatível com diferentes tipos de dados. Uma das opções mais importantes para o formato HDF5 é que ele permite anexar metadados a cada elemento da estrutura, tornando-o ideal para a criação de arquivos offline.

No Python, uma interface com o formato HDF5 pode ser criada usando o pacote h5py. Um dos recursos mais interessantes deste pacote é que os dados são lidos de um arquivo somente quando necessário. Imagine que você tem uma matriz muito grande que não cabe na sua RAM disponível. Por exemplo, você pode gerar uma matriz em um computador com especificações diferentes, diferente da usada para análise de dados. O formato HDF5 permite escolher quais elementos da matriz serão lidos com sintaxe equivalente a NumPy. Em seguida, você pode trabalhar com dados armazenados no disco rígido, e não na RAM, sem alterações significativas no código existente.
Neste artigo, veremos como você pode usar o h5py para armazenar e recuperar dados do seu disco rígido. Discutiremos diferentes maneiras de armazenar dados e como otimizar o processo de leitura. Todos os exemplos que aparecem neste artigo também estão disponíveis em nosso
repositório Github .
InstalaçãoO formato HDF5 é suportado pelo
Grupo HDF e é baseado em padrões de código aberto, o que significa que seus dados estarão sempre disponíveis, mesmo que o grupo desapareça. O suporte ao Python é fornecido através do pacote
h5py , que pode ser instalado via pip. Lembre-se de que você deve usar o ambiente
virtual para testar:
pip install h5py
este comando também instalará o NumPy se não estiver no seu ambiente.
Se você estiver procurando por uma ferramenta gráfica para examinar o conteúdo de seus arquivos HDF5, poderá instalar o
HDF5 Viewer . Como está escrito em Java, deve funcionar em praticamente qualquer computador.
Armazenamento e leitura de dados básicosVamos passar a usar a biblioteca HDF5. Criaremos um novo arquivo e salvaremos um array NumPy aleatório.
import h5py import numpy as np arr = np.random.randn(1000) with h5py.File('random.hdf5', 'w') as f: dset = f.create_dataset("default", data=arr)
As primeiras linhas são bem simples: importamos os pacotes h5py e NumPy e criamos uma matriz com valores aleatórios. Abrimos o arquivo random.hdf5 com permissão de gravação w, o que significa que, se um arquivo com o mesmo nome já existir, ele será substituído. Se você quiser salvar o arquivo e ainda conseguir gravar nele, poderá abri-lo com o atributo a em vez de w. Criamos um conjunto de dados chamado padrão e configuramos os dados como uma matriz aleatória criada anteriormente. Os conjuntos de dados são os guardiões dos nossos dados, principalmente os blocos de construção do formato HDF5.
Uma nota
Se você não estiver familiarizado com a declaração with, devo observar que esta é uma maneira conveniente de abrir e fechar arquivos. Mesmo se ocorrer um erro interno, o arquivo será fechado. Se, por algum motivo, você não estiver usando, nunca se esqueça de adicionar o comando
f.close()
ao final. A instrução
with
funciona com qualquer arquivo, não apenas com arquivos HDF.
Podemos ler os dados quase da mesma maneira que lemos o arquivo NumPy:
with h5py.File('random.hdf5', 'r') as f: data = f['default'] print(min(data)) print(max(data)) print(data[:15])
Abrimos o arquivo com o atributo de leitura r e restauramos os dados acessando diretamente o conjunto de dados chamado padrão. Se você abrir o arquivo e não souber quais conjuntos de dados estão disponíveis, poderá obtê-los:
for key in f.keys(): print(key)
Depois de ler o conjunto de dados desejado, você pode usá-lo como se estivesse usando qualquer matriz NumPy. Por exemplo, você pode encontrar os valores máximo e mínimo ou selecionar os 15 primeiros valores da matriz. Esses exemplos simples, no entanto, ocultam muitas coisas que acontecem sob o capô e precisam ser discutidos para entender todo o potencial do HDF5.
No exemplo acima, você pode usar os dados como uma matriz. Por exemplo, você pode consultar o terceiro elemento inserindo os dados [2] ou obter um intervalo de valores [1: 3]. Observe: os dados não são uma matriz, são um conjunto de dados. Você pode vê-lo digitando
print(type(data))
. Os conjuntos de dados funcionam de uma maneira completamente diferente das matrizes, porque suas informações são armazenadas no disco rígido e não são carregadas na RAM se não as usarmos. O código a seguir, por exemplo, não funcionará:
f = h5py.File('random.hdf5', 'r') data = f['default'] f.close() print(data[1])
O erro que aparece é um pouco complicado, mas a última linha é muito útil:
ValueError: Not a dataset (not a dataset)
O erro significa que estamos tentando acessar um conjunto de dados ao qual não temos mais acesso. Isso é um pouco confuso, mas acontece porque fechamos o arquivo e, portanto, não temos mais permissão para acessar o segundo valor nos dados. Quando atribuímos f ['padrão'] aos dados variáveis, na verdade não lemos os dados do arquivo; em vez disso, geramos um ponteiro para onde os dados estão no disco rígido. Por outro lado, esse código funcionará:
f = h5py.File('random.hdf5', 'r') data = f['default'][:] f.close() print(data[10])
Observe que a única diferença é que adicionamos [:] após a leitura do conjunto de dados. Muitos outros manuais se concentram nesses exemplos, sem sequer demonstrar todo o potencial do formato HDF5 com o pacote h5py. Por causa dos exemplos que examinamos até agora, você deve estar se perguntando: por que usar o HDF5 se salvar os arquivos NumPy oferece a mesma funcionalidade? Vamos nos aprofundar nos recursos do formato HDF5.
Leitura seletiva de arquivos HDF5Até agora, vimos que, quando lemos um conjunto de dados, ainda não estamos lendo dados do disco, em vez disso, criamos um link para um local específico no disco rígido. Podemos ver o que acontece se, por exemplo, lemos explicitamente os 10 primeiros elementos de um conjunto de dados:
with h5py.File('random.hdf5', 'r') as f: data_set = f['default'] data = data_set[:10] print(data[1]) print(data_set[1])
Dividimos o código em linhas diferentes para torná-lo mais explícito, mas você pode ser mais sintético em seus projetos. Nas linhas acima, primeiro lemos o arquivo e depois o conjunto de dados padrão. Atribuímos os 10 primeiros elementos do conjunto de dados à variável de dados. Depois de fechar o arquivo (quando ele termina), podemos acessar os valores armazenados nos dados, mas o data_set gera um erro. Observe que apenas lemos do disco quando acessamos explicitamente os 10 primeiros elementos de um conjunto de dados. Se você observar os tipos de dados e data_set, verá que eles são realmente diferentes. O primeiro é um array NumPy e o segundo é um DataSet h5py.
O mesmo comportamento é relevante em cenários mais complexos. Vamos criar um novo arquivo, desta vez com dois conjuntos de dados, e vamos selecionar os elementos de um deles com base nos elementos do outro. Vamos começar criando um novo arquivo e armazenando dados; esta parte é a mais simples:
import h5py import numpy as np arr1 = np.random.randn(10000) arr2 = np.random.randn(10000) with h5py.File('complex_read.hdf5', 'w') as f: f.create_dataset('array_1', data=arr1) f.create_dataset('array_2', data=arr2)
Temos dois conjuntos de dados chamados array_1 e array_2, cada um contendo um array NumPy aleatório. Queremos ler os valores da matriz_2 que correspondem aos elementos em que os valores da matriz_1 são positivos. Podemos tentar fazer algo assim:
with h5py.File('complex_read.hdf5', 'r') as f: d1 = f['array_1'] d2 = f['array_2'] data = d2[d1>0]
mas isso não vai funcionar. d1 é um conjunto de dados e não pode ser comparado com um número inteiro. A única maneira é realmente ler os dados do disco e compará-los. Portanto, temos algo parecido com isto:
with h5py.File('complex_read.hdf5', 'r') as f: d1 = f['array_1'] d2 = f['array_2'] data = d2[d1[:]>0]
O primeiro conjunto de dados d1 é completamente carregado na memória quando d1 [:], mas a partir do segundo conjunto de dados d2 pegamos apenas alguns elementos. Se o conjunto de dados d1 fosse muito grande para ser carregado inteiramente na memória, poderíamos trabalhar dentro de um loop.
with h5py.File('complex_read.hdf5', 'r') as f: d1 = f['array_1'] d2 = f['array_2'] data = [] for i in range(len(d1)): if d1[i] > 0: data.append(d2[i]) print('The length of data with a for loop: {}'.format(len(data)))
Obviamente, existem problemas com a eficiência da leitura item por item e da adição de itens à lista, mas este é um exemplo muito bom de uma das maiores vantagens do uso do HDF5 sobre arquivos de texto ou NumPy. Dentro do loop, carregamos apenas um elemento na memória. No nosso exemplo, cada elemento é simplesmente um número, mas pode ser qualquer coisa: do texto à imagem ou vídeo.
Como sempre, dependendo do seu aplicativo, você deve decidir se deseja ou não ler a matriz inteira. Às vezes, você executa simulações em um computador específico com uma grande quantidade de memória, mas não possui as mesmas características no seu laptop e é forçado a ler partes de seus dados. Lembre-se de que a leitura do disco rígido é relativamente lenta, especialmente se você usar o HDD em vez de discos SDD ou até mais se ler de uma unidade de rede.
Gravar seletivamente em arquivos HDF5Nos exemplos acima, adicionamos dados ao conjunto de dados assim que ele foi criado. No entanto, para muitos aplicativos, você precisa salvar dados durante a geração. O HDF5 permite salvar dados da mesma maneira que você os lê. Vamos ver como criar um conjunto de dados vazio e adicionar alguns dados a ele.
arr = np.random.randn(100) with h5py.File('random.hdf5', 'w') as f: dset = f.create_dataset("default", (1000,)) dset[10:20] = arr[50:60]
As duas primeiras linhas são as mesmas de antes, exceto para
create_dataset
. Não adicionamos dados ao criá-los, apenas criamos um conjunto de dados vazio que pode conter até 1000 elementos. Com a mesma lógica de antes, quando lemos certos elementos de um conjunto de dados, na verdade gravamos no disco apenas quando atribuímos valores a certos elementos da variável dset. No exemplo acima, atribuímos apenas valores a um subconjunto da matriz, com índices de 10 a 19.
AdvertênciaNão é inteiramente verdade o que você grava no disco quando atribui valores a um conjunto de dados. O momento exato depende de vários fatores, incluindo o estado do sistema operacional. Se o programa fechar muito cedo, pode acontecer que nem tudo seja gravado. É muito importante sempre usar o método
close()
e, caso você escreva em etapas, você também pode usar
flush()
para forçar a entrada. O uso com evita muitos problemas de gravação.
Se você ler o arquivo e imprimir os 20 primeiros valores do conjunto de dados, verá que todos são zeros, exceto os índices 10 a 19. Há um erro comum que pode levar a uma dor de cabeça perceptível. O código a seguir não salvará nada no disco:
arr = np.random.randn(1000) with h5py.File('random.hdf5', 'w') as f: dset = f.create_dataset("default", (1000,)) dset = arr
Esse erro sempre causa muitos problemas, porque você não entenderá que não escreveu nada até tentar ler o resultado. O problema aqui é que você não especifica onde deseja armazenar os dados, apenas sobrescreve a variável dset com uma matriz NumPy. Como o conjunto de dados e a matriz têm o mesmo comprimento, você deve usar dset [:] = arr. Esse erro ocorre com mais frequência do que você pensa e, como tecnicamente não está errado, você não verá nenhum erro no terminal e seus dados serão zeros.
Até agora, sempre trabalhamos com matrizes unidimensionais, mas não estamos limitados a eles. Por exemplo, suponha que desejamos usar uma matriz 2D, podemos simplesmente fazer:
dset = f.create_dataset('default', (500, 1024))
o que nos permite armazenar dados em uma matriz de 500 x 1024. Para usar um conjunto de dados, podemos usar a mesma sintaxe de antes, mas levando em consideração a segunda dimensão:
dset[1,2] = 1 dset[200:500, 500:1024] = 123
Especifique tipos de dados para otimizar o espaçoAté agora, examinamos apenas a ponta do iceberg do que o HDF5 tem a oferecer. Além do comprimento dos dados que você deseja manter, você pode especificar o tipo de dados para otimizar o espaço.
A documentação do h5py contém uma lista de todos os tipos suportados. Aqui, mostramos apenas alguns deles. Ao mesmo tempo, trabalharemos com vários conjuntos de dados em um arquivo.
with h5py.File('several_datasets.hdf5', 'w') as f: dset_int_1 = f.create_dataset('integers', (10, ), dtype='i1') dset_int_8 = f.create_dataset('integers8', (10, ), dtype='i8') dset_complex = f.create_dataset('complex', (10, ), dtype='c16') dset_int_1[0] = 1200 dset_int_8[0] = 1200.1 dset_complex[0] = 3 + 4j
No exemplo acima, criamos três conjuntos de dados diferentes, cada um com um tipo diferente. Inteiros de 1 byte, inteiros de 8 bytes e números complexos de 16 bytes. Armazenamos apenas um número, mesmo que nossos conjuntos de dados possam conter até 10 elementos. Você pode ler os valores e ver o que realmente foi salvo. Deve-se observar aqui que um número inteiro de 1 byte deve ser arredondado para 127 (em vez de 1200), e um número inteiro de 8 bytes deve ser arredondado para 1200 (em vez de 1200.1).
Se você já programou em idiomas como C ou Fortran, provavelmente sabe o que significam diferentes tipos de dados. No entanto, se você sempre trabalhou com Python, pode não ter encontrado nenhum problema sem declarar explicitamente o tipo de dados com o qual está trabalhando. É importante lembrar que o número de bytes indica quantos números diferentes você pode salvar. Se você usa 1 byte, possui 8 bits e, portanto, pode armazenar 2 ^ 8 números diferentes. No exemplo acima, os números inteiros são positivos, negativos e 0. Quando você usa números inteiros de 1 byte, pode armazenar valores de -128 a 127, no total são 2 ^ 8 números possíveis. Isso equivale a usar 8 bytes, mas com uma grande variedade de números.
O tipo de dados selecionado afetará seu tamanho. Primeiro, vamos ver como isso funciona com um exemplo simples. Vamos criar três arquivos, cada um com um conjunto de dados para 100.000 elementos, mas com diferentes tipos de dados. Salvaremos os mesmos dados neles e compararemos seus tamanhos. Criamos uma matriz aleatória para atribuição a cada conjunto de dados para preencher a memória. Lembre-se de que os dados serão convertidos para o formato especificado no conjunto de dados.
arr = np.random.randn(100000) f = h5py.File('integer_1.hdf5', 'w') d = f.create_dataset('dataset', (100000,), dtype='i1') d[:] = arr f.close() f = h5py.File('integer_8.hdf5', 'w') d = f.create_dataset('dataset', (100000,), dtype='i8') d[:] = arr f.close() f = h5py.File('float.hdf5', 'w') d = f.create_dataset('dataset', (100000,), dtype='f16') d[:] = arr f.close()
Ao verificar o tamanho de cada arquivo, você terá algo como:
Ficheiro | Tamanho (b) |
---|
inteiro_1 | 102144 |
inteiro_9 | 802144 |
flutuar | 1602144 |
A relação entre tamanho e tipo de dados é clara. Quando você passa de números inteiros de 1 byte a até 8 bytes, o tamanho do arquivo aumenta em 8 vezes, da mesma forma, quando você passa para 16 bytes, leva cerca de 16 vezes mais espaço. Mas o espaço não é o único fator importante a considerar; você também deve considerar o tempo que leva para gravar dados no disco. Quanto mais você escrever, mais tempo será necessário. Dependendo da sua aplicação, pode ser crucial otimizar a leitura e gravação de dados.
Observação: se você usar o tipo de dados errado, também poderá perder informações. Por exemplo, se você possui números inteiros de 8 bytes e os armazena como números inteiros de 1 byte, seus valores serão truncados. Ao trabalhar no laboratório, os dispositivos que criam diferentes tipos de dados geralmente estão disponíveis. Algumas placas DAQ têm 16 bits, algumas câmeras funcionam com 8 bits, mas algumas podem funcionar com 24. É importante prestar atenção aos tipos de dados, mas isso também é algo que os desenvolvedores do Python podem não levar em consideração, porque você não precisa explicitamente declarar tipo.
Também é interessante lembrar que a matriz NumPy padrão será flutuante com 8 bytes (64 bits) por elemento. Isso pode ser um problema se, por exemplo, você inicializar uma matriz com zeros para armazenar dados, que devem ter apenas 2 bytes. O tipo da matriz em si não será alterado. Se você salvar os dados ao criar o conjunto de dados (adicionando dados = minha_ matriz), o formato padrão será "f8", que é uma matriz, mas não dados reais,
Pensar nos tipos de dados não é algo que acontece regularmente se você trabalha com Python em aplicativos simples. No entanto, você deve estar ciente de que existem tipos de dados e que impacto eles podem ter nos seus resultados. Você pode ter discos rígidos grandes e não se importa muito com o armazenamento de arquivos, mas quando se importa com a velocidade com que salva, não há outra maneira senão otimizar todos os aspectos do seu código, incluindo tipos de dados.
Compressão de dadosAo salvar dados, você pode escolher a compactação usando algoritmos diferentes. O pacote h5py suporta vários filtros de compactação, como GZIP, LZF e SZIP. Ao usar um dos filtros de compactação, os dados serão processados no caminho para o disco e, após a leitura, serão descompactados. Portanto, não há alterações especiais no código. Podemos repetir o mesmo experimento, salvando diferentes tipos de dados, mas usando um filtro de compactação. Nosso código fica assim:
import h5py import numpy as np arr = np.random.randn(100000) with h5py.File('integer_1_compr.hdf5', 'w') as f: d = f.create_dataset('dataset', (100000,), dtype='i1', compression="gzip", compression_opts=9) d[:] = arr with h5py.File('integer_8_compr.hdf5', 'w') as f: d = f.create_dataset('dataset', (100000,), dtype='i8', compression="gzip", compression_opts=9) d[:] = arr with h5py.File('float_compr.hdf5', 'w') as f: d = f.create_dataset('dataset', (100000,), dtype='f16', compression="gzip", compression_opts=9) d[:] = arr
Escolhemos o gzip porque ele é suportado em todas as plataformas. As opções depression_opts especificam o nível de compactação. Quanto maior o nível, menos espaço os dados ocupam, mas mais tempo o processador deve funcionar. O nível de compactação padrão é 4. Podemos ver as diferenças em nossos arquivos com base no nível de compactação:
Tipo | Sem compressão | Compressão 9 | Compressão 4 |
---|
inteiro_1 | 102144 | 28016 | 30463 |
inteiro_8 | 802144 | 43329 | 57971 |
flutuar | 1602144 | 1469580 | 1469868 |
O efeito da compactação em matrizes de dados inteiras é muito mais perceptível do que em conjuntos de dados de ponto flutuante. Deixo para você descobrir por que a compressão funcionou tão bem nos dois primeiros casos, mas não nos últimos. Como uma dica: você deve verificar quais dados você está realmente armazenando.
A leitura de dados compactados não altera nenhum código descrito acima. A biblioteca principal do HDF5 cuidará da extração de dados de conjuntos de dados compactados usando o algoritmo apropriado. Portanto, se você implementar a compactação para salvar, não precisará alterar o código usado para leitura.
A compactação de dados é uma ferramenta adicional que você deve considerar juntamente com todos os outros aspectos do processamento de dados. Você deve considerar o tempo extra do processador e a taxa de compactação efetiva para avaliar os benefícios da compactação de dados em seu próprio aplicativo. O fato de ser transparente para o código downstream torna incrivelmente fácil testar e encontrar a melhor solução.
Redimensionar conjuntos de dadosQuando você está trabalhando em um experimento, às vezes é impossível descobrir qual será o tamanho dos seus dados. Imagine que você está gravando um filme, talvez o pare após um segundo, talvez depois de uma hora. Felizmente, o HDF5 permite redimensionar os conjuntos de dados em tempo real com pouco custo computacional. O comprimento do conjunto de dados pode ser excedido até o tamanho máximo. Esse tamanho máximo é especificado ao criar o conjunto de dados usando a palavra-chave maxshape:
import h5py import numpy as np with h5py.File('resize_dataset.hdf5', 'w') as f: d = f.create_dataset('dataset', (100, ), maxshape=(500, )) d[:100] = np.random.randn(100) d.resize((200,)) d[100:200] = np.random.randn(100) with h5py.File('resize_dataset.hdf5', 'r') as f: dset = f['dataset'] print(dset[99]) print(dset[199])
Primeiro, você cria um conjunto de dados para armazenar 100 valores e definir o tamanho máximo para 500 valores. Depois de salvar o primeiro lote de valores, você pode expandir o conjunto de dados para salvar os próximos 100. Você pode repetir o procedimento até obter um conjunto de dados com 500 valores. , N- . , , .
, , . , - ( , , ):
with h5py.File('resize_dataset.hdf5', 'a') as f: dset = f['dataset'] dset.resize((300,)) dset[:200] = 0 dset[200:300] = np.random.randn(100) with h5py.File('resize_dataset.hdf5', 'r') as f: dset = f['dataset'] print(dset[99]) print(dset[199]) print(dset[299])
, , 200 200 299. , , .
, , , . 2D-, , — , 2D-. 3- HDF-, . , :
with h5py.File('movie_dataset.hdf5', 'w') as f: d = f.create_dataset('dataset', (1024, 1024, 1), maxshape=(1024, 1024, None )) d[:,:,0] = first_frame d.resize((1024,1024,2)) d[:,:,1] = second_frame
1024x1024 , . , , . maxshape None.
(Chunks), . (chunk) , .. . , , . , :
dset = f.create_dataset("chunked", (1000, 1000), chunks=(100, 100))
, dset [0: 100,0: 100] . dset [200: 300, 200: 300], dset [100: 200, 400: 500] . . h5py, :
(Chunking) . 10 KiB 1 MiB, . , , .
(auto-chunking), . , maxshape. :
dset = f.create_dataset("autochunk", (1000, 1000), chunks=True)
(Groups). HDF5, , . (groups), , . , :
import numpy as np import h5py arr = np.random.randn(1000) with h5py.File('groups.hdf5', 'w') as f: g = f.create_group('Base_Group') gg = g.create_group('Sub_Group') d = g.create_dataset('default', data=arr) dd = gg.create_dataset('default', data=arr)
Base_Group , Sub_Group. default . , , :
with h5py.File('groups.hdf5', 'r') as f: d = f['Base_Group/default'] dd = f['Base_Group/Sub_Group/default'] print(d[1]) print(dd[1])
, : Base_Group/default Base_Group/Sub_Group/default. , , , , . — keys():
with h5py.File('groups.hdf5', 'r') as f: for k in f.keys(): print(k)
, , for-. , . visit(), :
def get_all(name): print(name) with h5py.File('groups.hdf5', 'r') as f: f.visit(get_all)
,
get_all
, , name. visit,
get_all.
visit , , None, . , , Sub_Group,
get_all
:
def get_all(name): if 'Sub_Group' in name: return name with h5py.File('groups.hdf5', 'r') as f: g = f.visit(get_all) print(g)
visit , , None, , get_all. Sub_Group, get_all , Sub_Group . , g , , :
with h5py.File('groups.hdf5', 'r') as f: g_name = f.visit(get_all) group = f[g_name]
. — , visititems, : name object. :
def get_objects(name, obj): if 'Sub_Group' in name: return obj with h5py.File('groups.hdf5', 'r') as f: group = f.visititems(get_objects) data = group['default'] print('First data element: {}'.format(data[0]))
visititems , , , . , , . . , , .
HDF5, HDF5, , . , , , , , , .. . , , 200x300x250. , , , , — , .
HDF5 -. .
import time import numpy as np import h5py import os arr = np.random.randn(1000) with h5py.File('groups.hdf5', 'w') as f: g = f.create_group('Base_Group') d = g.create_dataset('default', data=arr) g.attrs['Date'] = time.time() g.attrs['User'] = 'Me' d.attrs['OS'] = os.name for k in g.attrs.keys(): print('{} => {}'.format(k, g.attrs[k])) for j in d.attrs.keys(): print('{} => {}'.format(j, d.attrs[j]))
, attrs . , , . , . , , , update:
with h5py.File('groups.hdf5', 'w') as f: g = f.create_group('Base_Group') d = g.create_dataset('default', data=arr) metadata = {'Date': time.time(), 'User': 'Me', 'OS': os.name,} f.attrs.update(metadata) for m in f.attrs.keys(): print('{} => {}'.format(m, f.attrs[m]))
, , hdf5, . , . hdf5, . Python -. JSON, , , , pickle.
import json with h5py.File('groups_dict.hdf5', 'w') as f: g = f.create_group('Base_Group') d = g.create_dataset('default', data=arr) metadata = {'Date': time.time(), 'User': 'Me', 'OS': os.name,} m = g.create_dataset('metadata', data=json.dumps(metadata))
, . , . , json.dumps, . , HDF5. , json.loads:
Python
with h5py.File('groups_dict.hdf5', 'r') as f: metadata = json.loads(f['Base_Group/metadata'][()]) for k in metadata: print('{} => {}'.format(k, metadata[k]))
json , . YAML, XML .. , , , attr , , .
HDF5, . , , , . HDF , , , , , . , HDF .
HDF5 . , , . , . . SQL,
HDFql , SQL HDF5.
. , , - , , . , . , , .
HDF5 — , . , , , , . HDF5 — , , .
O FIM
,
.