#python #pandas #numpy #binary
#python #pandas #numpy #двоичный
Вопрос:
Мне нужно преобразовать большие двоичные файлы в массивы n x 3. Данные представляют собой серию кадров изображения, определяемых координатами (x, y, time). Каждый фрейм использует два 32-разрядных целых числа для определения измерений n x 3 и n триплетов 16-разрядных целых чисел для определения значений (x, y, time). Результатом является двоичная структура, которая выглядит как:
int32, int32, uint16, uint16, uint16, ..., int32, int32, uint16, uint16, uint16
и так далее.
Моя первая попытка заключалась в преобразовании двоичных данных в одномерный массив, а затем добавлении нужных разделов во фрейм данных. Текущие данные уже отсортированы таким образом, что разделение фреймов может быть восстановлено без двух int32
значений, поэтому при необходимости их можно удалить. Если бы это было не так, того же эффекта можно было бы достичь, сортируя каждый фрейм по отдельности, прежде чем добавлять его в конечный фрейм данных.
import numpy as np
import pandas as pd
def frame_extract(index):
n = data[index]
subarray=data[index 4:index (3*n 4)]
subarray=np.reshape(subarray, (len(subarray)/3,3))
frame = pd.DataFrame(data=subarray, columns=['x','y','t'])
return frame
def indexer(index):
n = data[index]
new_index = index (3*n 4)
return new_index
data = np.fromfile('file.bin', dtype='<u2')
framedata = pd.DataFrame()
index = 0
while index <= len(data)-1:
framedata = framedata.append(frame_extract(index), ignore_index=True)
index = indexer(index)
print(framedata)
Вышеуказанное работает, но цикл while выполняется очень медленно, особенно по сравнению со следующим структурированным методом, который работал бы нормально (и на порядки быстрее), если int32
бы значения не мешали:
dt = np.dtype([('x', '<u2'), ('y', '<u2'), ('time', '<u2')])
data = np.fromfile("file.bin", dtype=dt)
df = pd.DataFrame(data.tolist(), columns=data.dtype.names)
Есть ли более эффективный способ приблизиться к этому? Если да, было бы проще сделать это во время распаковки двоичных данных или после их преобразования в целые числа?
В настоящее время я рассматриваю возможность использования генератора для чтения двоичного файла в виде серии блоков (т. Е. Использовать Два 32-разрядных целых числа, чтобы определить, насколько велик 16-разрядный целочисленный фрагмент, который мне нужен), но я еще недостаточно знаком с ними, чтобы знать, правильный ли это подход.
Ответ №1:
Каждый раз, когда вы добавляете к фрейму данных, вы копируете все это в новое место в памяти. Вы захотите инициализировать фрейм данных массивом numpy с полным конечным размером, а затем индексировать его с помощью iloc() и т. Д. когда вы заполняете его данными изображения.
Кроме того, есть ли конкретная причина, по которой вы используете фреймы данных pandas для хранения данных изображений? На самом деле они не предназначены для этого…
Комментарии:
1. Спасибо, заполнение инициализированного фрейма данных было значительно быстрее и обеспечило работоспособное решение. Однако итерация по файлу оказалась более эффективной, поэтому я отредактировал исходное сообщение, чтобы отразить это. Я использовал pandas, чтобы соответствовать другим программам, используемым моей группой; не было особой причины.
Ответ №2:
count
Параметр упростил это, позволив np.fromfile
воспользоваться структурой, определяемой int32
значениями. Следующий for
цикл создает каждый фрейм изображения по отдельности:
f = open('file.bin', 'rb')
for i in np.arange(1,15001,1):
m, n = np.fromfile(f, dtype='<i', count=2)
frame = np.reshape(np.fromfile(f, dtype='<u2', count=m*n), (m, n))
Каждый фрейм можно добавить в список и преобразовать в фрейм данных с помощью:
f = open('file.bin', 'rb')
xyt_data = list()
for i in np.arange(1,15001,1):
m, n = np.fromfile(f, dtype='<i', count=2)
frame = np.reshape(np.fromfile(f, dtype='<u2', count=m*n), (m, n))
xyt_data.append(frame)
df = pd.DataFrame(np.vstack(xyt_data), columns=['x','y','t'])
Результат примерно на три порядка быстрее, чем версия, описанная в исходном вопросе.