"Checkbord-подобный" бинарный выбор - PullRequest
0 голосов
/ 05 мая 2018

У меня есть 2d массив

test = np.arange(25).reshape((5, 5))
array([[ 0,  1,  2,  3,  4],
       [ 5,  6,  7,  8,  9],
       [10, 11, 12, 13, 14],
       [15, 16, 17, 18, 19],
       [20, 21, 22, 23, 24]])

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

В этом случае (потому что номера строк нечетные), я могу получить это через

test.flatten()[::2]
Out[22]: array([ 0,  2,  4,  6,  8, 10, 12, 14, 16, 18, 20, 22, 24])

, который является "любым другим элементом" в обоих измерениях. Но если мы попробуем это с

test2 = np.arange(16).reshape((4, 4))
test2
Out[23]: 
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11],
       [12, 13, 14, 15]])
test2.flatten()[::2]
Out[27]: array([ 0,  2,  4,  6,  8, 10, 12, 14])

неудивительно, что это не сработало.

Каков общий способ генерации типа выбора, который я хочу, независимо от формы (2d) матрицы? Легко ли (или даже возможно) распространиться на 3d матрицы?

Я предпочитаю эффективные (векторизованные или основанные на Cython) подходы.


Бонус: 3D :

test3 = np.arange(25*3).reshape((3, 5, 5))
Out[30]: 
array([[[ 0,  1,  2,  3,  4],
        [ 5,  6,  7,  8,  9],
        [10, 11, 12, 13, 14],
        [15, 16, 17, 18, 19],
        [20, 21, 22, 23, 24]],
       [[25, 26, 27, 28, 29],
        [30, 31, 32, 33, 34],
        [35, 36, 37, 38, 39],
        [40, 41, 42, 43, 44],
        [45, 46, 47, 48, 49]],
       [[50, 51, 52, 53, 54],
        [55, 56, 57, 58, 59],
        [60, 61, 62, 63, 64],
        [65, 66, 67, 68, 69],
        [70, 71, 72, 73, 74]]])

Здесь речь идет не о нечетных и четных строках , а о соседних элементах. Нет двух соседних элементов должны иметь одинаковый цвет (быть частью одного и того же селектора bool).

То есть, если мы выберем test3[0, ...].flatten()[::2], мы получим [0, ... 24]. Соседний элемент 0 в первом измерении - 25, поэтому мы не хотим этого. Ожидаемый результат -

np.hstack((test3[0, ...].flatten()[::2], test3[1, ...].flatten()[1::2], test3[2, ...].flatten()[::2], ))
Out[42]: 
array([ 0,  2,  4,  6,  8, 10, 12, 14, 17, 19, 21, 23, 25, 27, 29, 31, 32,
       34, 36, 38, 40, 42, 44, 46])

Ответы [ 3 ]

0 голосов
/ 05 мая 2018

Пример использования основных списков и простого Python.

matrix = [
    [ 0,  1,  2,  3],
    [ 4,  5,  6,  7],
    [ 8,  9, 10, 11],
    [12, 13, 14, 15]
]

result = (row[i % 2::2] for i, row in enumerate(matrix))

flattened_result = [cell for filtered_row in result for cell in filtered_row]

print(flattened_result)
0 голосов
/ 05 мая 2018

Вот одно векторизованное решение -

def checker_select(a):
    m,n = a.shape[-2:]
    i,j = np.ogrid[:m,:n]
    mask = (i+j)%2==0
    return a.reshape(-1,m,n)[:,mask].ravel()

Вероятно, быстрее с array-initialization -

def checker_select_v2(a):
    m,n = a.shape[-2:]
    mask = np.zeros((m,n), dtype=bool)
    mask[::2,::2] = 1
    mask[1::2,1::2] = 1
    return a.reshape(-1,m,n)[:,mask].ravel()

Пробный прогон для 2D -

In [117]: a
Out[117]: 
array([[ 0,  1,  2,  3,  4],
       [ 5,  6,  7,  8,  9],
       [10, 11, 12, 13, 14],
       [15, 16, 17, 18, 19],
       [20, 21, 22, 23, 24]])

In [118]: checker_select(a)
Out[118]: array([ 0,  2,  4,  6,  8, 10, 12, 14, 16, 18, 20, 22, 24])

Образец прогона для 3D -

In [144]: a
Out[144]: 
array([[[  0,   1,   2,   3,   4],
        [  5,   6,   7,   8,   9],
        [ 10,  11,  12,  13,  14],
        [ 15,  16,  17,  18,  19],
        [ 20,  21,  22,  23,  24]],

       [[ 25,  26,  27,  28,  29],
        [ 30,  31,  32,  33,  34],
        [ 35,  36,  37,  38,  39],
        [ 40,  41,  42,  43,  44],
        [ 45,  46,  47,  48,  49]],

        ....

In [145]: checker_select(a)
Out[145]: 
array([  0,   2,   4,   6,   8,  10,  12,  14,  16,  18,  20,  22,  24,
        25,  27,  29,  31,  33,  35,  37,  39,  41,  43,  45,  47,  49,
        ....
0 голосов
/ 05 мая 2018

Вы можете сделать это в простом старом питоне

mat = np.arange(16).reshape((4, 4))

result = []
for row in range(len(mat)):
    for col in range(len(mat[row])):
        if row % 2 == 0 and col % 2 == 0:
            result.append(mat[row][col])
        elif row % 2 == 1 and col % 2 == 1:
            result.append(mat[row][col])

print(result)

выход

[0, 2, 5, 7, 8, 10, 13, 15]

Если вы ищете более питонический путь.

n = 6
m = 4
mat = np.arange(n * m).reshape((n, m))

flat = mat.flatten()
result = [flat[i] for i in range(len(flat)) if i // m % 2 == i % m % 2]
print(result)

выход

[0, 2, 5, 7, 8, 10, 13, 15, 16, 18, 21, 23]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...