C1W3.LAB.Linear algebra in Python with NumPy

理论课:C1W3.Vector Space Models


理论课: C1W3.Vector Space Models

Numpy 是 Python 中最常用的数组操作库之一。它使我们只需几行代码就能对大型多维数组进行操作,不用再为矩阵操作而编写嵌套循环!
导入 numpy 库,并为其指定别名 np。这个是约定俗成的命名。

import numpy as np  # The swiss knife of the data scientist.

Defining lists and numpy arrays

list 是 Python 的内置数据结构,可以包含不同类型的元素,如整数、浮点数、字符串等,甚至可以包含其他列表。
array 通常指的是 array 模块中的数组,它只能包含相同类型的元素,主要用于数值计算。

alist = [1, 2, 3, 4, 5]   # Define a python list. It looks like an np array
narray = np.array([1, 2, 3, 4]) # Define a numpy array
print(alist)
print(narray)

print(type(alist))
print(type(narray))

结果:
[1, 2, 3, 4, 5]
[1 2 3 4]
<class ‘list’>
<class ‘numpy.ndarray’>

Algebraic operators on NumPy arrays vs. Python lists

初学者常见的错误之一就是混淆 NumPy 数组和 Python 列表的线性操作。例如:NumPy 数组中的 "+"操作符执行的是元素加法,而 Python 列表中的相同操作则是列表连接。

print(narray + narray)
print(alist + alist)

结果:
[2 4 6 8]
[1, 2, 3, 4, 5, 1, 2, 3, 4, 5]
这里注意替换两种数据结构设计的用途。
对应乘法运算符也有不同效果,对于矩阵相当于向量的放大,而list则相当于拼接操作:

print(narray * 3)
print(alist * 3)

结果:
[ 3 6 9 12]
[1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5]

Matrix or Array of Arrays

在线性代数中,矩阵是由 n 行和 m 列组成的结构。这意味着每一行必须有相同数量的列。在 NumPy 中,我们有两种创建矩阵的方法:

  • 使用 np.array(推荐)创建数组数组。
  • 使用 np.matrix创建矩阵(仍然可用,但可能很快就会移除)。

NumPy 数组或列表可用于初始化矩阵,但生成的矩阵将仅由 NumPy 数组组成。
下面看三种初始化矩阵的方式:

npmatrix1 = np.array([narray, narray, narray]) # Matrix initialized with NumPy arrays
npmatrix2 = np.array([alist, alist, alist]) # Matrix initialized with lists
npmatrix3 = np.array([narray, [1, 1, 1, 1], narray]) # Matrix initialized with both types

print(npmatrix1)
print(npmatrix2)
print(npmatrix3)

[[1 2 3 4]
[1 2 3 4]
[1 2 3 4]]
[[1 2 3 4 5]
[1 2 3 4 5]
[1 2 3 4 5]]
[[1 2 3 4]
[1 1 1 1]
[1 2 3 4]]

Scaling and translating matrices

建立正确 NumPy 数组和矩阵后,再看看在 Python 中使用常规代数运算符(如 + 和 -)对它们进行操作有多简单。这些操作可以在数组与数组之间或数组与标量之间进行。

okmatrix = np.array([[1, 2], [3, 4]]) # Define a 2x2 matrix
print(okmatrix) # Print okmatrix
# Scale by 2 and translate 1 unit the matrix
result = okmatrix * 2 + 1 # For each element in the matrix, multiply by 2 and add 1
print(result)

结果:
[[1 2]
[3 4]]
[[3 5]
[7 9]]

# Add two compatible matrices
result1 = okmatrix + okmatrix
print(result1)

# Subtract two compatible matrices. This is called the difference vector
result2 = okmatrix - okmatrix
print(result2)

结果:
[[2 4]
[6 8]]
[[0 0]
[0 0]]
注意,星号代表的是元素相乘。请勿将其与点乘混淆。

result = okmatrix * okmatrix # Multiply each element by itself
print(result)

结果:
[[ 1 4]
[ 9 16]]

Transpose a matrix

在线性代数中,矩阵的转置是一种将矩阵在其对角线上翻转的运算,转置运算将矩阵的行和列索引互换,产生另一个矩阵。如果原始矩阵的维数是 n 乘 m,那么转置后的矩阵将是 m 乘 n。
通常用上标T 表示 NumPy 矩阵的转置操作。

matrix3x2 = np.array([[1, 2], [3, 4], [5, 6]]) # Define a 3x2 matrix
print('Original matrix 3 x 2')
print(matrix3x2)
print('Transposed matrix 2 x 3')
print(matrix3x2.T)

结果:
Original matrix 3 x 2
[[1 2]
[3 4]
[5 6]]
Transposed matrix 2 x 3
[[1 3 5]
[2 4 6]]
注意,转置不会影响一维数组。

nparray = np.array([1, 2, 3, 4]) # Define an array
print('Original array')
print(nparray)
print('Transposed array')
print(nparray.T)

结果:
Original array
[1 2 3 4]
Transposed array
[1 2 3 4]
上面定义的是一个一维数组,它的形状是 (4,),即有4个元素的数组。当你使用 .T 属性进行转置时,由于一维数组没有行和列的概念,转置操作实际上不会改变数组的形状,只是返回了数组本身。

nparray = np.array([[1, 2, 3, 4]]) # Define a 1 x 4 matrix. Note the 2 level of square brackets
print('Original array')
print(nparray)
print('Transposed array')
print(nparray.T)

结果:
Original array
[[1 2 3 4]]
Transposed array
[[1]
[2]
[3]
[4]]
上面定义的是一个二维数组,形状是 (1, 4),即有1行4列的矩阵。使用 .T 属性进行转置后,矩阵的形状变为 (4, 1),即4行1列的矩阵。

Get the norm of a nparray or matrix

在线性代数中,n 维向量 a ⃗ \vec a a 的范数定义如下:
n o r m ( a ⃗ ) = ∣ ∣ a ⃗ ∣ ∣ = ∑ i = 1 n a i 2 norm(\vec a) = ||\vec a|| = \sqrt {\sum_{i=1}^{n} a_i ^ 2} norm(a )=∣∣a ∣∣=i=1nai2

计算向量甚至矩阵的范数是处理数据时的一种通用操作。Numpy 的linalg子包中有一组线性代数函数,其中包括norm函数。如果没有指定范数的类型,np.linalg.norm 计算的是 L2 范数,也就是欧几里得范数,它是数组元素平方和的平方根。

nparray1 = np.array([1, 2, 3, 4]) # Define an array
norm1 = np.linalg.norm(nparray1)

nparray2 = np.array([[1, 2], [3, 4]]) # Define a 2 x 2 matrix. Note the 2 level of square brackets
norm2 = np.linalg.norm(nparray2) 

print(norm1)
print(norm2)

结果:
5.477225575051661
5.477225575051661

对于一维数组 nparray1 来说,np.linalg.norm(nparray1) 计算的是这个一维数组的 L2 范数。由于 nparray1 是一个一维数组,其 L2 范数实际上就是数组元素平方和的平方根。
对于二维数组 nparray2 来说,np.linalg.norm(nparray2) 默认计算的是矩阵的 L2 范数,这实际上是矩阵的最大奇异值。然而,如果二维数组是方阵,并且我们想要计算所有元素平方和的平方根,我们可以使用 axis 参数来指定沿着哪个轴计算范数。例如,np.linalg.norm(nparray2, axis=1) 会沿着每一列计算范数,而 np.linalg.norm(nparray2, axis=0) 会沿着每一行计算范数。

nparray2 = np.array([[1, 1], [2, 2], [3, 3]]) # Define a 3 x 2 matrix. 

normByCols = np.linalg.norm(nparray2, axis=0) # Get the norm for each column. Returns 2 elements
normByRows = np.linalg.norm(nparray2, axis=1) # get the norm for each row. Returns 3 elements

print(normByCols)
print(normByRows)

结果:
[3.74165739 3.74165739]
[1.41421356 2.82842712 4.24264069]

The dot product between arrays: All the flavors

大小相同的两个向量 a ⃗ \vec a a b ⃗ \vec b b 之间的点积、标量积或内积定义如下:
a ⃗ ⋅ b ⃗ = ∑ i = 1 n a i b i \vec a \cdot \vec b = \sum_{i=1}^{n} a_i b_i a b =i=1naibi

点积吃两个向量,返回一个数字。

nparray1 = np.array([0, 1, 2, 3]) # Define an array
nparray2 = np.array([4, 5, 6, 7]) # Define an array

flavor1 = np.dot(nparray1, nparray2) # Recommended way
print(flavor1)

flavor2 = np.sum(nparray1 * nparray2) # Ok way
print(flavor2)

flavor3 = nparray1 @ nparray2         # Geeks way
print(flavor3)

# As you never should do:             # Noobs way
flavor4 = 0
for a, b in zip(nparray1, nparray2):
    flavor4 += a * b
    
print(flavor4)

结果:
38
38
38
38
这里强烈推荐第一种方法,因为np.dot可以吃矩阵也可以吃列表:

norm1 = np.dot(np.array([1, 2]), np.array([3, 4])) # Dot product on nparrays
norm2 = np.dot([1, 2], [3, 4]) # Dot product on python lists

print(norm1, '=', norm2 )

由范数定义可知,其是向量本身的点积结果再开放,因此可以写成:
n o r m ( a ⃗ ) = ∣ ∣ a ⃗ ∣ ∣ = ∑ i = 1 n a i 2 = a ⋅ a norm(\vec a) = ||\vec a|| = \sqrt {\sum_{i=1}^{n} a_i ^ 2} = \sqrt {a \cdot a} norm(a )=∣∣a ∣∣=i=1nai2 =aa

Sums by rows or columns

对矩阵进行的另一种常规操作是按行或列求和。
正如我们对函数 norm 所做的一样,axis 参数控制着操作的形式:
axis=0 表示每列元素相加。
axis=1 表示将每一行的元素相加。

nparray2 = np.array([[1, -1], [2, -2], [3, -3]]) # Define a 3 x 2 matrix. 

sumByCols = np.sum(nparray2, axis=0) # Get the sum for each column. Returns 2 elements
sumByRows = np.sum(nparray2, axis=1) # get the sum for each row. Returns 3 elements

print('Sum by columns: ')
print(sumByCols)
print('Sum by rows:')
print(sumByRows)

结果:
Sum by columns:
[ 6 -6]
Sum by rows:
[0 0 0]

Get the mean by rows or columns

与求和一样,我们可以使用axis参数按行或列求取mean。均值是各元素之和除以向量长度的结果
m e a n ( a ⃗ ) = ∑ i = 1 n a i n mean(\vec a) = \frac {{\sum_{i=1}^{n} a_i }}{n} mean(a )=ni=1nai

nparray2 = np.array([[1, -1], [2, -2], [3, -3]]) # Define a 3 x 2 matrix. Chosen to be a matrix with 0 mean

mean = np.mean(nparray2) # Get the mean for the whole matrix
meanByCols = np.mean(nparray2, axis=0) # Get the mean for each column. Returns 2 elements
meanByRows = np.mean(nparray2, axis=1) # get the mean for each row. Returns 3 elements

print('Matrix mean: ')
print(mean)
print('Mean by columns: ')
print(meanByCols)
print('Mean by rows:')
print(meanByRows)

结果:
Matrix mean:
0.0
Mean by columns:
[ 2. -2.]
Mean by rows:
[0. 0. 0.]

Center the columns of a matrix

去中心化是矩阵另一个重要的预处理步骤。矩阵居中意味着去掉列内每个元素的列均值。去中心化后矩阵的列均值始终为 0。

nparray2 = np.array([[1, 1], [2, 2], [3, 3]]) # Define a 3 x 2 matrix. 

nparrayCentered = nparray2 - np.mean(nparray2, axis=0) # Remove the mean for each column

print('Original matrix')
print(nparray2)
print('Centered by columns matrix')
print(nparrayCentered)

print('New mean by column')
print(nparrayCentered.mean(axis=0))

结果:
Original matrix
[[1 1]
[2 2]
[3 3]]
Centered by columns matrix
[[-1. -1.]
[ 0. 0.]
[ 1. 1.]]
New mean by column
[0. 0.]
注意:去中心化不适用于行,可考虑对矩阵进行转置,按列去中心化,然后将结果转置回去。例子:

nparray2 = np.array([[1, 3], [2, 4], [3, 5]]) # Define a 3 x 2 matrix. 

nparrayCentered = nparray2.T - np.mean(nparray2, axis=1) # Remove the mean for each row
nparrayCentered = nparrayCentered.T # Transpose back the result

print('Original matrix')
print(nparray2)
print('Centered by rows matrix')
print(nparrayCentered)

print('New mean by rows')
print(nparrayCentered.mean(axis=1))

结果:
Original matrix
[[1 3]
[2 4]
[3 5]]
Centered by rows matrix
[[-1. 1.]
[-1. 1.]
[-1. 1.]]
New mean by rows
[0. 0. 0.]
可以使用静态或者动态方法,当然更推荐前者:

nparray2 = np.array([[1, 3], [2, 4], [3, 5]]) # Define a 3 x 2 matrix. 

mean1 = np.mean(nparray2) # Static way.mean1 
mean2 = nparray2.mean()   # Dinamic way.mean2 

print(mean1, ' == ', mean2)

结果:
3.0 == 3.0

在上面代码中,mean1 和 mean2 都是用来计算 nparray2 矩阵的平均值,但是它们使用的是 NumPy 数组的两种不同方法:

mean1 = np.mean(nparray2) 使用的是 NumPy 库中的 mean 函数。这是一种静态方法,意味着它是直接调用 NumPy 模块提供的一个函数。在这个函数调用中,没有指定 axis 参数,所以它计算的是整个数组的全局均值,即所有元素的总和除以元素的总数。

mean2 = nparray2.mean() 使用的是 NumPy 数组对象的 mean 方法。这是一种动态方法,意味着它是直接在数组对象上调用的一个方法。同样,由于没有指定 axis 参数,它也会计算整个数组的全局均值。

  • 6
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

oldmao_2000

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值