Numpy学习与总结(续篇)

一、NumPy 广播(Broadcast)

广播是 NumPy 中一种对不同形状的数组进行数值计算的强大机制,它能够在不需要显式循环的情况下对数组执行算术运算。

具体来说,当进行算术运算(如加法、减法、乘法、除法等)时,NumPy会按照一定的规则,自动地处理不同形状的数组,使它们能够进行元素级的操作。关键的规则是:

  1. 维度数(轴数)要相同:如果两个数组的维度数不同,可以通过在形状较小的数组的前面插入长度为 1 的维度来使它们的维度数相同。

  2. 各维度的长度要兼容:当两个数组在某个维度上的长度不同时,NumPy会沿着长度为1的维度进行扩展,直到两个数组在所有维度上的形状都匹配为止。

举个例子,假设有数组 ab

  • a.shape 是 (3, 1)

  • b.shape 是 (1, 4)

这两个数组在进行乘法运算时,NumPy会通过广播将它们的形状扩展为:

  • a 扩展为 (3, 4)

  • b 扩展为 (3, 4)

然后对应位置的元素进行相乘,得到最终的结果数组。

import numpy as np  
a = np.array([[3], [3], [3]])
b = np.array([[4, 4, 4, 4]])
c = a * b
print(c)

当运算中的 2 个数组的形状不同时,numpy 将自动触发广播机制。

import numpy as np  
a=np.array([[0,1,2],[3,4,5],[5,6,7]])
b=np.array([0,1,2])
print(a+b)

下面的图片展示了数组 b 如何通过广播来与数组 a 兼容。

广播的规则:

  • 形状对齐:NumPy会自动在较小的数组形状的左侧补 1,使得两个数组的形状在每个维度上保持一致。例如,形状为 (3, 1) 的数组和形状为 (1, 4) 的数组,通过广播可以对齐为 (3, 4)。

  • 输出数组形状:输出数组的形状是输入数组形状的各个维度上的最大值。例如,如果有一个形状为 (3, 1) 和一个形状为 (1, 4) 的数组,它们通过广播运算后得到的数组形状为 (3, 4)。

  • 条件判断:在进行广播时,NumPy会检查对应维度上的长度是否相同或其中一个数组长度为 1。如果这些条件不满足,就会出现 "ValueError: frames are not aligned" 错误,表示无法进行有效的广播操作。

  • 广播运算:一旦形状对齐符合广播规则,NumPy会对每对对应元素执行适当的算术运算。例如,对于两个形状分别为 (3, 1) 和 (1, 4) 的数组进行乘法,会将第一个数组的每一行分别与第二个数组的每一列相乘,得到一个形状为 (3, 4) 的输出数组。

简单理解:对两个数组,分别比较他们的每一个维度(若其中一个数组没有当前维度则忽略),满足:

  • 数组拥有相同形状。

  • 当前维度的值相等。

  • 当前维度的值有一个是 1。

若条件不满足,抛出 "ValueError: frames are not aligned" 异常。

二、Numpy 数组操作

1、修改数组形状

1.1、ndarray.reshape

"""
不改变数据的条件下修改形状:
numpy.reshape(arr, newshape, order='C')
- `arr`:要修改形状的数组
- `newshape`:整数或者整数数组,新的形状应当兼容原有形状
- order:'C' -- 按行,'F' -- 按列,'A' -- 原顺序,'k' -- 元素在内存中的出现顺序
"""
import numpy as np
a=np.arange(6)
b=a.reshape(3,2)
print(b)
numpy.ndarray.flat 是一个数组元素迭代器
a=np.arange(9).reshape(3,3)
for row in a:
    print(row)
for el in a.flat:
    print(el)

1.2、ndarray.flat

numpy.ndarray.flat 是一个数组元素迭代器

import numpy as np
a=np.arange(8).reshape(4,2)
for row in a:
    print(row)
for el in a.flat:
    print(el)
​

1.3、ndarray.flatten

"""
ndarray.flatten 返回一份数组拷贝,对拷贝所做的修改不会影响原始数组:
ndarray.flatten(order='C')
"""
import numpy as np
a=np.arange(8).reshape(2,4)
print(a.flatten())
print(a.flatten(order='F'))#order(可选):'C' -- 按行,'F' -- 按列,'A' -- 原顺序,'K' -- 元素在内存中的出现顺序
​

1.4、ndarray.ravel

numpy.ravel() 展平的数组元素(扁平化),顺序通常是"C风格",返回的是数组视图(view,有点类似 C/C++引用reference的意味),修改会影响原始数组。

"""
用法:
ndarray.ravel(a, order='C')
"""
import numpy as np
a=np.arange(8).reshape(2,4)
print(a.revel())
print(a.revel(order='F'))

2、翻转数组

函数描述
transpose转置
ndarray.T转置

2.1、numpy.transpose、ndarray.T

ndarray.T 类似 numpy.transpose:

import numpy as np
a=np.arange(6).reshape(2,3)
print(np.transpose(a))
print(a.T)

3、连接数组

3.1.numpy.concatenate

"""
numpy.transpose(arr, axes)
- `a1, a2, ...`:相同类型的数组
- `axis`:沿着它连接数组的轴,默认为 0
"""
import numpy as np
a=np.array([[1,2],[3,4]])
b=np.array([[5,6],[7,8]])
print(np.concatenate((a,b)))
print(np.concatenate((a,b),axis=1))

4、分割数组

函数数组及操作
split将一个数组分割为多个子数组
hsplit将一个数组水平分割为多个子数组(按列)
vsplit将一个数组垂直分割为多个子数组(按行)

4.1、numpy.split、numpy.vsplit、numpy.hsplit

"""
沿特定的轴将数组分割为子数组:
numpy.split(ary, indices_or_sections, axis)
- `ary`:被分割的数组
- `indices_or_sections`:如果是一个整数,就用该数平均切分,如果是一个数组,为沿轴切分的位置(左开右闭)
- `axis`:设置沿着哪个方向进行切分,默认为 0,横向切分,即水平方向。为 1 时,纵向切分,即竖直方向。
"""
import numpy as np
a=np.arange(9)
b=np.split(a,3)
print(b)
b=np.split(a,[4,7])
print(b)
axis 为 0 时在水平方向分割,axis 为 1 时在垂直方向分割
a=np.arange(16).reshape(4,4)
b=np.split(a,1)
print(b)
c=np.split(a,2,1)
print('沿水平方向分割:\n',c)
d=np.hsplit(a,2)
print('沿水平方向分割:\n',d)
e = np.split(a, 2, 0)
print('沿垂直方向分割:\n', e)
f = np.vsplit(a, 2)
print('沿垂直方向分割:\n', f)
f=np.vsplit(a,2)
print('沿垂直方向分割:\n',f)

三、NumPy 数学函数

NumPy 包含大量的各种数学运算的函数,包括三角函数,算术运算的函数,复数处理函数等。

1、三角函数

"""
三角函数:sin()、cos()、tan()
"""
import numpy as np
a=np.array([0,30,45,60,90])
du=np.pi/180
print(np.sin(a*du))
print(np.cos(a*du))
print(np.tan(a*du))
"""
arcsin,arccos,和 arctan 函数返回给定角度的 sin,cos 和 tan 的反三角函数。
可以通过 numpy.degrees() 函数将弧度转换为角度。
"""
import numpy as np
a=np.array([0,30,45,60,90])
sin = np.sin(a*np.pi/180)
print(sin)
inv=np.arcsin(sin)
print(inv)
print(np.degrees(inv))#arccos,arctan同理
​

1、舍入函数

"""
numpy.around() 函数返回指定数字的四舍五入值:
numpy.around(a,decimals)
- a: 数组
- decimals: 舍入的小数位数。 默认值为0。 如果为负,整数将四舍五入到小数点左侧的位置
"""
import numpy as np
a = np.array([1.0,6.55,  12,  0.563,  11.52])
print (np.around(a))
print (np.around(a,  1))
print (np.around(a, decimals=-1))
#numpy.floor() 返回小于或者等于指定表达式的最大整数,即向下取整
a = np.array([-1.2,  2.5,  -0.5,  0.8,  9])
print (np.floor(a))
# numpy.ceil() 返回大于或者等于指定表达式的最小整数,即向上取整
a = np.array([-1.2,  2.5,  -0.5,  0.8,  9])
print (np.ceil(a))

四、NumPy 算术函数

NumPy 算术函数包含简单的加减乘除: add()subtract()multiply()divide()

需要注意的是数组必须具有相同的形状或符合数组广播规则。

import numpy as np
a = np.arange(4, dtype = np.float_).reshape(2,2)
b = np.array([5,5])
c=a+b
c=a-b
c=a*b
c=a/b
c=a//b
# print (np.add(a,b))
print (np.subtract(a,b))
print (np.multiply(a,b))
print (np.divide(a,b))

1、numpy.reciprocal()

numpy.reciprocal() 函数返回参数逐元素的倒数。如 1/2倒数为 2/1

import numpy as np  
a=np.array([0.5,1.66,2,10])
print(np.reciprocal(a))

2、numpy.power()

numpy.power() 函数将第一个输入数组中的元素作为底数,计算它与第二个输入数组中相应元素的幂。

实例

import numpy as np  
a=np.array([4,5,6])
print (np.power(a,2))
b=np.array([1,2,3])
print (np.power(a,b))

3、numpy.mod()

numpy.mod() 计算输入数组中相应元素的相除后的余数。

import numpy as np 
a = np.array([10,20,30])
b = np.array([5,7,9])
print (np.mod(a,b))

五、NumPy 副本和视图

  • 视图(浅拷贝)

    视图是对原始数据的一个别称或引用,通过视图可以访问和操作原始数据,但并不会产生数据的拷贝。当你对视图进行修改时,会影响到原始数据。视图一般发生在以下情况:

    • NumPy 切片操作:NumPy 的切片操作返回原数据的视图。例如,如果 arr 是一个 NumPy 数组,arr_view = arr[::2],则 arr_viewarr 的一个视图,修改 arr_view 会影响到 arr

    • 调用 ndarrayview() 函数:这个函数可以创建一个数组的视图,视图与原数组共享数据存储,但形状可能不同。修改视图会影响原数组。

    副本(深拷贝)

    副本是原始数据的完整拷贝,即使对副本进行修改也不会影响到原始数据,它们在物理内存中不同。副本一般发生在以下情况:

    • Python 序列的切片操作:当你对 Python 的列表或其他序列进行切片操作时,会生成一个新的序列对象,这个操作是深拷贝的。例如,list_copy = list_original[:]list_copylist_original 的一个副本。

    • 调用 copy() 函数:在 NumPy 中,ndarray 对象有一个 copy() 方法,调用这个方法会生成一个数组的深拷贝。例如,arr_copy = arr.copy(),则 arr_copyarr 的一个完整副本。

    补充说明

    • 在 NumPy 中,虽然切片操作返回视图,但是有时候也可能返回副本,这取决于切片的方式和是否对结果进行修改。

    • NumPy 的 view() 方法与 Python 中的 deepcopy() 函数并不直接相关,deepcopy() 主要用于 Python 中的一般对象,它会递归地拷贝对象及其包含的所有对象。

1、无复制

简单的赋值不会创建数组对象的副本。 相反,它使用原始数组的相同id()来访问它。 id()返回 Python 对象的通用标识符,类似于 C 中的指针。

此外,一个数组的任何变化都反映在另一个数组上。 例如,一个数组的形状改变也会改变另一个数组的形状。

import numpy as np  
a=np.arange(4)
print(a)
print(id(a))
​
b=a
print(b)
print(id(b))
​
b.shape =(2,2)
print (b)
print (a)

2、视图或浅拷贝

使用ndarray.view() 实现数组的浅拷贝

import numpy as np
arr=np.arange(16)
arr1=arr.view()
print(arr,arr1,id(arr),id(arr1))
arr1[0]=25
print(arr,arr1,id(arr),id(arr1))

切片也是一种浅拷贝

import numpy as np  
arr=np.arange(9)
a=arr[3:]
b=arr[3:]
b[2]=12
print(arr)
print(id(a),id(b),id(arr[3:]))

3、副本或深拷贝

ndarray.copy() 函数创建一个副本。 对副本数据进行修改,不会影响到原始数据,它们物理内存不在同一位置。

import numpy as np  
a=np.array([[2,3],[4,5],[6,8]])
print(a)
b=a.copy()
print(b)
print(id(a),id(b))
b[0,0]=10
print(b)
print(a)

六、NumPy 矩阵库(Matrix)

NumPy 中包含了一个矩阵库 numpy.matlib,该模块中的函数返回的是一个矩阵,而不是 ndarray 对象。

矩阵里的元素可以是数字、符号或数学式。以下是一个由 6 个数字元素构成的 2 行 3 列的矩阵:

 

1、转置矩阵

NumPy 中除了可以使用 numpy.transpose 函数来对换数组的维度,还可以使用 T 属性。。

例如有个 m 行 n 列的矩阵,使用 t() 函数就能转换为 n 行 m 列的矩阵。

实例

import numpy as np 
a = np.arange(12).reshape(3,4) 
print ('原数组:')
print (a)
print ('转置数组:')
print (a.T)

2、numpy.eye()

"""
numpy.eye(n, M,k, dtype)
- n: 返回矩阵的行数
- M: 返回矩阵的列数,默认为 n
- k: 对角线的索引
- dtype: 数据类型
​
"""
import numpy as np
print (np.eye( 2, 3,   0, dtype = float))

3、numpy.identity()

numpy.identity() 函数返回给定大小的单位矩阵。

单位矩阵是个方阵,从左上角到右下角的对角线(称为主对角线)上的元素均为 1,除此以外全都为 0。

 

import numpy as np  
# 大小为 2,类型位浮点型
print (np.identity(2, dtype =  float))

4、numpy.random

numpy.random 是 NumPy 库中用于生成随机数的子模块,提供了各种生成随机数的函数。以下是一些常见的用法及其示例:

4.1.生成服从均匀分布的随机数
  • numpy.random.rand: 生成指定形状的服从均匀分布 [0, 1) 的随机数。

    import numpy as np
    rand_nums = np.random.rand(3, 2)  # 生成一个 3x2 的数组
    print(rand_nums)
    ​
4.2.生成服从标准正态分布的随机数
  • numpy.random.randn: 生成指定形状的服从标准正态分布 (均值为 0,标准差为 1) 的随机数。

    import numpy as np
    rand_nums = np.random.randn(2, 4)  # 生成一个 2x4 的数组
    print(rand_nums)
    ​
4.3.生成整数随机数
  • numpy.random.randint: 生成指定范围内整数随机数。

    import numpy as np
    rand_int = np.random.randint(1, 10, size=(3, 3))  # 生成一个 3x3 的数组,范围在 [1, 10) 内
    print(rand_int)
    ​
4.4.生成随机排列
  • numpy.random.permutation: 返回一个序列的随机排列。

    import numpy as np
    arr = np.array([1, 2, 3, 4, 5])
    rand_perm = np.random.permutation(arr)  # 返回 arr 的随机排列
    print(rand_perm)
    ​
5.随机种子的设置

numpy.random.seed: 设置随机数生成器的种子,以确保随机数可复现性。

import numpy as np
np.random.seed(0)  # 设置随机数种子为 0
rand_nums = np.random.rand(2, 2)
print(rand_nums)
​

七、NumPy 线性代数

函数描述
dot两个数组的点积。
vdot两个向量的点积
inner两个数组的内积
matmul两个数组的矩阵积
determinant数组的行列式
solve求解线性矩阵方程
inv计算矩阵的乘法逆矩阵

1、numpy.dot()

numpy.dot() 函数用于计算两个数组的点积(内积),对于一维数组,它计算的是它们的标准内积;对于多维数组,它返回的是它们的矩阵乘积。

numpy.dot(a, b, out=None) 

参数说明:

  • a, b: 输入的数组,可以是一维或多维数组。对于一维数组,计算它们的内积;对于二维数组,计算它们的矩阵乘积。

  • out: 可选参数,用于指定结果的存储位置。

#一维数组的内积
import numpy as np
​
# 定义两个一维数组
a = np.array([1, 2, 3])
b = np.array([4, 5, 6])
​
# 计算内积
dot_product = np.dot(a, b)
​
print("数组 a:", a)
print("数组 b:", b)
print("内积结果:", dot_product)
​
#二维数组的矩阵乘积
# 定义两个二维数组
c = np.array([[1, 2], [3, 4]])
d = np.array([[5, 6], [7, 8]])
​
# 计算矩阵乘积
matrix_product = np.dot(c, d)
​
print("矩阵 c:")
print(c)
print("矩阵 d:")
print(d)
print("矩阵乘积的结果:")
print(matrix_product)
​

2、numpy.vdot()

#向量的点积
import numpy as np
​
# 定义两个向量
A = np.array([1+2j, 3+4j])
B = np.array([5+6j, 7+8j])
​
# 计算向量的点积
vdot_product = np.vdot(A, B)
​
print("向量 A:", A)
print("向量 B:", B)
print("向量的点积:", vdot_product)
​
#多维数组的扩展点积
# 定义两个二维数组
C = np.array([[1, 2], [3, 4]])
D = np.array([[5, 6], [7, 8]])
​
# 计算数组的扩展点积
vdot_product_2d = np.vdot(C, D)
​
print("矩阵 C:")
print(C)
print("矩阵 D:")
print(D)
print("扩展点积的结果:", vdot_product_2d)
​

3、numpy.inner()

numpy.inner() 函数用于计算两个向量的内积,对于更高维度的数组,它的行为有一些特定规则:

  1. 一维数组的向量内积:

    • numpy.inner() 函数应用于两个一维数组时,它计算的是这两个向量的内积,也称为点积。

  2. 高维数组的乘积规则:

    • 对于更高维度的数组(多维数组),numpy.inner() 函数会在最后一个轴上进行乘积求和。具体来说,它会对数组的最后一个维度上的对应元素进行乘积,然后对这些乘积结果求和,得到一个降低了一个维度的数组。

用一个简单的例子来说明:

import numpy as np
​
# 定义两个一维数组(向量)
A = np.array([1, 2, 3])
B = np.array([4, 5, 6])
​
# 计算向量的内积(点积)
inner_product = np.inner(A, B)
​
print("向量 A:", A)
print("向量 B:", B)
print("向量的内积(点积):", inner_product)
​

4、numpy.matmul

numpy.matmul() 函数的确用于计算两个数组的矩阵乘积。让我来澄清一下:

  1. 二维数组的矩阵乘法:

    • numpy.matmul() 函数应用于两个二维数组(矩阵)时,它执行的是标准的矩阵乘法运算。这意味着它会按照矩阵乘法的规则,将第一个矩阵的行与第二个矩阵的列进行乘积运算,得到一个新的二维数组作为结果。

  2. 多维数组的广义乘法:

    • numpy.matmul() 还支持多维数组的乘法操作。对于高维数组,它会按照广义矩阵乘法的规则进行操作。具体来说,它会在最后两个维度上进行矩阵乘法运算,而其他维度保持不变。

举个例子来说明二维数组的矩阵乘法:

import numpy as np
​
# 定义两个二维数组(矩阵)
A = np.array([[1, 2],
              [3, 4]])
​
B = np.array([[5, 6],
              [7, 8]])
​
# 使用 matmul 计算矩阵乘积
C = np.matmul(A, B)
​
print("矩阵 A:")
print(A)
​
print("\n矩阵 B:")
print(B)
​
print("\n矩阵乘积 C = A @ B:")
print(C)
​

5、numpy.linalg.det()

numpy.linalg.det() 函数用于计算输入矩阵的行列式。在线性代数中,行列式是一个标量值,对于一个 ( n \times n ) 的方阵 ( A ),其行列式通常记作 ( \det(A) )。

行列式的计算涉及到矩阵的特征值和特征向量,其值表示了矩阵在线性变换下的缩放因子,可以用来判断矩阵是否可逆、解方程组的唯一性等。

以下是使用 numpy.linalg.det() 函数计算行列式的一个简单示例:

import numpy as np
​
# 定义一个2x2的矩阵
A = np.array([[1, 2],
              [3, 4]])
​
# 计算矩阵A的行列式
det_A = np.linalg.det(A)
​
print("矩阵 A:")
print(A)
​
print("\n矩阵 A 的行列式 det(A):")
print(det_A)
​

6、numpy.linalg.solve()

numpy.linalg.inv() 函数确实是用来计算矩阵的逆矩阵(inverse matrix)。在线性代数中,逆矩阵是与原矩阵相乘后得到单位矩阵的矩阵。具体来说:

  • 对于一个可逆的方阵 ( A ),存在一个矩阵 ( B ),使得 ( AB = BA = I ),其中 ( I ) 是单位矩阵。

  • 如果矩阵 ( A ) 可逆,那么 ( B ) 就是 ( A ) 的逆矩阵,记作 ( A^{-1} )。

在 NumPy 中,使用 numpy.linalg.inv() 函数可以计算给定方阵的逆矩阵。这个函数接受一个方阵作为输入,并返回其逆矩阵(如果存在的话)。以下是一个简单的示例:

import numpy as np
​
# 创建一个2x2的方阵
A = np.array([[1, 2],
              [3, 4]])
​
# 计算A的逆矩阵
A_inv = np.linalg.inv(A)
​
print("原矩阵 A:")
print(A)
​
print("\nA的逆矩阵 A_inv:")
print(A_inv)
​
# 验证逆矩阵:A与A_inv相乘应该得到单位矩阵
identity = np.dot(A, A_inv)
print("\nA * A_inv =")
print(identity)
​

7、numpy.linalg.inv()

numpy.linalg.inv() 函数确实是用来计算矩阵的逆矩阵(inverse matrix)。在线性代数中,逆矩阵是与原矩阵相乘后得到单位矩阵的矩阵。具体来说:

  • 对于一个可逆的方阵 ( A ),存在一个矩阵 ( B ),使得 ( AB = BA = I ),其中 ( I ) 是单位矩阵。

  • 如果矩阵 ( A ) 可逆,那么 ( B ) 就是 ( A ) 的逆矩阵,记作 ( A^{-1} )。

在 NumPy 中,使用 numpy.linalg.inv() 函数可以计算给定方阵的逆矩阵。这个函数接受一个方阵作为输入,并返回其逆矩阵(如果存在的话)。以下是一个简单的示例:

import numpy as np
​
# 创建一个2x2的方阵
A = np.array([[1, 2],
              [3, 4]])
​
# 计算A的逆矩阵
A_inv = np.linalg.inv(A)
​
print("原矩阵 A:")
print(A)
​
print("\nA的逆矩阵 A_inv:")
print(A_inv)
​
# 验证逆矩阵:A与A_inv相乘应该得到单位矩阵
identity = np.dot(A, A_inv)
print("\nA * A_inv =")
print(identity)
​

  • 19
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值