组合两个包含数组的Numpy矩阵

时间:2017-03-23 10:14:56

标签: python arrays numpy

我有两个矩阵(m1和m2),大小为125,30,360,包含不同长度的数组。我想要做的是按元素连接这些数组。现在,我使用for循环执行此操作:

for i in range(125):
    for j in range(30):
        for k in range(360):
            m1[i, j, k] = np.hstack(m1[i, j, k], m2[i, j, k])

因此,生成的m1仍然具有与之前相同的大小,但是,每个元素中的数组都已更改长度。上面的例子有效,但需要很长时间(我在代码中多次这样做)。有更快的方法吗?如果有明确说明,则m1m2创建如下:

m1 = np.zeros([125, 30, 360], dtype=np.ndarray)
for i in range(125):
    for j in range(30):
        for k in range(360):
            m1[i,j,k] = np.array([])
编辑:我上面的文字有点不清楚,这导致了一些混乱。因此,我在下面创建了一个我想做的小例子。

步骤1:创建m1和m2。

m1 = np.zeros([2, 2], dtype=np.ndarray)
m2 = np.zeros([2, 2], dtype=np.ndarray)
for i in range(2):
    for j in range(2):
        m1[i, j] = np.array(range(i+j))
        m2[i, j] = np.array(range(i+j+1))

步骤1导致:

m1 = array([[array([], dtype=float64), array([0])],
  [array([0]), array([0, 1])]], dtype=object)
m2 = array([[array([0]), array([0, 1])],
  [array([0, 1]), array([0, 1, 2])]], dtype=object)

步骤2:连接m1和m2。

for i in range(2):
    for j in range(2):
        m1[i, j] = np.hstack((m1[i, j], m2[i, j]))

步骤2导致:

m1 = array([[array([ 0.]), array([0, 0, 1])],
  [array([0, 0, 1]), array([0, 1, 0, 1, 2])]], dtype=object)

所以,问题是:第2步可以更快完成吗?

1 个答案:

答案 0 :(得分:0)

In [164]: m1 = np.zeros([2, 2], dtype=np.ndarray)
     ...: m2 = np.zeros([2, 2], dtype=np.ndarray)
     ...: for i in range(2):
     ...:     for j in range(2):
     ...:         m1[i, j] = np.array(range(i+j))
     ...:         m2[i, j] = np.array(range(i+j+1))
     ...:         

结果是dtype对象的2个2d数组。 dtype=np.ndarray对于object定义的集合中的任何内容都会变为dtypes

In [165]: m1
Out[165]: 
array([[array([], dtype=float64), array([0])],
       [array([0]), array([0, 1])]], dtype=object)
In [166]: m1.shape
Out[166]: (2, 2)
In [167]: m2.shape
Out[167]: (2, 2)
In [168]: m1[0,0]
Out[168]: array([], dtype=float64)

m1是一个二维数组,包含指向内存中其他对象的指针。在你的情况下,它们是数组,但它们可以是列表,dicts,None,字符串或数字甚至函数。

这样的数组可以被描述为一个美化列表,因为它具有形状(2d),可以被重新整形,并且在少数情况下它甚至会将数学运算投射到元素(例如m1*2)。或者它可能是一个贬值的列表,因为它没有append等方法。

在大多数情况下,对此类数组的numpy操作需要Python级迭代。并且具有需要双循环或等效的2d形状。

与任何nd数组一样,你可以绕过扁平化的嵌套循环;例如,列表理解:

In [173]: [np.concatenate((a,b)) for a,b in zip(m1.flat, m2.flat)]
Out[173]: [array([ 0.]), array([0, 0, 1]), array([0, 0, 1]), array([0, 1, 0, 1, 2])]
In [174]: np.array([np.concatenate((a,b)) for a,b in zip(m1.flat, m2.flat)]).reshape(2,2)
Out[174]: 
array([[array([ 0.]), array([0, 0, 1])],
       [array([0, 0, 1]), array([0, 1, 0, 1, 2])]], dtype=object)

这是frompyfunc可能有用的情况,为您处理更高维度。我发现它提供了一个适度的(最多2倍)加速更明确的循环:

In [177]: f=np.frompyfunc(lambda a,b: np.concatenate((a,b)),2,1)
In [178]: f(m1,m2)
Out[178]: 
array([[array([ 0.]), array([0, 0, 1])],
       [array([0, 0, 1]), array([0, 1, 0, 1, 2])]], dtype=object)

总之,与n-d数值数组上的类似操作相比,对象数组上的任何元素操作都会很慢。