2016-04-07 2 views
0

Мне нужно рассчитать самый частый элемент в матрице, основанный на соседних значениях и сам. Я нашел функцию generic_filter, которую я использовал для расчета того, что я хотел. Так вот, как я могу сделать это для 2d массиваndimage.generic_function на 3d-массиве

arr = np.array([ 
    [1, 2, 4], 
    [5, 6, 7], 
    [2, 4, 4] 
]) 

def most_frequent(arr): 
    def most_frequent(val): 
     return Counter(val).most_common(1)[0][0] 

    footprint = [[1, 1, 1], [1, 1, 1], [1, 1, 1]] 
    return ndimage.generic_filter(arr, most_frequent, footprint=footprint, mode='constant') 

print most_frequent(arr) 

Это возвращает меня

[[0 0 0] 
[0 4 0] 
[0 0 0]] 

Игнорировать элементы на краю. Как вы видите, средний элемент равен 4, потому что это самый частый элемент среди соседей и значение.

Большая проблема в том, что мне нужно сделать то же самое для 3d-матрицы. Таким образом, для матрицы, как этот

arr = np.array([ 
    [[1, 1], [2, 2], [4, 4]], 
    [[5, 5], [6, 6], [7, 7]], 
    [[2, 2], [4, 4], [4, 4]] 
]) 

Я ожидаю получить [0, 0] везде и [4, 4] в середине. Это не с RuntimeError('filter footprint array has incorrect shape.'). Хуже дело, что у меня есть сомнения, что я могу использовать generic_filter здесь, потому что документы говорят:

CVAL: скаляр, дополнительное значение для заполнения мимо края ввода, если режим «константы».

Так как я могу решить свою проблему?

+0

Имеет ли массив трехмерного ввода только целые числа? – Divakar

+0

Еще один вопрос: вы намереваетесь запускать такой фильтр в скользящем режиме через entir e 3D-массив, который может быть любой длины, а не просто '(3,3,2)', правильно? – Divakar

ответ

1

Здесь полностью векторное решение.

Сначала сделайте плоские окрестности:

(n,m,_)=M.shape 
(sn,sm,s2)=M.strides 
newshape=(n-2,m-2,9,2) 
newstrides=(sn,sm,2*s2,s2) 
neighborhoods=np.lib.stride_tricks.as_strided(M,newshape,newstrides) 
""" 
array([[[[1, 1], 
     [2, 2], 
     [4, 1], 
     [1, 1], 
     [5, 5], 
     [6, 6], 
     [7, 7], 
     [2, 3], 
     [2, 2]], 

     [[2, 2], 
     [4, 1], 
     [1, 1], 
     [5, 5], 
     [6, 6], 
     [7, 7], 
     [2, 3], 
     [2, 2], 
     [4, 1]]]]) 
    """ 

Тогда вы должны упаковать два компонента использовать np.unique, которые работают с 1D массивов. предполагая M.dtype является int32, вы можете сделать это с помощью зрения:

packed_neighborhoods=np.ascontiguousarray(neighborhoods).view(int64) 
In [5]: packed_neighborhoods.shape 
Out[5]: (1, 2, 9, 1) 

Теперь определим функцию, взять 1D массив и найти Indice из наиболее часто, на основе np.unique:

def mostfreq(arr): 
    _,index,counts=unique(arr, return_index=True, return_counts=True) 
    return index[counts.argmax()] 

Нанесите его на хорошую ось:

ind2=apply_along_axis(mostfreq,2,packed_neighborhoods).squeeze() 

И есть результат, включая другие показатели.

ind0,ind1=indices(neighborhoods.shape[:2]) 
print(neighborhoods[ind0,ind1,ind2]) 
""" 
[[[1 1] 
    [4 1]]] 
""" 

Но ваше решение имеет такую ​​же производительность в данный момент;. (

+0

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

+0

Потому что «массив следа фильтра имеет неправильную форму». , вам нужно добавить одно измерение для соответствия данным ndim. Ред. –

+0

Похоже, что есть проблема. Например, для этого массива arr = 'np.array ([ [[1, 1], [2, 2], [4, 1], [1, 1]], [[5, 5], [6 , 6], [7, 7], [2, 3]], [[2, 2], [4, 1], [4, 4], [2, 3]] ]) 'один из Результатом является '[2 1]', но такой элемент даже не существует в массиве. –

0

Один из способов я нашел, как добиться этого, делая что-то вроде

def most_frequent(M): 
    x, y, _ = arr.shape 
    res = np.zeros((x - 2, y - 2, 2)) 
    for i in xrange(1, x - 1): 
     for j in xrange(1, y - 1): 
      neighbors = [M[i - 1, j - 1], M[i - 1, j], M[i - 1, j + 1], M[i, j - 1], M[i, j], M[i, j + 1], M[i + 1, j - 1], M[i + 1, j], M[i + 1, j + 1]] 
      res[i - 1, j - 1] = Counter([tuple(_) for _ in neighbors]).most_common(1)[0][0] 

    return res 

все еще ищет лучшее решение (тот, который не включает в себя мои 2 петли).

+0

Является ли 'M' таким же, как входной 3D-массив? – Divakar

+0

@ Дивакар да, это –