Как расширить pyWavelets для работы с N-мерными данными?

Это может быть вопрос для другого форума, если да, пожалуйста, дайте мне знать. Я заметил, что на тег вейвлета подписано всего 14 человек.

У меня есть элегантный способ расширить разложение вейвлета в pywt (пакет pyWavelets) на несколько измерений. Это должно работать из коробки, если установлен pywt. Тест 1 показывает декомпозицию и рекомпозицию трехмерного массива. Все, что нужно сделать, это увеличить количество измерений, и код будет работать при декомпозиции/перекомпоновке с 4, 6 или даже 18 измерениями данных.

Здесь я заменил функции pywt.wavedec и pywt.waverec. Кроме того, в fn_dec я показываю, как новая функция wavedec работает так же, как и старая.

Однако есть одна загвоздка: он представляет вейвлет-коэффициенты в виде массива той же формы, что и данные. Как следствие, с моими ограниченными знаниями о вейвлетах я смог использовать его только для вейвлетов Хаара. Другие, такие как DB4, например, выводят коэффициенты за края этих строгих границ (это не проблема с текущим представлением коэффициентов в виде списка массивов [CA, CD1 ... CDN]. Еще одна загвоздка в том, что я работал только с 2 ^N реберные кубоиды данных.

Теоретически, я думаю, должна быть возможность убедиться, что "кровотечения" не происходит. Алгоритм такого рода вейвлет-разложения и рекомпозиции обсуждается в «Численных рецептах на языке C» Уильяма Пресса, Сола А. Теукольского, Уильяма Т. Феттерлинга и Брайана П. Фланнери (второе издание). Хотя этот алгоритм предполагает отражение на ребрах, а не другие формы расширения ребер (например, zpd), метод достаточно общий, чтобы работать с другими формами расширения.

Любое предложение о том, как распространить эту работу на другие вейвлеты?

ПРИМЕЧАНИЕ. Этот запрос также опубликован на странице http://groups.google.com/group/pywavelets.

Спасибо, Аджо

import pywt
import sys
import numpy as np

def waveFn(wavelet):
    if not isinstance(wavelet, pywt.Wavelet):
        return pywt.Wavelet(wavelet)
    else:
        return wavelet

# given a single dimensional array ... returns the coefficients.
def wavedec(data, wavelet, mode='sym'):
    wavelet = waveFn(wavelet)

    dLen = len(data)
    coeffs = np.zeros_like(data)
    level = pywt.dwt_max_level(dLen, wavelet.dec_len)

    a = data    
    end_idx = dLen
    for idx in xrange(level):
        a, d = pywt.dwt(a, wavelet, mode)
        begin_idx = end_idx/2
        coeffs[begin_idx:end_idx] = d
        end_idx = begin_idx

    coeffs[:end_idx] = a
    return coeffs

def waverec(data, wavelet, mode='sym'):
    wavelet = waveFn(wavelet)

    dLen = len(data)
    level = pywt.dwt_max_level(dLen, wavelet.dec_len)

    end_idx = 1
    a = data[:end_idx] # approximation ... also the original data 
    d = data[end_idx:end_idx*2]    
    for idx in xrange(level):
        a = pywt.idwt(a, d, wavelet, mode)
        end_idx *= 2
        d = data[end_idx:end_idx*2]
    return a

def fn_dec(arr):
    return np.array(map(lambda row: reduce(lambda x,y : np.hstack((x,y)), pywt.wavedec(row, 'haar', 'zpd')), arr))
    # return np.array(map(lambda row: row*2, arr))

if __name__ == '__main__':
    test  = 1
    np.random.seed(10)
    wavelet = waveFn('haar')
    if test==0:
        # SIngle dimensional test.
        a = np.random.randn(1,8)
        print "original values A"
        print a
        print "decomposition of A by method in pywt"
        print fn_dec(a)
        print " decomposition of A by my method"
        coeffs =  wavedec(a[0], 'haar', 'zpd')
        print coeffs
        print "recomposition of A by my method"
        print waverec(coeffs, 'haar', 'zpd')
        sys.exit()
    if test==1:
        a = np.random.randn(4,4,4)
        # 2 D test
        print "original value of A"
        print a

        # decompose the signal into wavelet coefficients.
        dimensions = a.shape
        for dim in dimensions:
            a = np.rollaxis(a, 0, a.ndim)
            ndim = a.shape
            #a = fn_dec(a.reshape(-1, dim))
            a = np.array(map(lambda row: wavedec(row, wavelet), a.reshape(-1, dim)))
            a = a.reshape(ndim)
        print " decomposition of signal into coefficients"
        print a

        # re-composition of the coefficients into original signal
        for dim in dimensions:
            a = np.rollaxis(a, 0, a.ndim)
            ndim = a.shape
            a = np.array(map(lambda row: waverec(row, wavelet), a.reshape(-1, dim)))
            a = a.reshape(ndim)
        print "recomposition of coefficients to signal"
        print a

person fodon    schedule 18.04.2011    source источник


Ответы (1)


Прежде всего, я хотел бы указать вам на функцию, которая уже реализует -wavelet-transform" rel="noreferrer">Одноуровневое многомерное преобразование (Источник). Он возвращает словарь n-мерных массивов коэффициентов. Коэффициенты адресуются ключами, описывающими тип преобразования (приближение/детали), применяемого к каждому из измерений.

Например, для 2D случая результатом будет словарь с массивами коэффициентов аппроксимации и деталей:

>>> pywt.dwtn([[1,2,3,4],[3,4,5,6],[5,6,7,8],[7,8,9,10]], 'db1')
{'aa': [[5.0, 9.0], [13.0, 17.0]],
 'ad': [[-1.0, -1.0], [-1.0, -1.0]],
 'da': [[-2.0, -2.0], [-2.0, -2.0]],
 'dd': [[0.0, 0.0], [0.0, -0.0]]}

Где aa — массив коэффициентов с преобразованием аппроксимации, примененным к обоим измерениям (LL), а da — массив коэффициентов с преобразованием деталей, примененным к первому измерению, и преобразованием аппроксимации, примененным ко второму (HL) (сравните с вывод dwt2).

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

Вот мой взгляд на часть декомпозиции: https://gist.github.com/934166.

Я также хотел бы затронуть одну проблему, которую вы упомянули в своем вопросе:

Однако есть одна загвоздка: он представляет вейвлет-коэффициенты в виде массива той же формы, что и данные.

Подход к представлению результатов в виде массива той же формы/размера, что и входные данные, на мой взгляд, вреден. Это делает все это излишне сложным для понимания и работы, потому что в любом случае вам придется делать предположения или поддерживать вторичную структуру данных с индексами, чтобы иметь возможность получить доступ к коэффициенту в выходном массиве и выполнить обратное преобразование (см. документацию Matlab для wavedec/waverec ).

Кроме того, несмотря на то, что он отлично работает на бумаге, он не всегда подходит для реальных приложений из-за упомянутых вами проблем: в большинстве случаев размер входных данных не равен 2 ^ n, а прореженный результат свертки сигнала с вейвлет-фильтром больше что «пространство для хранения», что, в свою очередь, может привести к потере данных и неидеальному восстановлению.

Чтобы избежать этих проблем, я бы рекомендовал использовать более естественные структуры данных для представления иерархии данных результатов, такие как списки Python, словари и кортежи (где они доступны).

person nigma    schedule 21.04.2011
comment
В вашем примере с github... рекомпозиция была более сложной частью. Кроме того, мне намного проще манипулировать массивом N-D коэффициентов (... например, сортировать величины коэффициентов и вычитать функцию ранга из величин коэффициентов.) Наконец, сумма квадратов величин коэффициентов такая же, как у выборки. данные, если использовать куб коэффициентов N-D. - person fodon; 22.04.2011