Numpy массив заполнен в форме ромба - PullRequest
3 голосов
/ 12 октября 2019

Я ищу способ заполнить пустую матрицу в форме ромба.

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

radius = 1
y,x = np.ogrid[-radius: radius + 1, -radius: radius + 1]
matrix = x**2 + y**2 <= radius**2

, которые даютмне это правильный вывод:

[[False  True False]
 [ True  True  True]
 [False  True False]]

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

Ответы [ 4 ]

5 голосов
/ 12 октября 2019

Алмазная маска с заданной длиной матрицы

Вот один из способов усиления broadcasting -

def diamond(n):
    a = np.arange(n)
    b = np.minimum(a,a[::-1])
    return (b[:,None]+b)>=(n-1)//2

Образцы прогонов -

In [73]: diamond(3)
Out[73]: 
array([[False,  True, False],
       [ True,  True,  True],
       [False,  True, False]])

In [74]: diamond(4)
Out[74]: 
array([[False,  True,  True, False],
       [ True,  True,  True,  True],
       [ True,  True,  True,  True],
       [False,  True,  True, False]])

In [75]: diamond(5)
Out[75]: 
array([[False, False,  True, False, False],
       [False,  True,  True,  True, False],
       [ True,  True,  True,  True,  True],
       [False,  True,  True,  True, False],
       [False, False,  True, False, False]])

Алмазная маска с заданным радиусом

Для заданного радиуса еще более упрощается -

def diamond2(r):
    b = np.r_[:r,r:-1:-1]
    return (b[:,None]+b)>=r

И это может быть дополнительно упрощено до однострочного-

def diamond2(r):
    return np.add.outer(*[np.r_[:r,r:-1:-1]]*2)>=r

Образцы прогонов -

In [19]: diamond2(1)
Out[19]: 
array([[False,  True, False],
       [ True,  True,  True],
       [False,  True, False]])

In [20]: diamond2(2)
Out[20]: 
array([[False, False,  True, False, False],
       [False,  True,  True,  True, False],
       [ True,  True,  True,  True,  True],
       [False,  True,  True,  True, False],
       [False, False,  True, False, False]])

In [21]: diamond2(3)
Out[21]: 
array([[False, False, False,  True, False, False, False],
       [False, False,  True,  True,  True, False, False],
       [False,  True,  True,  True,  True,  True, False],
       [ True,  True,  True,  True,  True,  True,  True],
       [False,  True,  True,  True,  True,  True, False],
       [False, False,  True,  True,  True, False, False],
       [False, False, False,  True, False, False, False]])
2 голосов
/ 12 октября 2019

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

half = n//2
matrix =  half <= x+y <= 3 * half and    # lower-left to upper-right borders
         -half <= x-y <= half            # upper-left to lower-right borders

Вторая строка может быть сокращена на abs(x-y) <= half

0 голосов
/ 12 октября 2019

Вот метод, основанный на быстрых шагах:

import numpy as np
from numpy.lib.stride_tricks import as_strided

# my (pp) approach
def diamond_fill(A,center=None,radius=None,fill=True,background=False):
    if hasattr(A,"__iter__"):
        if np.ndim(A) == 2:
            m,n = A.shape
        else:
            m,n = A
            A = np.full((m,n),background)
    else:
        m,n = A,A
        A = np.full((m,n),background)
    if center is None:
        cm,cn = (m-1)//2,(n-1)//2
    else:
        if hasattr(center,"__iter__"):
            cm,cn = center
        else:
            cm,cn = center,center
        cm %= m
        cn %= n
    if radius is None:
        radius = min(cm,cn,m-cm-1,n-cn-1)
    else:
        assert radius <= min(cm,cn,m-cm-1,n-cn-1)
    s,t = A.strides
    diamond = as_strided(A[cm:,cn-radius:],(2,radius+1,radius+1),(t,t-s,t+s))
    diamond[0] = fill
    diamond[1,:-1,:-1] = fill
    return A

# @Divakar
def diamond2(r):
    return np.add.outer(*[np.r_[:r,r:-1:-1]]*2)>=r

# @peer
def peer(radius):
    length = 2*radius + 1 
    zeros_bottom_left  = np.triu(np.ones((length,length)),-((length-1)/2)) 
    zeros_bottom_right = np.rot90(zeros_bottom_left, 1) 
    zeros_top_right    = np.rot90(zeros_bottom_left, 2) 
    zeros_top_left     = np.rot90(zeros_bottom_left, 3)  

    diamond = np.ones((length, length)) * zeros_bottom_left * zeros_bottom_right *\
                                          zeros_top_left * zeros_top_right 
    return diamond

# example    
print(diamond_fill(10,(4,5),4,'X','-'))

# benchmarks
from timeit import timeit

for R in (5,10,100,1000):
    assert np.all(diamond_fill(2*R+1)==diamond2(R))
    assert np.all(diamond_fill(2*R+1)==peer(R))
    print("pp     ",timeit(lambda:diamond_fill(2*R+1),number=100)*10,"ms")
    print("divakar",timeit(lambda:diamond2(R),number=100)*10,"ms")
    print("peer   ",timeit(lambda:peer(R),number=100)*10,"ms")

Пример выполнения:

[['-' '-' '-' '-' '-' 'X' '-' '-' '-' '-']
 ['-' '-' '-' '-' 'X' 'X' 'X' '-' '-' '-']
 ['-' '-' '-' 'X' 'X' 'X' 'X' 'X' '-' '-']
 ['-' '-' 'X' 'X' 'X' 'X' 'X' 'X' 'X' '-']
 ['-' 'X' 'X' 'X' 'X' 'X' 'X' 'X' 'X' 'X']
 ['-' '-' 'X' 'X' 'X' 'X' 'X' 'X' 'X' '-']
 ['-' '-' '-' 'X' 'X' 'X' 'X' 'X' '-' '-']
 ['-' '-' '-' '-' 'X' 'X' 'X' '-' '-' '-']
 ['-' '-' '-' '-' '-' 'X' '-' '-' '-' '-']
 ['-' '-' '-' '-' '-' '-' '-' '-' '-' '-']]
radius 5
pp      0.014590059872716665 ms
divakar 0.02198140005930327 ms
peer    0.0753312800952699 ms
radius 10
pp      0.015058760036481544 ms
divakar 0.023163620062405244 ms
peer    0.07851567002944648 ms
radius 100
pp      0.02892196993343532 ms
divakar 0.09013354996568523 ms
peer    0.5498108400206547 ms
radius 1000
pp      4.311415600386681 ms
divakar 11.687388699647272 ms
peer    68.75276724967989 ms
0 голосов
/ 12 октября 2019

Я предполагаю, что ваша матрица имеет нечетную длину. Это другой метод, чем тот, который вы используете, но вы все равно можете найти его интересным. Он генерирует матрицы треугольников, которые затем используются для маскировки углов матрицы:

import numpy as np 

radius = 3 
length = 2*3 + 1 
allset = np.ones((length, length)) 
zeros_bottom_left  = np.triu(np.ones((length,length)),-((length-1)/2)) 
zeros_bottom_right = np.rot90(zeros_bottom_left, 1) 
zeros_top_right    = np.rot90(zeros_bottom_left, 2) 
zeros_top_left     = np.rot90(zeros_bottom_left, 3)  

diamond = np.ones((length, length)) * zeros_bottom_left * zeros_bottom_right *\
                                      zeros_top_left * zeros_top_right 
diamond.astype(bool)  
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...