it-swarm.com.ru

Сжатие массивов numpy эффективно

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

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

Я пытался с HDF5 (h5py):

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

но это довольно медленно, и степень сжатия не самое лучшее, что мы можем ожидать.

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

numpy.savez_compressed()

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

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

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

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

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

  3. Практическое предложение, подходящее для многих видов достаточно непрерывных данных: шумоподавление -> ограничение полосы пропускания -> дельта-сжатие -> 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
12
Alex I

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

import gzip
import numpy

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

Сохранение файла HDF5 со сжатием может быть очень быстрым и эффективным: все зависит от алгоритма сжатия, и от того, хотите ли вы, чтобы оно было быстрым при сохранении, или при чтении обратно, или в обоих случаях. И, естественно, о самих данных, как это было объяснено выше. GZIP имеет тенденцию быть где-то посередине, но с низкой степенью сжатия. BZIP2 медленный с обеих сторон, хотя и с лучшим соотношением. BLOSC - один из алгоритмов, который я нашел, чтобы получить довольно сжатие, и быстрое на обоих концах. Недостатком BLOSC является то, что он реализован не во всех реализациях HDF5. Таким образом, ваша программа не может быть переносимой. Вам всегда нужно сделать хотя бы несколько тестов, чтобы выбрать лучшую конфигурацию для ваших нужд.

1
Igor Podolak

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

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

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

1
Mike

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

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

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

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

1
Eelco Hoogendoorn

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

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

Он хранит массивов в файле или сжатый в памяти. Сжатие основано на blosc . Смотрите scipy video для некоторого контекста.

0
SiggyF