Вопрос:

Добавление фильтра уникальных значений к движущимся окнам в Python

python arrays numpy multidimensional-array scipy

318 просмотра

2 ответа

45 Репутация автора

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

len (numpy.unique (array)) может сделать это, но для вычисления всех массивов потребуется много итераций. Я могу работать с изображением размером 2000 x 2000, поэтому итерации не являются хорошим вариантом. Все дело в производительности и эффективности памяти.

Вот два решения для движущихся окон шагов:

Первый прямо взят у Эрика Ригторпа по адресу http://www.mail-archive.com/numpy-discussion@scipy.org/msg29450.html.

import numpy as np

def rolling_window_lastaxis(a, window):
    if window < 1:
       raise ValueError, "`window` must be at least 1."
    if window > a.shape[-1]:
       raise ValueError, "`window` is too long."
    shape = a.shape[:-1] + (a.shape[-1] - window + 1, window)
    strides = a.strides + (a.strides[-1],)
    return np.lib.stride_tricks.as_strided(a, shape=shape, strides=strides)

def rolling_window(a, window):
    if not hasattr(window, '__iter__'):
        return rolling_window_lastaxis(a, window)
    for i, win in enumerate(window):
        if win > 1:
            a = a.swapaxes(i, -1)
            a = rolling_window_lastaxis(a, win)
            a = a.swapaxes(-2, i)
    return a

filtsize = (3, 3)
a = np.zeros((10,10), dtype=np.float)
a[5:7,5] = 1

b = rolling_window(a, filtsize)
blurred = b.mean(axis=-1).mean(axis=-1)

Второй от Алекса Рогожникова по адресу http://gozhnikov.github.io/2015/09/30/NumpyTipsAndTricks2.html .

def compute_window_mean_and_var_strided(image, window_w, window_h):
   w, h = image.shape
   strided_image = np.lib.stride_tricks.as_strided(image, 
                                                shape=[w - window_w + 1, h - window_h + 1, window_w, window_h],
                                                strides=image.strides + image.strides)
   # important: trying to reshape image will create complete 4-dimensional compy
   means = strided_image.mean(axis=(2,3)) 
   mean_squares = (strided_image ** 2).mean(axis=(2, 3)) 
   maximums = strided_image.max(axis=(2,3))

   variations = mean_squares - means ** 2
   return means, maximums, variations

image = np.random.random([500, 500])
compute_window_mean_and_var_strided(image, 20, 20)

Есть ли способ добавить / реализовать функцию подсчета уникальных значений в одном или обоих решениях?

Пояснение : в основном мне нужен фильтр уникальных значений для двумерного массива, как и numpy.ndarray.mean.

Спасибо вам

Alex

Автор: Alex C. Источник Размещён: 06.03.2017 08:53

Ответы (2)


0 плюса

127729 Репутация автора

np.meanработает на заданной оси без каких-либо копий. Глядя только на форму as_stridedмассива, он выглядит намного больше, чем исходный массив. Но поскольку каждое «окно» является представлением, оно не занимает дополнительного места. Такие операторы редукции meanработают нормально с таким видом.

Но обратите внимание, что ваш второй пример предупреждает о reshape. Это создает копию; он копирует значения во всех этих окнах.

unique начинается с

ar = np.asanyarray(ar).flatten()

так что сразу же делает заново переработанную копию. Это копия, и 1d. Затем он сортирует элементы, ищет дубликаты и т. Д.

Существуют способы поиска uniqueстрок, но они требуют преобразования строк в большие элементы структурированного массива. По сути, превращение 2d массива в 1d, с которым uniqueможно работать.

Автор: hpaulj Размещён: 06.03.2017 09:14

2 плюса

170159 Репутация автора

Решение

Вот один подход с scikit-imageview_as_windows для эффективного скользящего извлечения окна.

Шаги вовлечены:

  • Получить раздвижные окна.

  • Преобразовать в 2D массив. Обратите внимание, что это сделало бы копию, и, таким образом, мы потеряли бы эффективность views, но сохранили ее векторизацию.

  • Сортировка по оси слитых блочных осей.

  • Получите дифференцирование по этим осям и посчитайте количество различных элементов, которое при добавлении с 1будет числом уникальных значений в каждом из этих скользящих окон и, следовательно, конечным ожидаемым результатом.

Реализация будет выглядеть так -

from skimage.util import view_as_windows as viewW

def sliding_uniq_count(a, BSZ):
    out_shp = np.asarray(a.shape) - BSZ + 1
    a_slid4D = viewW(a,BSZ)    
    a_slid2D = np.sort(a_slid4D.reshape(-1,np.prod(BSZ)),axis=1)    
    return ((a_slid2D[:,1:] != a_slid2D[:,:-1]).sum(1)+1).reshape(out_shp)

Пробный прогон -

In [233]: a = np.random.randint(0,10,(6,7))

In [234]: a
Out[234]: 
array([[6, 0, 5, 7, 0, 8, 5],
       [3, 0, 7, 1, 5, 4, 8],
       [5, 0, 5, 1, 7, 2, 3],
       [5, 1, 3, 3, 7, 4, 9],
       [9, 0, 7, 4, 9, 1, 1],
       [7, 0, 4, 1, 6, 3, 4]])

In [235]: sliding_uniq_count(a, [3,3])
Out[235]: 
array([[5, 4, 4, 7, 7],
       [5, 5, 4, 6, 7],
       [6, 6, 6, 6, 6],
       [7, 5, 6, 6, 6]])

Гибридный подход

Чтобы заставить его работать с очень большими массивами, чтобы вместить все в память, нам, возможно, придется сохранить один цикл, который будет проходить по каждой строке входных данных, например, так:

def sliding_uniq_count_oneloop(a, BSZ):
    S = np.prod(BSZ)
    out_shp = np.asarray(a.shape) - BSZ + 1
    a_slid4D = viewW(a,BSZ)    
    out = np.empty(out_shp,dtype=int)
    for i in range(a_slid4D.shape[0]):
        a_slid2D_i = np.sort(a_slid4D[i].reshape(-1,S),-1)
        out[i] = (a_slid2D_i[:,1:] != a_slid2D_i[:,:-1]).sum(-1)+1
    return out

Гибридный подход - Версия II

Другая версия гибридной, с явным использованием np.lib.stride_tricks.as_strided-

def sliding_uniq_count_oneloop(a, BSZ):
    S = np.prod(BSZ)
    out_shp = np.asarray(a.shape) - BSZ + 1   
    strd = np.lib.stride_tricks.as_strided
    m,n = a.strides
    N = out_shp[1]
    out = np.empty(out_shp,dtype=int)
    for i in range(out_shp[0]):
        a_slid3D = strd(a[i], shape=((N,) + tuple(BSZ)), strides=(n,m,n))
        a_slid2D_i = np.sort(a_slid3D.reshape(-1,S),-1)
        out[i] = (a_slid2D_i[:,1:] != a_slid2D_i[:,:-1]).sum(-1)+1
    return out
Автор: Divakar Размещён: 06.03.2017 09:33
Вопросы из категории :
32x32