注意:我对表单的答案不感兴趣'只是使用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)
问题:
如何使这项工作?
答案 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*4
,2*5
和3*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)