【问题标题】:numpy get the blocks making an array in a matrixnumpy 获取在矩阵中创建数组的块
【发布时间】:2020-10-04 20:02:22
【问题描述】:

我有一个 numpy 矩阵,如下所示。我想做的是获取包含在此处制作每一行/列的块的数组。这如何在 numpy 中有效地完成?

示例

因此,例如,如果我们有数组 [1 1 1 1 0 1 1 1 1 0](第一行),那么我们将得到 [4 4],因为我们有 2 个 4 块。

对于第一列,我们会得到[3 1],因为我们在开始时有三个1-s,然后是一个零,然后是一个1,然后是更多的零。

提到的矩阵

[[1 1 1 1 0 1 1 1 1 0]
 [1 0 0 1 0 1 1 1 1 1]
 [1 0 1 0 1 0 0 1 0 1]
 [0 1 0 0 1 0 1 0 0 0]
 [1 1 1 1 1 1 0 1 0 1]
 [0 0 1 0 0 1 1 1 0 0]
 [0 0 0 0 1 1 0 1 1 0]
 [0 0 0 0 0 0 0 0 1 1]
 [0 1 0 1 0 1 0 0 0 0]
 [0 0 1 0 0 0 1 1 1 0]]

注意:行从左到右排序,列从上到下。

【问题讨论】:

  • 第 2 行是什么? [1, 1, 5]?第 3 行:[1, 1, 1, 1, 1]?
  • @S3DEV 是的,完全正确
  • @S3DEV 并且同样的操作也应该应用于列(行从左到右排序,列从上到下)
  • 好的。考虑到您正在寻找行和列结果,输出的形状/数据结构是什么。也许每个都有一个输出?
  • @S3DEV 一个包含多个数组的数组,每个数组都具有此处描述的形式(数组按其在矩阵中的出现排序,这意味着描述第一行的数组位于零位置(第一) )。列也是如此。

标签: python arrays numpy matrix


【解决方案1】:

这里有一些 numpy 魔法:

a = np.array([[1, 1, 1, 1, 0, 1, 1, 1, 1, 0],
              [1, 0, 0, 1, 0, 1, 1, 1, 1, 1],
              [1, 0, 1, 0, 1, 0, 0, 1, 0, 1],
              [0, 1, 0, 0, 1, 0, 1, 0, 0, 0],
              [1, 1, 1, 1, 1, 1, 0, 1, 0, 1],
              [0, 0, 1, 0, 0, 1, 1, 1, 0, 0],
              [0, 0, 0, 0, 1, 1, 0, 1, 1, 0],
              [0, 0, 0, 0, 0, 0, 0, 0, 1, 1],
              [0, 1, 0, 1, 0, 1, 0, 0, 0, 0],
              [0, 0, 1, 0, 0, 0, 1, 1, 1, 0]])


a_pad = np.zeros((a.shape[0]+2, a.shape[1]+2))
a_pad[1:-1, 1:-1] = a

cols = [np.diff(np.nonzero(c)[0].reshape(-1, 2), axis=1)[:, 0]
        for c in np.diff(a_pad, axis=0).T[1:-1]]
# [array([3, 1]),  array([1, 2, 1]),  array([1, 1, 2, 1]), ...

rows = [np.diff(np.nonzero(r)[0].reshape(-1, 2), axis=1)[:, 0]
        for r in np.diff(a_pad, axis=1)[1:-1]]
# [array([4, 4]),  array([1, 1, 5]),  array([1, 1, 1, 1, 1]), ...

现在让我们探索一个示例数组 (a[5, :]) 上发生的情况:

# a            [0, 0, 1,  0, 0, 0, 1, 1,  1, 0,]
# pad       [0, 0, 0, 1,  0, 0, 0, 1, 1,  1, 0, 0]
# diff()       [0, 0, 1, -1, 0, 0, 1, 0, 0, -1, 0]
#                     ^   ^        ^         ^
# nonzero()          [2,  3,       6,        9]
# reshape() [[2, 3],
#            [6, 9]]
# diff()     [1, 3]

这个想法是,当在两端用零填充二进制数组时,可以通过应用 np.diff() 轻松找到每个序列的开始和结束(1 where 0->1 and -1 where 1->0)。因此np.nonzero(np.diff()) 给出了每个序列的起点和终点的索引。此外,我们知道开始 (+1) 和结束 (-1) 必须始终交替。所以np.reshape(-1, 2) 给了我们第一列的起点和第二列的终点。在这个数组上再次应用np.diff() 会得到每个序列的长度。

【讨论】:

  • 看起来这很好用!你介意在这里解释一下这个过程吗?
  • 我的解决方案中的方法相同,但类似方法的排列方式不同;)
【解决方案2】:

这是一种按行执行此操作的方法:

def get_blocks(a):
    x = np.diff(a,prepend=0,append=0)
    groups, starts = np.nonzero(x*x+x)
    groups, ends = np.nonzero(x*x-x)
    values = ends - starts
    markers = np.diff(groups, prepend=0)
    marker_idx = np.nonzero(marker_idx)[0]
    return np.split(values, marker_idx)

示例运行:

>>> a = np.array([[1, 1, 1, 1, 0, 1, 1, 1, 1, 0],
   [1, 0, 0, 1, 0, 1, 1, 1, 1, 1],
   [1, 0, 1, 0, 1, 0, 0, 1, 0, 1],
   [0, 1, 0, 0, 1, 0, 1, 0, 0, 0],
   [1, 1, 1, 1, 1, 1, 0, 1, 0, 1],
   [0, 0, 1, 0, 0, 1, 1, 1, 0, 0],
   [0, 0, 0, 0, 1, 1, 0, 1, 1, 0],
   [0, 0, 0, 0, 0, 0, 0, 0, 1, 1],
   [0, 1, 0, 1, 0, 1, 0, 0, 0, 0],
   [0, 0, 1, 0, 0, 0, 1, 1, 1, 0]])
>>> get_blocks(a)
[array([4, 4], dtype=int32), 
array([1, 1, 5], dtype=int32), 
array([1, 1, 1, 1, 1], dtype=int32), 
array([1, 1, 1], dtype=int32), 
array([6, 1, 1], dtype=int32), 
array([1, 3], dtype=int32), 
array([2, 2], dtype=int32), 
array([2], dtype=int32), 
array([1, 1, 1], dtype=int32), 
array([1, 3], dtype=int32)]

如果您在 A.T 上调用它,它也适用于列

【讨论】:

  • np.diff() 接受一个 perpend 和一个 append 参数?!伙计,我应该更频繁地查看文档。
  • @sclaronomic 是的,它似乎是自 2019 年 1 月 numpy 1.16.0 发布以来的一项新功能。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-02-08
  • 2018-07-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多