You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Hi folks! I'm hitting an "endian" error. I wrote a script that does the following in order:
loads up data from an hdf5 file
creates an astropy Table object for that data,
turns that Table into a pandas dataframe using table.to_pandas(), then
makes a new pandas dataframe via "groupy" and "apply".
This produces this error:
pandas/_libs/algos_take_helper.pxi in pandas._libs.algos.take_2d_axis1_float32_float32()
ValueError: Big-endian buffer not supported on little-endian compiler
The error is new. I've been running similar code for a few months without this error. (The code that triggered this is here.)
Questions:
(a) Is this arising from a bug somewhere in the software stack?
(b) Regardless of the above, is there anything I can do in the short term to hack around this problem and create a suitable workaround? (For example, can I ask either the astropy table or the intermediate pandas dataframe to manually invert their endian-ness?)
Expected behavior
I expected to get a new, groupby'd pandas dataframe.
@tomr-stargazer - astropy is supposed to be converting the data to native byte order before passing to pandas. This is a known issue that has been discussed and indeed fixed some time ago. See #1156 and #3729.
Perhaps the discussion in those two issues will help you find a workaround. We would probably need a data file and/or minimum working example showing the problem to get much further in fixing this if indeed there is a real bug in astropy.
@taldcroft, thank you!
On first pass, it's not clear to me how I would make a workaround - does astropy.table.Table itself have a method to swap to a new byte ordering, or (equally fine by me) is there a hackish way to modify the byte ordering of the internal data in-place?
I've tried the following, in an attempt to in-place modify the byte order of the table's data:
dat=Table.read(filename)
data=np.array(dat, copy=False)
data=data.byteswap().newbyteorder()
df=dat.to_pandas()
ds=spreadsheet_maker(df) # this is a custom function I wrote which mostly consists of a groupby / apply step
but it didn't seem to have an affect (same error occurs), and I'm trying to figure out how else I might modify the table's byte-order in-place.
In the meantime, I wondered if part of the issue involved h5py, so I re-generated my data files as .fits instead of .hdf5, and then changed my data handling chain from:
(original)
astropy.table -> .hdf5 file
.hdf5 file -> astropy.table
astropy.table -> pandas DataFrame
pandas DataFrame -> Groupy & Apply # this is where the endian error occured
(new)
astropy.table -> .fits file
.fits file -> astropy.table
astropy.table -> pandas DataFrame
pandas DataFrame -> Groupy & Apply # no error!
For my purposes I seem to have found a workaround: avoid saving my intermediate data as .h5 and use .fits instead. (This points to a possible bug in how astropy and/or h5py are handling data, perhaps?)
My data file is 291 MB, and I still have the .hdf5 version in case anyone would like to see it.
@tomr-stargazer - For the table that fails going to pandas DataFrame, can you print the dtype with tbl.dtype and report that? Also, perhaps you can generate a small version of your HDF5 file with just a few rows and see if that replicates the issue. That will help debugging (probably don't need all 291 Mb).
As an aside, astropy Table natively supports group_by and aggregation operations, so maybe you don't need Pandas? Using pandas is great, I'm just always wondering about any missing functionality in Table.
Looked quite mysterious how any big-endian values would come to appear there in the first place, since you read in an all-little endian dtype, and I guess the original table written to HDF5 was native byteorder as well (or have some columns been read from FITS)?
But I could in fact reproduce this directly with
and any operation such as trying to print the entire data frame (not individual columns though) raises the same ValueError: Big-endian buffer not supported on little-endian compiler you triggered (in my case on a float64 column, probably because it is the first float encountered).
Whereas directly reading the file in with pandas (which might be a shorter workaround for the time being ;-)
So it looks indeed like the bug is somewhere in the tab.to_pandas() method somehow triggering the byteswap, which would be unwarranted in the first place.
In contrast, both tab.as_array(), which is supposed to behave in the same way, and tab.as_array(keep_byteorder=True) preserve the original all-little endian tab.dtype.
only makes a string comparison to native or string/object-type byteorders.
At the core changing the conversion to
out[name] =out[name].byteswap().newbyteorder('=')
would already take care of this. Alternatively or additionally (to avoid unnecessary byteswap() entirely), we could test against a native_order tuple like @embray did in #4080.
For a temporary workaround (other than the intermediate FITS file or directly using pd.read_hdf) you'd probably need to byteswap explicitly to native as well, and feed the ndarray back to a table:
and indeed, the .hdf5 file that I'm creating contains data that were originally read from a .fits file, before being manipulated as an astropy Table object and then re-saved in .hdf5 format.
Thank you for the notes on all of this, especially with the multiple workaround suggestions. If you'd like me to test anything else out let me know! Also, if it would be appropriate for me to be the one to try and do a bugfix pull request on astropy/astropy/table/table.py, do let me know, though I feel I'm a little less than qualified to submit a patch to astropy.
if getattr(out[name].dtype, 'byteorder', '=') == ('>' if sys.byteorder == 'little' else '<'):
Now I am not sure if this is fancier or the indexing trick...
For the patch I pushed now I took the lazy way out by just using dtype.isnative, but I think that should catch all cases in our supported numpy versions. Became a bit clearer from the numpy docs why dtype only identifies as '<' on little endian if explicitly created with .newbyteorder('<')); that may also have caused at least one of the tests to check the wrong thing, when it correctly, but unintendedly, asserted that for t[column].dtype.byteorder == '<' the column was swapped.
Activity
tomr-stargazer commentedon Jan 30, 2021
Also h5py version, if it's meaningful:
taldcroft commentedon Jan 30, 2021
@tomr-stargazer - astropy is supposed to be converting the data to native byte order before passing to pandas. This is a known issue that has been discussed and indeed fixed some time ago. See #1156 and #3729.
Perhaps the discussion in those two issues will help you find a workaround. We would probably need a data file and/or minimum working example showing the problem to get much further in fixing this if indeed there is a real bug in astropy.
tomr-stargazer commentedon Jan 30, 2021
@taldcroft, thank you!
On first pass, it's not clear to me how I would make a workaround - does astropy.table.Table itself have a method to swap to a new byte ordering, or (equally fine by me) is there a hackish way to modify the byte ordering of the internal data in-place?
I've tried the following, in an attempt to in-place modify the byte order of the table's data:
but it didn't seem to have an affect (same error occurs), and I'm trying to figure out how else I might modify the table's byte-order in-place.
In the meantime, I wondered if part of the issue involved h5py, so I re-generated my data files as .fits instead of .hdf5, and then changed my data handling chain from:
(original)
(new)
For my purposes I seem to have found a workaround: avoid saving my intermediate data as .h5 and use .fits instead. (This points to a possible bug in how astropy and/or h5py are handling data, perhaps?)
My data file is 291 MB, and I still have the .hdf5 version in case anyone would like to see it.
[-]Astropy tables / pandas / Endian issue[/-][+]Astropy tables / pandas / hdf5 / Endian issue[/+]taldcroft commentedon Jan 30, 2021
@tomr-stargazer - For the table that fails going to pandas DataFrame, can you print the
dtypewithtbl.dtypeand report that? Also, perhaps you can generate a small version of your HDF5 file with just a few rows and see if that replicates the issue. That will help debugging (probably don't need all 291 Mb).As an aside, astropy
Tablenatively supports group_by and aggregation operations, so maybe you don't need Pandas? Using pandas is great, I'm just always wondering about any missing functionality inTable.tomr-stargazer commentedon Jan 30, 2021
@taldcroft - here's a 5 KB version of the hdf5 file (hosted on Google Drive) that causes the same endian error on my computer.
Here's the dtype:
Here's the associated error traceback.
also, wow! I had no idea that groupby and aggregation existed in Astropy Tables. I certainly switched to pandas specifically in search of this kind of functionality. I may be a little too deep in pandas now to switch back, but in case you're curious, I have a fairly convoluted groupby/apply function that is vital to my multi-band time-series photometry analysis. The code appears here:
https://github.com/tomr-stargazer/Variability_Project_2020/blob/master/wuvars/analysis/variability_selection.py#L269
dhomeier commentedon Jan 30, 2021
Looked quite mysterious how any big-endian values would come to appear there in the first place, since you read in an all-little endian dtype, and I guess the original table written to HDF5 was native byteorder as well (or have some columns been read from FITS)?
But I could in fact reproduce this directly with
and any operation such as trying to print the entire data frame (not individual columns though) raises the same
ValueError: Big-endian buffer not supported on little-endian compileryou triggered (in my case on afloat64column, probably because it is the first float encountered).Whereas directly reading the file in with pandas (which might be a shorter workaround for the time being ;-)
returned an apparently functional data frame.
So it looks indeed like the bug is somewhere in the
tab.to_pandas()method somehow triggering the byteswap, which would be unwarranted in the first place.In contrast, both
tab.as_array(), which is supposed to behave in the same way, andtab.as_array(keep_byteorder=True)preserve the original all-little endiantab.dtype.dhomeier commentedon Jan 30, 2021
OK, that was rather easy. The table read by h5py has explicit
<byteorders, butastropy/astropy/table/table.py
Lines 3679 to 3681 in 4d31e6c
only makes a string comparison to native or string/object-type byteorders.
At the core changing the conversion to
would already take care of this. Alternatively or additionally (to avoid unnecessary
byteswap()entirely), we could test against anative_ordertuple like @embray did in #4080.dhomeier commentedon Jan 30, 2021
For a temporary workaround (other than the intermediate FITS file or directly using
pd.read_hdf) you'd probably need to byteswap explicitly to native as well, and feed the ndarray back to a table:tomr-stargazer commentedon Jan 31, 2021
@dhomeier this is all awesome!
You wrote:
and indeed, the .hdf5 file that I'm creating contains data that were originally read from a .fits file, before being manipulated as an astropy Table object and then re-saved in .hdf5 format.
Thank you for the notes on all of this, especially with the multiple workaround suggestions. If you'd like me to test anything else out let me know! Also, if it would be appropriate for me to be the one to try and do a bugfix pull request on
astropy/astropy/table/table.py, do let me know, though I feel I'm a little less than qualified to submit a patch to astropy.mhvk commentedon Jan 31, 2021
@dhomeier - wow, nice catch!
I think one would want to change the test to explicitly check if the byte-order is swapped, for instance by (following https://numpy.org/devdocs/reference/generated/numpy.dtype.byteorder.html):
dhomeier commentedon Jan 31, 2021
Now I am not sure if this is fancier or the indexing trick...
For the patch I pushed now I took the lazy way out by just using
dtype.isnative, but I think that should catch all cases in our supported numpy versions. Became a bit clearer from the numpy docs why dtype only identifies as '<' on little endian if explicitly created with.newbyteorder('<')); that may also have caused at least one of the tests to check the wrong thing, when it correctly, but unintendedly, asserted that fort[column].dtype.byteorder == '<'the column was swapped.dhomeier commentedon Jan 31, 2021
@tomr-stargazer thanks; I have already put my ideas for a fix into a PR, but your input and testing on #11288 will be highly appreciated!