How to find HDF5 file groups/keys within Python? - python

Lets's say someone gave me a random HDF5 document. I would like to write a function that checks what are the groups/"keys" used.
Take pandas HDFStore(). For many methods which retrieve HDF5 data, one requires to know the key, e.g. pandas.HDFStore.get()
http://pandas.pydata.org/pandas-docs/stable/generated/pandas.HDFStore.get.html
What is the most efficient way to check the identity of keys if not a priori known?

You probably want to use the h5py package:
import h5py
with h5py.File("myfile.h5") as f:
print(f.keys()) # works like a dict

Related

h5py file subset taking more space than parent file?

I have an existing h5py file that I downloaded which is ~18G in size. It has a number of nested datasets within it:
h5f = h5py.File('input.h5', 'r')
data = h5f['data']
latlong_data = data['lat_long'].value
I want to be able to some basic min/max scaling of the numerical data within latlong, so i want to put it in its own h5py file for easier use and lower memory usage.
However, when i try to write it out to its own file:
out = h5py.File('latlong_only.h5', 'w')
out.create_dataset('latlong', data=latlong)
out.close()
The output file is incredibly large. It's still not done writing to disk and is ~85GB in space. Why is the data being written to the new file not compressed?
Could be h5f['data/lat_long'] is using compression filters (and you aren't). To check the original dataset's compression settings, use this line:
print (h5f['data/latlong'].compression, h5f['data/latlong'].compression_opts)
After writing my answer, it occurred to me that you don't need to copy the data to another file to reduce the memory footprint. Your code reads the dataset into an array, which is not necessary in most use cases. A h5py dataset object behaves similar to a NumPy array. Instead, use this line: ds = h5f1['data/latlong'] to create a dataset object (instead of an array) and use it "like" it's a NumPy array. FYI, .value is a deprecated method to return the dataset as an array. Use this syntax instead arr = h5f1['data/latlong'][()]. Loading the dataset into an array also requires more memory than using an h5py object (which could be an issue with large datasets).
There are other ways to access the data. My suggestion to use dataset objects is 1 way. Your method (extracting data to a new file) is another way. I am not found of that approach because you now have 2 copies of the data; a bookkeeping nightmare. Another alternative is to create external links from the new file to the existing 18GB file. That way you have a small file that links to the big file (and no duplicate data). I describe that method in this post: [How can I combine multiple .h5 file?][1] Method 1: Create External Links.
If you still want to copy the data, here is what I would do. Your code reads the dataset into an array then writes the array to the new file (uncompressed). Instead, copy the dataset using h5py's group .copy() method, it will retain compression settings and attributes.
See below:
with h5py.File('input.h5', 'r') as h5f1, \
h5py.File('latlong_only.h5', 'w') as h5f2:
h5f1.copy(h5f1['data/latlong'], h5f2,'latlong')

Storing multiple GeoTiffs in HDF5 file in Python

I want to store multiple GeoTiff files in one HDF5 file to use it for further analysis since the function I am supposed to use can just deal with HDF5 (so basically like a raster stack in R but stored in a HDF5). I have to use Python. I am relatively new to HDF5 format (and geoanalysis in Python generally) and don't really know how to approach this issue. Especially keeping the geolocation/projection inforation seems tricky to me. So far I tried:
import h5py
import rasterio
r1 = rasterio.open("filename.tif")
r2 = rasterio.open("filename2.tif")
with h5py.File('path/test.h5', 'w') as hdf:
hdf.create_dataset('GeoTiff1', data=r1)
hdf.create_dataset('GeoTiff2', data=r2)
Yielding the following errror:
TypeError: Object dtype dtype('O') has no native HDF5 equivalent
I am pretty sure this not at all the correct approach and I'm happy about any suggestions.
What you can try is to do this:
import numpy as np
spec_dtype = h5py.special_dtype(vlen=np.dtype('float64'))
Just make a spec_dtype variable with float64 type then apply this to create_dataset:
with h5py.File('path/test.h5', 'w') as hdf:
hdf.create_dataset('GeoTiff1', data=r1,, dtype=spec_dtype)
hdf.create_dataset('GeoTiff2', data=r2,, dtype=spec_dtype)
Apply these and hopefully it will work.
Using HDFql in Python, your use-case could be solved as follows:
import HDFql
HDFql.execute("SHOW FILE SIZE filename.tif, filename2.tif")
HDFql.cursor_next()
HDFql.execute("CREATE DATASET path/test.h5 GeoTiff1 AS OPAQUE(%d) VALUES FROM BINARY FILE filename.tif" % HDFql.cursor_get_bigint())
HDFql.cursor_next()
HDFql.execute("CREATE DATASET path/test.h5 GeoTiff2 AS OPAQUE(%d) VALUES FROM BINARY FILE filename2.tif" % HDFql.cursor_get_bigint())

How can I import many binary files in Dask?

I have many binary files (.tdms format, similar to .wav) stored in S3 and I would like to read them with nptdms then process them in a distributed fashion with Dask on a cluster.
In PySpark there is pyspark.SparkContext.binaryFiles() which produces an RDD with a bytearray for each input file which is a simple solution to this problem.
I have not found an equivalent function in Dask - is there one? If not, how could the equivalent functionality be achieved in Dask?
I noticed there's dask.bytes.read_bytes() if it's necessary to involve this however nptdms can't read a chunk of a file - it needs the entire file to be available and I'm not sure how to accomplish that.
dask.bytes.read_bytes() will give you whole files if you use blocksize=None, i.e., exactly one block per file. The most common use case for that is compressed files (e.g., gzip) where you can't start mid-stream, but should work for your use case too. Note that the delayed objects you get each return bytes, not open files.
Alternatively, you can use fsspec.open_files. This returns OpenFile objects, which are safe to serialise and so you can use them in dask.delayed calls such as
ofs = fsspec.open_files("s3://...", ...)
#dask.delayed
def read_a_file(of):
with of as f:
# entering context actually touches storage
return TdmsFile.read(f)
tdms = [read_a_file(of) for of in ofs]

write HDF h5 dataset (via h5py) which is a mix of string and numpy list

I have the following two datasets (I have several of these tuples):
filename_string: "something"
filename_list: [1,2,3,4,5] # this is a numpy array.
Id like to know how to write this in a compact format via h5py. The goal is to have the end user read this h5 datafile and be able to deduce the list and its corresponding filename.
I am able to efficiently write the numpy list to h5, but strings seems to be a big problem and errors out when I include this.
Any help would be great - wasted a few hours looking for a solution!
This little scrap of code will create a dataset named something (from the variable filename_string) that contains the data in your list filename_list.
import h5py
filename_string= "something"
filename_list= [1,2,3,4,5]
with h5py.File('SO_63137136.h5','w') as h5f:
h5f.create_dataset(filename_string, data=filename_list)

Method to read DBF files efficiently python

**I have the following method to open DBF files, but it performs very slow, I´m looking to open large DBF files, I need to efficient my method. Need Help. Thanxs **
def lectura_tablas(nombre_tabla):
table_name=nombre_tabla
table_ventas = DBF(f'{table_name}', load=True,ignore_missing_memofile=True)
table_new=[]
for x in range(0,len(table_ventas.records)):
table_new.append(OrderedDict(table_ventas.records[x]))
dataframe= pd.DataFrame(table_new)
return dataframe
Your code ought to work. A slowness might be caused by a "Schlemiel the Painter" problem in the loop (the fact that you use load=True makes this unlikely, but it's the only possibility I see). Try rewriting it like this:
for record in table_ventas:
table_new.append(record)
This ought to use the standard iterator on the DBF object, which ought to already return an OrderedDict.
Other than that, you might try recompiling the DBF into some other format which is more efficiently accessed and see whether the overall time improves any.

Categories

Resources