convert binary string to numpy array
Asked Answered
D

2

34

Assume I have the string:

my_data = '\x00\x00\x80?\x00\x00\x00@\x00\x00@@\x00\x00\x80@'

Where I got it is irrelevant, but for the sake of having something concrete, assume I read it from a binary file.

I know my string is the binary representation of 4 (4-byte) floats. I would like to get those floats as a numpy array. I could do:

import struct
import numpy as np
tple = struct.unpack( '4f', my_data )
my_array = np.array( tple, dtype=np.float32 )

But it seems silly to create an intermediate tuple. Is there a way to do this operation without creating an intermediate tuple?

EDIT

I would also like to be able to construct the array in such a way that I can specify the endianness of the string.

Dyak answered 1/8, 2012 at 13:14 Comment(2)
possible duplicate of How do I create a numpy array from string?Sallie
@Sallie I would say this is close, but not an exact duplicate. Though the answers are similar, this question is about floats and that question is about integers.Patroclus
S
49
>>> np.frombuffer(b'\x00\x00\x80?\x00\x00\x00@\x00\x00@@\x00\x00\x80@', dtype='<f4') # or dtype=np.dtype('<f4'), or np.float32 on a little-endian system (which most computers are these days)
array([ 1.,  2.,  3.,  4.], dtype=float32)

Or, if you want big-endian:

>>> np.frombuffer(b'\x00\x00\x80?\x00\x00\x00@\x00\x00@@\x00\x00\x80@', dtype='>f4') # or dtype=np.dtype('>f4'), or np.float32  on a big-endian system
array([  4.60060299e-41,   8.96831017e-44,   2.30485571e-41,
         4.60074312e-41], dtype=float32)

The b isn't necessary prior to Python 3, of course.

In fact, if you actually are using a binary file to load the data from, you could even skip the using-a-string step and load the data directly from the file with numpy.fromfile().

Also, dtype reference, just in case: http://docs.scipy.org/doc/numpy/reference/arrays.dtypes.html

Sunnisunnite answered 1/8, 2012 at 13:19 Comment(6)
This is excellent. (thanks). One downside here that I can see is that there's no way to specify endianness. Any ideas on that one?Dyak
Specify the endianness in the dtype. np.dtype('<f4') for little-endian (though this is the default, so isn't necessary for anything other than code clarity), np.dtype('>f4') for big-endian. So np.fromstring(b'\x00\x00\x80?\x00\x00\x00@\x00\x00@@\x00\x00\x80@', dtype=np.dtype('>f4')) results in array([4.60060299e-41, 8.96831017e-44, 2.30485571e-41, 4.60074312e-41], dtype=float32). Reference: docs.scipy.org/doc/numpy/reference/arrays.dtypes.htmlSunnisunnite
perfect. just what I was looking for.Dyak
I think you should add the stuff about endianness conversion to your answer. I think that could also be potentially helpful to someone else with the same question I had so it makes sense to feature it more prominently than in a comment.Dyak
@Sunnisunnite - +1. One note - I don't think little-endian is the default. Rather, machine type is the default. So if you're on a big endian machine (rare these days) and are reading a little endian string, you need to specify '<f4'.Trochee
Oh, that's a good point. I'll modify my answer slightly, then.Sunnisunnite
H
0

np.fromstring() is deprecated. Use np.frombuffer() instead.

import numpy as np

my_data = b'\x00\x00\x80?\x00\x00\x00@\x00\x00@@\x00\x00\x80@'

# np.fromstring is deprecated
# data = np.fromstring(my_data, np.float32)
data = np.frombuffer(my_data, np.float32)

print(data)
[1. 2. 3. 4.]
Harsh answered 5/12, 2020 at 23:38 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.