将所有数组元素组合乘以numpy

时间:2016-01-10 15:14:49

标签: python arrays numpy

注意:我对表单的答案不感兴趣'只是使用for循环'或者说,我想以笨拙的方式做到这一点。

我是Python的初学者,我想使用numpy ndarray' s来做以下事情: 给定一系列数字t和另一个数字序列b,对于每个t[i],我想计算列表t[i]*b并将其存储为最终数组中的新行。例如:

t = [3,4]
b = [1,2,3,4]

然后结果应该是某种形式的列表编码

[
  [3,6,9,12], # 3 * the array of b's
  [4,8,12,16]   # 4 * the array of b's
]

在我最近看到的一个程序中,这完美地完成了但是当我想自己做的时候,它会引发一个错误: 运行

import numpy

t = numpy.linspace(3,4,2)[:, None]
t = t.T

# filled with some garbage numbers
b = numpy.ndarray(shape=(4,1), dtype=numpy.float64, order='C')

res = numpy.dot(t,b)

在python(版本3.4)中给出了

Traceback (most recent call last):
  File "C:\Daten\LiClipse_workspace\TestProject\MainPackage\PlayGround.py", line 9, in <module>
    res = numpy.dot(t,b)
ValueError: shapes (1,2) and (4,1) not aligned: 2 (dim 1) != 4 (dim 0)

问题:

如何使这项工作?

2 个答案:

答案 0 :(得分:5)

首先,执行您想要执行的操作的简单(并且可以说是“正确”):使用numpy.outer(),而不是numpy.dot()

>>> import numpy
>>> t = [3,4]
>>> b = [1,2,3,4]
>>> numpy.outer(t, b)
array([[ 3,  6,  9, 12],
       [ 4,  8, 12, 16]])

此函数计算两个1D数组的分量乘积 - 换句话说,它将一个数组的每个元素乘以另一个数组的每个元素 - 并返回带有结果的2D数组。

考虑到Numpy显示结果的方式,您可以将其视为在矩形顶部写入第一个向量,在左侧写入第二个向量,并填充乘法表。

 |   1   2   3   4
-+----------------
3|   3   6   9  12
4|   4   8  12  16

该函数对向量实现常见的数学运算,称为outer product,张量积或Kronecker积。请注意,外部产品不是可交换的;换句话说,根据您给出参数的顺序,您会得到不同的结果。将上述结果与此进行比较:

>>> numpy.outer(b, t)
array([[ 3,  4],
       [ 6,  8],
       [ 9, 12],
       [12, 16]])

再次,您可以将此描述为在第一个参数中编写第一个参数,在第二个参数旁边,并乘以:

 |   3   4
-+---------
1|   3   4
2|   6   8
3|   9  12
4|  12  16
另一方面,Numpy的dot()函数在应用于1D数组时实现dot product,或在应用于2D数组时实现matrix multiplication,或在应用时应用矩阵乘法的通用版本对于更高维的数组,但我会忽略这种情况,因为理解起来有点棘手。

  • 对于两个1D数组,dot()将两个第一个元素相乘,两个第二个元素组合在一起,然后将它们全部加起来,得到一个数字。

    >>> numpy.dot([1,2,3], [4,5,6])
    32
    

    因为1*4+2*5+3*6 == 32。所以基本上,它迭代每个数组的索引,将相应的元素相乘,然后将它们相加。显然,这两个数组必须具有相同的长度。

    您可以通过与outer()类似的方式将其可视化,但不是沿着边缘写入1D数组,而是将它们垂直于边缘写入。您也应该切换订单,原因稍后会变得明确(但它确实是一个实现选择):在左边写第一个,在顶部写第二个。一个例子将证明:

             |   4
             |   5
             |   6
    ---------+----
    1   2   3|  32
    

    为了计算32,我在该单元格上方的列中的相应位置和其旁边的行中乘以元素。 1*42*53*6,然后将它们全部添加。

  • 对于两个2D数组,dot()遍历每个数组的一个轴,将相应的元素相乘,然后将它们相加。迭代的轴是第一个数组的最后一个,第二个数组的第一个(实际上,倒数第二个)。显然,这两个轴必须具有相同的长度。

    根据图表很容易理解这个操作,所以我会直接跳到那个:假设你想要计算

    的矩阵乘积
    array([[ 1,  2,  3],
           [ 4,  5,  6],
           [ 7,  8,  9]])
    

    array([[10, 11],
           [12, 13],
           [14, 15]])
    

    按此顺序。再次,只需在矩形的一侧写下第一个参数,然后在顶部写下第二个参数,然后你就可以乘法和加法来填充每个单元格,就像我用1D示例一样。

              |  10  11
              |  12  13
              |  14  15
    ----------+--------
     1   2   3|  76  82
     4   5   6| 184 199
     7   8   9| 292 316
    

    因为,例如4*10+5*12+6*14 == 184

现在,您可能会注意到可以使用dot()函数执行与outer()函数相同的操作 - 但是您的数组是2D并且维度的长度为1.这就是为什么你必须跳过原始代码示例中的一些环节(如[:, None]索引)才能使其正常工作。它也必须是正确的维度:它必须是第一个数组的最后一个维度,以及第二个数组的倒数第二个维度。因此,在您的具体示例中,您希望按顺序计算[3,4][1,2,3,4]的外部产品,您需要将第一个列表转换为形状(2,1)的数组,并且将第二个列表转换为形状(1,4)的数组。如果你这样做,当你将它们传递给dot()时,它会有效地构建这个图并填充单元格:

     |[[ 1,  2,  3,  4]]
-----+------------------
[[3],|   3   6   9  12
 [4]]|   4   8  12  16

我添加了一些括号,以帮助您将这些要求与Numpy语法联系起来。

在您的问题(numpy.dot(t, b))的代码示例中,您尝试执行的操作与此图表相对应:

        | [[1],
        |  [2],
        |  [3],
        |  [4]]
--------+------------------
[[3, 4]]|   ?

请注意,当您尝试对此应用乘法和加法过程时,它不起作用,因为您在一个数组中有两个元素而在另一个数组中有四个元素,并且您无法将它们配对最多做乘法。这是Numpy向您展示的错误的根源。

当您撤消订单numpy.dot(b, t)时,您会看到此图表:

     |[[ 3,  4]]
-----+----------
[[1],|   3   4
 [2],|   6   8
 [3],|   9  12
 [4]]|  12  16

这确实给你一个明智的结果,但要小心它是否真的是你想要的那个。这是一个形状(4,2)的数组,如果你以最简单的方式修复另一个过程,你会得到一个形状(1,1)的结果,或者实际上只是一个数字。在任何给定的情况下,这些选项中只有一个(最多)可以工作。似乎您在评论中发布的screenshot中的logistic函数期望从dot()函数中出现一个数字;它不适用于更大的矩阵。 (好吧,它可能,但它不会做你想的。)

答案 1 :(得分:0)

这是另一种执行相同计算但产生不同形状的方法。

a = np.array(range(2 * 5 * 3)).reshape((2, 5, 3))
b = np.array(range(4 * 6)).reshape((4, 6))

c = np.zeros((2, 5, 3, 4, 6))
for i1 in range(2):
    for i2 in range(5):
        for i3 in range(3):
            for i4 in range(4):
                for i5 in range(6):
                    c[i1, i2, i3, i4, i5] = a[i1, i2, i3] * b[i4, i5]

d = np.multiply.outer(a, b)

assert np.all(c == d)

比较:

>>> np.multiply.outer(a, b).shape
(2, 5, 3, 4, 6)

>>> np.outer(a, b).shape
(30, 24)

如果你想看起来很聪明,你也可以使用它:np.einsum('ijk,lm->ijklm', a, b)