Эффективное сжатие массивов

Я попробовал различные методы сжатия данных при сохранении на диск некоторых numpy arrays .

Эти 1D-массивы содержат выборочные данные с определенной частотой дискретизации (могут быть записаны с микрофоном или любыми другими измерениями с любым датчиком): данные по существу непрерывны (в математическом смысле, конечно, после выборки теперь это дискретные данные) ,

Я пробовал с HDF5 (h5py):

 f.create_dataset("myarray1", myarray, compression="gzip", compression_opts=9) 

но это довольно медленно, и коэффициент сжатия не самый лучший, который мы можем ожидать.

Я также пробовал

 numpy.savez_compressed() 

но в очередной раз это не лучший алгоритм сжатия для таких данных (описанный выше).

Что бы вы выбрали для лучшей степени сжатия в numpy array с такими данными?

(Я думал о таких вещах, как FLAC без потерь (изначально предназначенный для аудио), но есть ли простой способ применить такой алгоритм к данным numpy?)

  1. Шум несжимаем. Таким образом, любая часть данных, которые у вас есть, представляет собой сжатые данные 1: 1 независимо от алгоритма сжатия, если вы не отбросите его каким-либо образом (сжатие с потерями). Если у вас есть 24 бит на выборку с эффективным количеством бит (ENOB), равным 16 бит, оставшиеся 24-16 = 8 бит шума будут ограничивать максимальную степень сжатия без потерь до 3: 1, даже если ваши (бесшумные) данные отлично сжимается. Неравномерный шум сжимается в той степени, в которой он неоднороден; вы, вероятно, хотите посмотреть на эффективную энтропию шума, чтобы определить, насколько она сжимаемая.

  2. Сжатие данных основано на его моделировании (частично для устранения избыточности, но также отчасти, чтобы вы могли отделяться от шума и отбрасывать шум). Например, если вы знаете, что ваши данные ограничены пропускной способностью до 10 МГц, а вы сэмплируете на частоте 200 МГц, вы можете делать БПФ, обнулять высокие частоты и сохранять коэффициенты только для низких частот (в этом примере: 10: 1 сжатие). Это связано с целым полем, называемым «сжимающим восприятием».

  3. Практическое предложение, подходящее для многих видов разумно непрерывных данных: denoise -> ограничение пропускной способности -> дельта-компресс -> gzip (или xz и т. Д.). Denoise может быть таким же, как ограничение полосы пропускания, или нелинейный фильтр, как текущая медиана. Предел пропускной способности может быть реализован с помощью FIR / IIR. Дельта-компресс – это просто y [n] = x [n] – x [n-1].

EDIT :

 from pylab import * import numpy import numpy.random import os.path import subprocess # create 1M data points of a 24-bit sine wave with 8 bits of gaussian noise (ENOB=16) N = 1000000 data = (sin( 2 * pi * linspace(0,N,N) / 100 ) * (1<<23) + \ numpy.random.randn(N) * (1<<7)).astype(int32) numpy.save('data.npy', data) print os.path.getsize('data.npy') # 4000080 uncompressed size subprocess.call('xz -9 data.npy', shell=True) print os.path.getsize('data.npy.xz') # 1484192 compressed size # 11.87 bits per sample, ~8 bits of that is noise data_quantized = data / (1<<8) numpy.save('data_quantized.npy', data_quantized) subprocess.call('xz -9 data_quantized.npy', shell=True) print os.path.getsize('data_quantized.npy.xz') # 318380 # still have 16 bits of signal, but only takes 2.55 bits per sample to store it 

Что я делаю сейчас:

 import gzip import numpy f = gzip.GzipFile("my_array.npy.gz", "w") numpy.save(file=f, arr=my_array) f.close() 

То, что составляет наилучшее сжатие (если оно есть), сильно зависит от характера данных. Многие виды данных измерений практически полностью несжимаемы, если действительно требуется сжатие без потерь.

В документах pytables содержится много полезных рекомендаций по сжатию данных. Он также детализирует компромисс скорости и так далее; Как оказалось, более высокие уровни сжатия обычно являются пустой тратой времени.

http://pytables.github.io/usersguide/optimization.html

Обратите внимание, что это, вероятно, так хорошо, как это получится. Для целочисленных измерений комбинация фильтра тасования с простым сжатием типа zip обычно работает достаточно хорошо. Этот фильтр очень эффективно использует общую ситуацию, когда старший байта обычно равен 0 и включается только для защиты от переполнения.

Во-первых, для общих наборов данных аргумент shuffle=True для create_dataset улучшает сжатие с помощью грубо непрерывных наборов данных. Он очень умно переставляет биты для сжатия, так что (для непрерывных данных) биты изменяются медленно, а это значит, что они могут быть сжаты лучше. Это замедляет сжатие очень немного в моем опыте, но может существенно улучшить коэффициент сжатия в моем опыте. Это не потеря, поэтому вы действительно получаете те же данные, что и вы.

Если вы так не заботитесь о точности, вы также можете использовать аргумент scaleoffset для ограничения количества сохраненных бит. Будьте осторожны, потому что это не то, что может показаться. В частности, это абсолютная точность, а не относительная точность. Например, если вы пройдете scaleoffset=8 , но ваши данные будут меньше 1e-8 вы получите только нули. Конечно, если вы масштабировали данные до максимума около 1, и не думайте, что вы можете слышать различия, меньшие, чем часть в миллионе, вы можете пройти scaleoffset=6 и получить отличное сжатие без большой работы.

Но для аудио в частности, я ожидаю, что вы правы, желая использовать FLAC, потому что его разработчики приложили огромные мысли, балансируя сжатие с сохранением различимых деталей. Вы можете конвертировать в WAV с scipy , а оттуда – в FLAC .

Возможно, вы захотите попробовать blz . Он может эффективно сжимать двоичные данные.

 import blz # this stores the array in memory blz.barray(myarray) # this stores the array on disk blz.barray(myarray, rootdir='arrays') 

Он хранит массивы либо в файле, либо сжат в памяти. Сжатие основано на blosc . См. Видеоролик для небольшого контекста.

Interesting Posts