Как прочитать несколько типов данных из memoryview в Python?

#python #numpy #memory #floating-point #unsigned-integer

#python #numpy #память #с плавающей запятой #целое число без знака

Вопрос:

Я считываю данные датчика, которые содержат 6 столбцов, первые четыре из которых представляют собой 32-разрядные числа с плавающей запятой, а последние два — целые числа без знака. Вот как это преобразуется в массив numpy:

 data = np.frombuffer(sensor_data.raw_data, dtype=np.dtype('float32')).reshape([-1, 6])
data = data[:, :5]

int_data = np.frombuffer(sensor_data.raw_data, dtype=np.dtype('uint')).reshape([-1, 6])
int_data = int_data[:, 4:6]
  

Это не кажется наиболее эффективным способом сделать это. Есть ли способ либо прочитать несколько типов данных, либо скрыть последние два столбца из float32 обратно в байты, а затем в uint ?

Комментарии:

1. Было бы проще создать правильное решение, если вы явно укажете, сколько байт использует каждое целое число без знака в файле. np.dtype('uint') может составлять 4 байта на некоторых платформах и 8 байт на других.

Ответ №1:

Если ваши 2 загрузки работают, беззнаковые целые числа должны быть 32-разрядными.

Мы можем построить эквивалентный структурированный массив с составным dtype:

 In [58]: dt = np.dtype([('f0','f4',4),('f1','uint32',2)])                       
In [59]: arr = np.zeros(5, dt)                                                  
In [60]: arr['f0'] = np.random.rand(5,4)                                        
In [61]: arr['f1'] = np.random.randint(0,100,(5,2))                             
In [62]: arr                                                                    
Out[62]: 
array([([0.38565257, 0.36662674, 0.5530039 , 0.17866635], [39,  3]),
       ([0.12109676, 0.60092086, 0.6555444 , 0.06968965], [18, 96]),
       ([0.7082187 , 0.48962796, 0.4019332 , 0.19190358], [26, 81]),
       ([0.34053752, 0.35870123, 0.22802468, 0.33509415], [48, 52]),
       ([0.45730132, 0.38697603, 0.18952931, 0.90458447], [ 3, 40])],
      dtype=[('f0', '<f4', (4,)), ('f1', '<u4', (2,))])
  

и создайте буфер данных:

 In [63]: astr = arr.tobytes()                                                   
  

Ваши нагрузки работают с этим буфером:

 In [64]: data = np.frombuffer(astr, 'float32').reshape(-1,6)                    
In [65]: data[:,:4]                                                             
Out[65]: 
array([[0.38565257, 0.36662674, 0.5530039 , 0.17866635],
       [0.12109676, 0.60092086, 0.6555444 , 0.06968965],
       [0.7082187 , 0.48962796, 0.4019332 , 0.19190358],
       [0.34053752, 0.35870123, 0.22802468, 0.33509415],
       [0.45730132, 0.38697603, 0.18952931, 0.90458447]], dtype=float32)
In [66]: data = np.frombuffer(astr, 'uint32').reshape(-1,6)                     
In [67]: data[:,4:]                                                             
Out[67]: 
array([[39,  3],
       [18, 96],
       [26, 81],
       [48, 52],
       [ 3, 40]], dtype=uint32)
  

Но мы также можем использовать составной dtype для его загрузки:

 In [68]: data = np.frombuffer(astr, dt)                                         
In [69]: data['f0']                                                             
Out[69]: 
array([[0.38565257, 0.36662674, 0.5530039 , 0.17866635],
       [0.12109676, 0.60092086, 0.6555444 , 0.06968965],
       [0.7082187 , 0.48962796, 0.4019332 , 0.19190358],
       [0.34053752, 0.35870123, 0.22802468, 0.33509415],
       [0.45730132, 0.38697603, 0.18952931, 0.90458447]], dtype=float32)
In [70]: data['f1']                                                             
Out[70]: 
array([[39,  3],
       [18, 96],
       [26, 81],
       [48, 52],
       [ 3, 40]], dtype=uint32)
       
  

Этот составной dtype также будет работать с ‘uint64’.

Мы также могли бы получить uint32 из float32 загрузки, используя view

 In [84]: data = np.frombuffer(astr, 'float32').reshape(-1,6)                    
In [86]: data[:,4:].view('uint32')                                              
Out[86]: 
array([[39,  3],
       [18, 96],
       [26, 81],
       [48, 52],
       [ 3, 40]], dtype=uint32)
  

(или значение float из uint с представлением)