“Checkbord-like”二进制选择

时间:2018-05-05 11:57:46

标签: python numpy

我有一个二维数组

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]])

我需要一个像选择器一样的“检查板”。基本上,我想在第一行中选择奇数元素,甚至在第二行中选择元素,在第三行中选择奇数元素等。

在这种情况下(因为行号是奇数)我可以通过

得到它
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 :(得分:1)

这是一个矢量化解决方案 -

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,
        ....

答案 1 :(得分:0)

你可以在普通的旧python

中做到这一点
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]

如果你正在寻找一种更加pythonic的方式。

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]

答案 2 :(得分:0)

使用基本列表和普通python的示例。

void Rev()
{
 char ch;
 cin.get(ch);
 if (ch != '\n')
 {
    Rev();
    cout.put(ch);
 }