首页 > 解决方案 > Python数组,如何在没有循环的情况下选择一定距离后的一组列和行

问题描述

我想从一个大的二维数组中选择某些列和行。例如,我想N = 64在每D = 128列之后选择列,如果我的大数组具有 shape (384,384),这将导致更小的(256, 256)矩阵,主要是因为我想从大矩阵中删除冗余数据。

我的代码如下所示,问题是我不知道如何在不使用循环的情况下以一种很好的方式避免显式索引(这里每个方向 4 次,实际上可以实现为具有通用大小的循环)。同样在这个例子中,我从 0 列开始选择,通常它可以从任意列开始。

row_mask = np.zeros(rows, dtype=bool)  # e.g. rows = 384
col_mask = np.zeros(cols, dtype=bool)  # e.g. cols = 384

N = 64
D = 128
# explicit selection of columns and rows
row_mask[0:N] = 1
row_mask[D:D + N] = 1
row_mask[D * 2:D * 2 + N] = 1
row_mask[-N:] = 1
col_mask[0:N] = 1
col_mask[D:D + N] = 1
col_mask[D * 2:D * 2 + N] = 1
col_mask[-N:] = 1

#Image of (384, 384), image of (256, 256)
image = Image[np.ix_(row_mask, col_mask)]

标签: pythonarraysnumpynumpy-ndarray

解决方案


实际上,对于这个具有相对较大图块的示例,在 for 循环中使用切片比通过更昂贵的花式索引避免 for 循环更有效:

from scipy.misc import face
from timeit import timeit

img = face()

def fancy():
    D,N=128,64
    r_mask = np.arange(img.shape[0]) % D < N
    c_mask = np.arange(img.shape[1]) % D < N
    return img[r_mask[:, None] & c_mask].reshape(np.count_nonzero(r_mask), np.count_nonzero(c_mask),3)

def loopy():
    di,dj=64,64
    DI,DJ=128,128
    return np.block([[[img[i:i+di,j:j+dj]] for j in range(0,img.shape[1],DJ)] for i in range(0,img.shape[0],DI)])

(fancy()==loopy()).all()
# True
timeit(loopy,number=100)*10
# 0.763049490051344
timeit(fancy,number=100)*10
# 5.845791429746896

推荐阅读