使用 numpy 堆叠具有一个不同维度的数组

Posted

技术标签:

【中文标题】使用 numpy 堆叠具有一个不同维度的数组【英文标题】:Stacking arrays with one different dimension using numpy 【发布时间】:2021-12-29 15:49:34 【问题描述】:

假设我有 2 个数组:

a = np.array([[[1],[1]],[[2],[2]],[[3],[3]],[[4],[4]]])
b = np.array(["a", "b", "c", "d"]).reshape(4,1,1)

然后是a.shape = (4,2,1)b.shape=(4,1,1)。我想要的输出应该是这样的

c = np.array([
[
    np.array([[1],[1]]), "a"
],
[
    np.array([[2],[2]]), "b"
],
[
    np.array([[3],[3]]), "c"
],
[
    np.array([[4],[4]]), "d"
],
])

我尝试了np.hstacknp.concatenate,但这并不完全符合我的要求。我意识到我可以简单地循环遍历 ab 并创建数组,我只是想知道是否有一个特定的函数会返回数组 c 或者循环是我最好的选择。

【问题讨论】:

我看到的最接近的结果是在轴 1 上使用连接,但这不完全是您的预期结果...请问您为什么需要这个?也许还有其他格式可以满足您的要求.. 为什么要在(object dtype)数组中混合数组和字符串?你认为你会从使用数组中获得一些神奇的速度优势吗?还是这样的数组在计算上比列表更好? 【参考方案1】:

您可以结合使用 zip 和 one-liner 进行迭代

a = np.array([[[1],[1]],[[2],[2]],[[3],[3]],[[4],[4]]])
b = np.array(["a", "b", "c", "d"])
c = np.array([[aa,bb] for aa,bb in zip(a,b)])

【讨论】:

这与 OP 使用 for 循环遍历其数组有何不同?我认为他们正在寻找一个特定的 numpy 函数来进行迭代,因为它将被矢量化或至少用 C 编写。 @LiquidSnake,OP 可能不明白他想要什么。 c 是一个对象 dtype 数组,因此“矢量化”魔法不适用。【参考方案2】:

我能得到的最接近的是使用np.column_stack([a, b])。但是,这将包含 numpy 数组中的字符串字符,而不是像您所拥有的那样。

>>> np.column_stack([a,b])
array([[['1'],
        ['1'],
        ['a']],

       [['2'],
        ['2'],
        ['b']],

       [['3'],
        ['3'],
        ['c']],

       [['4'],
        ['4'],
        ['d']]], dtype='<U11')

【讨论】:

【参考方案3】:

首先删除b中不必要的维度:

In [203]: b1 = b.ravel()

第二次从a创建一个4元素对象dtype数组:

In [204]: a1 = np.empty(4, object)
In [205]: a1[:] = list(a)
In [206]: a1
Out[206]: 
array([array([[1],
              [1]]), array([[2],
                            [2]]), array([[3],
                                          [3]]), array([[4],
                                                        [4]])],
      dtype=object)

现在我们可以stack他们在新的第二个轴上创建一个 (4,2) 数组:

In [207]: np.stack((a1,b1), axis=1)
Out[207]: 
array([[array([[1],
               [1]]), 'a'],
       [array([[2],
               [2]]), 'b'],
       [array([[3],
               [3]]), 'c'],
       [array([[4],
               [4]]), 'd']], dtype=object)

列表推导更简单,而且可能更快:

In [209]: [[i,j.item()] for i,j in zip(a,b)]
Out[209]: 
[[array([[1],
         [1]]),
  'a'],
 [array([[2],
         [2]]),
  'b'],
 [array([[3],
         [3]]),
  'c'],
 [array([[4],
         [4]]),
  'd']]

或者制作一个包含 2 个字段的结构化数组:

In [215]: c = np.zeros(4, dtype='O,U1')
In [216]: c
Out[216]: 
array([(0, ''), (0, ''), (0, ''), (0, '')],
      dtype=[('f0', 'O'), ('f1', '<U1')])
In [218]: c['f0'] = list(a)
In [219]: c['f1'] = b.ravel()
In [220]: c
Out[220]: 
array([(array([[1],
              [1]]), 'a'), (array([[2],
                                  [2]]), 'b'), (array([[3],
                                                      [3]]), 'c'),
       (array([[4],
              [4]]), 'd')], dtype=[('f0', 'O'), ('f1', '<U1')])

In [221]: c = np.zeros(4, dtype=[('a',int,(2,1)),('b','U1')])
In [222]: c['a']=a    
In [224]: c['b']=b.ravel()
In [225]: c
Out[225]: 
array([([[1], [1]], 'a'), ([[2], [2]], 'b'), ([[3], [3]], 'c'),
       ([[4], [4]], 'd')], dtype=[('a', '<i8', (2, 1)), ('b', '<U1')])

所有这些方法的关键是了解您要创建的内容。您不是在制作“普通”多维数组。您正在尝试混合使用数组和字符串。

您可以concatenate 制作 (4,3,1) - 并通过指定 dtype 来保留整数。这将 (4,2,1) 与中间维度上的 (4,1,1) 连接起来。这就是连接(以及stack 派生类)最擅长的。

In [263]: np.concatenate((a,b),axis=1, dtype=object)
Out[263]: 
array([[[1],
        [1],
        ['a']],

       [[2],
        [2],
        ['b']],

       [[3],
        [3],
        ['c']],

       [[4],
        [4],
        ['d']]], dtype=object)

【讨论】:

以上是关于使用 numpy 堆叠具有一个不同维度的数组的主要内容,如果未能解决你的问题,请参考以下文章

堆叠两个不同维度的稀疏矩阵

numpy数组的堆叠:numpy.stack, numpy.hstack, numpy.vstack

在 Fortran 中创建具有不同类型元素的数组

在无限滚动页面中加载不同维度的表格,同时最小化表格之间的空白空间

Numpy 中 np.vstack() 和 np.hstack() 简单解析

在循环中附加具有不同维度的numpy ndarray