- 引言
根据数学家的说法,点积是一种运算,它取两个等长的向量作为输入,然后返回一个数字(标量)。向量A与向量B的点积用符号表示为A•B。在线性代数中,点积是输入向量中每个对应元素的乘积之和。
本文重点介绍点积的定义以及相关代码实现,闲话少说,我们直接开始吧! - 举个栗子
考虑一下我们去商店购买货品的购物单,如下所示:
Item | Quantity | Unit Cost
Wine | 2 | 12.50
Orange | 12 | 0.50
Muffin | 3 | 1.75
假设我们需要计算我们的购物账单,此时我们需要得到每件商品的成本,然后把它们加起来。要计算每个项目的单个成本,我们需要将该项目的数量乘以其单位价格即可。换句话说,我们需要进行的运算为(212.50)+(120.5)+(3*1.75)=36.25。上述操作被称为加权和。
此外,如果我们将数量和单位价格表示为两个向量,我们也可以将加权和表示为点积的形式。如下所示:
quantity = [2,12,3]
costs = [12.5,.5,1.75]
sum(q*c for q,c in zip(quantity,costs))
上述代码中的点积运算等价于所有物品的单价乘以对应数量求和后得到的总和。
使用Numpy中的点积
同样的操作也可以在NumPy中实现,并获得较好的运行性能。
样例代码如下:import numpy as np quantity = np.array([2,12,3]) costs = np.array([12.5,.5,1.75]) np.sum(quantity*costs) # element-wise multiplication
使用NumPy进行求和的方式更加简单。可以用三种不同的方式实现。
quantity.dot(costs) # dot product way 1
np.dot(quantity,costs) # dot product way 2
quantity @ costs # dot product way 3
- 一维数组运算
在Python中处理行与列相乘时需要特别小心。我们不妨考虑以下二维数组row_vec 和col_vec,如下所示:
row_vec = np.arange(5).reshape(1,5)
col_vec = np.arange(0,50,10).reshape(5,1)
Outputs are:
row_vec =
array([[0, 1, 2, 3, 4]])
col_vec =
array([[ 0],
[10],
[20],
[30],
[40]])
如果我们使用内积进行计算,输出如下:
out = np.dot(row_vec, col_vec)
Output is:
array([[300]]
但是如果我们将二者进行互换呢?输出如下:
out = np.dot(col_vec, row_vec)
Output is:
array([[ 0, 0, 0, 0, 0],
[ 0, 10, 20, 30, 40],
[ 0, 20, 40, 60, 80],
[ 0, 30, 60, 90, 120],
[ 0, 40, 80, 120, 160]])
显然,col_vecrow_vec与row_veccol_vec的输出是不一样的!我们现在有一个5行5列的矩阵,而不再是一个数字。让我们看看结果中任一个元素,看看它来自哪里。回想一下,在Python中,第一个索引是0。我们考虑元素out[1,2],此值为20。它来自col_vec第1行与row_vec 的第2列两个向量的点积,将两者相乘得到结果20。
- 一维数组和二维数组点积运算
当我们把一维数组和二维数组结合起来进行点击运算时,我们应该更加小心。
oned_vec = np.arange(5) # output is array([0, 1, 2, 3, 4])
row_vec = np.arange(5).reshape(1,5)
col_vec = np.arange(0,50,10).reshape(5,1)
np.dot(oned_vec, col_vec) # output is array([300])
np.dot(row_vec, oned_vec) # output is array([30])
然而,如果我们交换相应的次序,代码可能无法正常运行!
np.dot(col_vec, oned_vec)
np.dot(oned_vec, row_vec)
Output:
shapes (5,1) and (5,) not aligned: 1 (dim 1) != 5 (dim 0)
shapes (5,) and (1,5) not aligned: 5 (dim 0) != 1 (dim 0)
从上述错误消息中,我们可以看到col_vec的shape为(5,1),row_vec对应的shpae为(1,5),而oned_vec对应的shape为(5,)。我们知道两个数组进行点积运算,第一个数组的列数应该等于第二个数组的行数,所以上述代码会显式地报上面的错误信息。同时上述代码说明,如果将一个一维的数组放到np.dot()第一个参数位置,则此时oned_vec将被当做shape为(1,5)的数组,同时如果将其放到np.dot()的第二个参数位置,则此时oned_vec将被当做shape为(5,1)的数组。
- 多维数组点积运算
NumPy还允许我们创建具有多个值输出的数组,而不仅仅是一个值。这取决于输入数组的形状,如下所示:
D = np.array([[1,3],[2,5],[2,7],[3,2]])
w = np.array([1.5,2.5])
np.dot(D,w) # [9,15.5,20.5,9.5]
通过上述示例,我们可以看出,1.51+2.53=9依次类推。这里,因为w在右边,所以它可以视为2行1列的数组。我们用一个4行2列的数组乘以一个2行1列的数组,将产生一个包含4个元素的一维数组。
- 总结
本文重点介绍了Numpy中点积的定义,以及相应的运算,并给出了相应的代码示例。