【问题标题】:Partition array into N chunks with Numpy使用 Numpy 将数组划分为 N 个块
【发布时间】:2013-01-02 14:45:00
【问题描述】:

有这个How do you split a list into evenly sized chunks? 用于将数组拆分为块。对于使用 Numpy 的巨型数组,有没有办法更有效地做到这一点?

【问题讨论】:

  • 对不起,我仍在寻找有效的答案;)。现在我认为 ctypes 是唯一有效的方法。
  • 定义高效。给出一些样本数据,你当前的方法,它有多快,你需要多快。
  • 我们应该将这个问题的输入解释为native Python array,还是numpy ndarray?第一句话似乎暗示了前者。第二句话暗示它要求对前者和后者进行比较。大概只有二维。当我们说“有效地......对于巨型阵列”时,我们是否更关心渐近大 N 的可扩展性,而不管它对于小 N 是否更慢?

标签: python arrays numpy numpy-ndarray


【解决方案1】:

试试numpy.array_split

来自文档:

>>> x = np.arange(8.0)
>>> np.array_split(x, 3)
    [array([ 0.,  1.,  2.]), array([ 3.,  4.,  5.]), array([ 6.,  7.])]

numpy.split 相同,但如果组长度不同,则不会引发异常。

如果块数 > len(array),您会得到嵌套在里面的空白数组,以解决这个问题 - 如果您的拆分数组保存在 a 中,那么您可以通过以下方式删除空数组:

[x for x in a if x.size > 0]

如果您愿意,只需将其保存回 a

【讨论】:

  • 你怎么能删除空列表呢?
  • 你能提供一个小例子吗?
  • if # chunks > len(array) 你得到嵌套在里面的空白数组。
  • 是的,这就是我正在使用的......但无论如何要使用 numpy 来做到这一点? python 中的列表理解很慢。
  • @EiyrioüvonKauyf,要使用 numpy,只需将元素的数量限制为数组的长度:np.array_split(x, min(len(x), 3)) 其中 3 是您想要的默认组数。
【解决方案2】:

只是一些array_splitsplit, hsplit and vsplit的用法示例:

n [9]: a = np.random.randint(0,10,[4,4])

In [10]: a
Out[10]: 
array([[2, 2, 7, 1],
       [5, 0, 3, 1],
       [2, 9, 8, 8],
       [5, 7, 7, 6]])

一些使用array_split的例子:
如果您将数组或列表作为第二个参数,您基本上会给出要“剪切”的索引(之前)

# split rows into 0|1 2|3
In [4]: np.array_split(a, [1,3])
Out[4]:                                                                                                                       
[array([[2, 2, 7, 1]]),                                                                                                       
 array([[5, 0, 3, 1],                                                                                                         
       [2, 9, 8, 8]]),                                                                                                        
 array([[5, 7, 7, 6]])]

# split columns into 0| 1 2 3
In [5]: np.array_split(a, [1], axis=1)                                                                                           
Out[5]:                                                                                                                       
[array([[2],                                                                                                                  
       [5],                                                                                                                   
       [2],                                                                                                                   
       [5]]),                                                                                                                 
 array([[2, 7, 1],                                                                                                            
       [0, 3, 1],
       [9, 8, 8],
       [7, 7, 6]])]

一个整数作为第二个参数。指定相等块的数量:

In [6]: np.array_split(a, 2, axis=1)
Out[6]: 
[array([[2, 2],
       [5, 0],
       [2, 9],
       [5, 7]]),
 array([[7, 1],
       [3, 1],
       [8, 8],
       [7, 6]])]

split 的工作原理相同,但如果无法进行等分,则会引发异常

除了array_split,您还可以使用快捷方式vsplithsplit
vsplithsplit 几乎不言自明:

In [11]: np.vsplit(a, 2)
Out[11]: 
[array([[2, 2, 7, 1],
       [5, 0, 3, 1]]),
 array([[2, 9, 8, 8],
       [5, 7, 7, 6]])]

In [12]: np.hsplit(a, 2)
Out[12]: 
[array([[2, 2],
       [5, 0],
       [2, 9],
       [5, 7]]),
 array([[7, 1],
       [3, 1],
       [8, 8],
       [7, 6]])]

【讨论】:

  • 我的问题是如果 chunks > len(array) 那么你会得到空白的嵌套数组......你如何摆脱它?
  • 很好的例子,谢谢。在您的np.array_split(a, [1], axis=1) 示例中,您知道如何防止第一个数组中的每个元素都嵌套吗?
【解决方案3】:

我相信您正在寻找 numpy.split 或可能是 numpy.array_split 如果节数不需要正确划分数组的大小。

【讨论】:

  • 和我问过 Prashant 的问题一样。如何摆脱空的 numpy 数组?
【解决方案4】:

不是一个完整的答案,而是对其他(正确)答案的代码格式很好的长注释。如果您尝试以下操作,您将看到您得到的是原始数组的视图,而不是副本,并且您链接的问题中接受的答案并非如此。注意可能的副作用!

>>> x = np.arange(9.0)
>>> a,b,c = np.split(x, 3)
>>> a
array([ 0.,  1.,  2.])
>>> a[1] = 8
>>> a
array([ 0.,  8.,  2.])
>>> x
array([ 0.,  8.,  2.,  3.,  4.,  5.,  6.,  7.,  8.])
>>> def chunks(l, n):
...     """ Yield successive n-sized chunks from l.
...     """
...     for i in xrange(0, len(l), n):
...         yield l[i:i+n]
... 
>>> l = range(9)
>>> a,b,c = chunks(l, 3)
>>> a
[0, 1, 2]
>>> a[1] = 8
>>> a
[0, 8, 2]
>>> l
[0, 1, 2, 3, 4, 5, 6, 7, 8]

【讨论】:

  • +1) 这是一个值得考虑的好点,您可以进一步扩展您的解决方案以处理某些 multidim。案例
  • 是的,我现在使用它。我想知道使用 numpy 有更好的方法来做到这一点。尤其是多暗淡:(
  • 这与更大的数据相关。我正在使用numpy.array_split,它似乎可以复制数据。将其传递给您的多处理池将制作另一个数据副本...
【解决方案5】:

这个怎么样?在这里,您使用您想要的长度拆分数组。

a = np.random.randint(0,10,[4,4])

a
Out[27]: 
array([[1, 5, 8, 7],
       [3, 2, 4, 0],
       [7, 7, 6, 2],
       [7, 4, 3, 0]])

a[0:2,:]
Out[28]: 
array([[1, 5, 8, 7],
       [3, 2, 4, 0]])

a[2:4,:]
Out[29]: 
array([[7, 7, 6, 2],
       [7, 4, 3, 0]])

【讨论】:

    【解决方案6】:

    这可以使用 numpy 的as_strided 来实现。我假设如果块大小不是总行数的一个因素,那么最后一批中的其余行将用零填充。

    from numpy.lib.stride_tricks import as_strided
    def batch_data(test, chunk_count):
      m,n = test.shape
      S = test.itemsize
      if not chunk_count:
        chunk_count = 1
      batch_size = m//chunk_count
    # Batches which can be covered fully
      test_batches = as_strided(test, shape=(chunk_count, batch_size, n), strides=(batch_size*n*S,n*S,S)).copy()
      covered = chunk_count*batch_size
      if covered < m:
        rest = test[covered:,:]
        rm, rn = rest.shape
        mismatch = batch_size - rm
        last_batch = np.vstack((rest,np.zeros((mismatch,rn)))).reshape(1,-1,n)
        return np.vstack((test_batches,last_batch))
      return test_batches
    

    这是基于我的回答https://stackoverflow.com/a/68238815/5462372

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-04-04
      • 1970-01-01
      • 2013-06-27
      • 2015-03-28
      • 2021-09-19
      • 2020-05-01
      相关资源
      最近更新 更多