1. 安装以及测试
- 简介
NumPy 是一个运行速度非常快的数学库,主要用于数组计算,包含:
- 一个强大的N维数组对象 ndarray
- 广播功能函数
- 整合 C/C++/Fortran 代码的工具
- 线性代数、傅里叶变换、随机数生成等功能
numpy内置了并行运算功能,当系统有多个核心时,做某种计算时,numpy会自动做并行计算。
Numpy底层使用C语言编写,内部解除了GIL(全局解释器锁),其对数组的操作速度不受Python解释器的限制,所以,其效率远高于纯Python代码。
- 安装
pip install numpy scipy matplotlib
- 测试
from numpy import *
eye(4) # 生成对角矩阵
结果:
array([[1., 0., 0., 0.],
[0., 1., 0., 0.],
[0., 0., 1., 0.],
[0., 0., 0., 1.]])
2. ndarray对象
N 维数组对象 ndarray,它是一系列同类型数据的集合,以 0 下标为开始进行集合中元素的索引。
创建一个ndarray语法:
numpy.array(object, dtype = None, copy = True, order = None, subok = False, ndmin = 0)
参数:
object 数组或嵌套的数列
dtype 数组元素的数据类型,可选
copy 对象是否需要复制,可选
order 创建数组的样式,C为行方向,F为列方向,A为任意方向(默认)
subok 默认返回一个与基类类型一致的数组
ndmin 指定生成数组的最小维度
测试:
import numpy as np
a = np.array([1,2,3])
print (a)
print("======")
b = np.array([[1, 2], [3, 4]])
print (b)
print("======")
c = np.array([1, 2, 3, 4, 5], ndmin = 2)
print (c)
print("======")
d = np.array([1, 2, 3], dtype = complex)
print (d)
结果:
[1 2 3]
======
[[1 2]
[3 4]]
======
[[1 2 3 4 5]]
======
[1.+0.j 2.+0.j 3.+0.j]
3. numpy 数组属性
NumPy 数组的维数称为秩(rank),秩就是轴的数量,即数组的维度,一维数组的秩为 1,二维数组的秩为 2...
在 NumPy中,每一个线性的数组称为是一个轴(axis),也就是维度(dimensions)。比如说,二维数组相当于是两个一维数组,其中第一个一维数组中每个元素又是一个一维数组。很多时候可以声明 axis。axis=0,表示沿着第 0 轴进行操作,即对每一列进行操作;axis=1,表示沿着第1轴进行操作,即对每一行进行操作。
NumPy 的数组中比较重要的对象属性有:
ndarray.ndim 秩,即轴的数量或维度的数量
ndarray.shape 数组的维度,对于矩阵,n 行 m 列
ndarray.size 数组元素的总个数,相当于 .shape 中 n*m 的值
ndarray.dtype ndarray 对象的元素类型
ndarray.itemsize ndarray 对象中每个元素的大小,以字节为单位
ndarray.flags ndarray 对象的内存信息
ndarray.real ndarray元素的实部
ndarray.imag ndarray 元素的虚部
ndarray.data 包含实际数组元素的缓冲区,由于一般通过数组的索引获取元素,所以通常不需要使用这个属性。
测试:
# 函数返回一个有终点和起点的固定步长的排列,如[1,2,3,4,5],起点是1,终点是6,步长为1。
# 1个参数代表终点,起点默认是0,步长默认为1
# 2个参数代表起点终点,步长默认为1
# 三个参数就代表起点、终点、步长
a1 = np.arange(6)
print(a1)
a2 = np.arange(3, 7)
print(a2)
a3 = np.arange(3, 7, 0.5)
print(a3)
print("======1")
# a 现只有一个维度
print (a1.ndim)
# 调整大小. a1.reshape(x,y,z,…) -> 将矩阵a1转变成(x, y,z,…)---->一维长度x,二维长度y,三维长度z,…的矩阵
a11 = a1.reshape(3,2)
print (a11)
print (a11.shape)
print (a11.itemsize)
print(a11.flags)
print(a11[0])
print(a11[0][1])
结果:
[0 1 2 3 4 5]
[3 4 5 6]
[3. 3.5 4. 4.5 5. 5.5 6. 6.5]
======1
1
[[0 1]
[2 3]
[4 5]]
(3, 2)
4
C_CONTIGUOUS : True
F_CONTIGUOUS : False
OWNDATA : False
WRITEABLE : True
ALIGNED : True
WRITEBACKIFCOPY : False
[0 1]
1
4. 数组操作
# reshape 不改变数据的条件下修改形状
# flat 数组元素迭代器
# flatten 返回一份数组拷贝,对拷贝所做的修改不会影响原始数组
# ravel 返回展开数组
a = np.arange(8)
print ('原始数组:')
print (a)
print ('\n')
b = a.reshape(4,2)
print ('修改后的数组:')
print (b)
print ('\n')
print ('b.T 反转数组:(列转行) == self.transpose() ')
print (b.T)
#对数组中每个元素都进行处理,可以使用flat属性,该属性是一个数组元素迭代器:
print ('\n')
print ('flat 迭代后的数组:')
for element in b.T.flat:
print (element)
# flatten(order='C') 返回对数组的拷贝,order:'C' -- 按行,'F' -- 按列,'A' -- 原顺序,'K' -- 元素在内存中的出现顺序。
print ('\n')
print ('flatten 后的数组:')
print(b.T.flatten())
print(b.T.flatten(order='C'))
print(b.T.flatten(order='F'))
# numpy.ravel(a, order='C')展平数组元素,顺序通常是"C风格",返回的是数组视图(view,有点类似 C/C++引用reference的意味),修改会影响原始数组
bt = b.T
print ('bt:')
print(bt)
print ('调用 ravel 函数之后:')
print (bt.ravel())
print ('以 F 风格顺序调用 ravel 函数之后:')
print (bt.ravel(order = 'F'))
print ('bt:')
print(bt)
'''
数组切割、合并、添加删除元素...等操作
'''
结果:
原始数组:
[0 1 2 3 4 5 6 7]
修改后的数组:
[[0 1]
[2 3]
[4 5]
[6 7]]
b.T 反转数组:(列转行) == self.transpose()
[[0 2 4 6]
[1 3 5 7]]
flat 迭代后的数组:
0
2
4
6
1
3
5
7
flatten 后的数组:
[0 2 4 6 1 3 5 7]
[0 2 4 6 1 3 5 7]
[0 1 2 3 4 5 6 7]
bt:
[[0 2 4 6]
[1 3 5 7]]
调用 ravel 函数之后:
[0 2 4 6 1 3 5 7]
以 F 风格顺序调用 ravel 函数之后:
[0 1 2 3 4 5 6 7]
bt:
[[0 2 4 6]
[1 3 5 7]]
5. 数组的创建
# numpy.empty(shape, dtype = float, order = 'C')
# order:有"C"和"F"两个选项,分别代表,行优先和列优先,在计算机内存中的存储元素的顺序。
x1 = np.empty([3,2], dtype = int)
print (x1)
# 数组元素为随机值,因为它们未初始化
# numpy.zeros(shape, dtype = float, order = 'C'): 创建指定大小的数组,数组元素以 0 来填充
# 默认为浮点数
x2 = np.zeros(5)
print(x2)
# 设置类型为整数
y = np.zeros((5,), dtype = int)
print(y)
# numpy.ones:数组元素以 1 来填充:
x3 = np.ones(5)
print(x3)
# 自定义类型
x4 = np.ones([2,2], dtype = int)
print(x4)
print("====3")
# 从已有的数组创建数组
# numpy.asarray(a, dtype = None, order = None)。a:任意形式的输入参数,可以是,列表, 列表的元组, 元组, 元组的元组, 元组的列表,多维数组
# 列表转数组
x5 = [1,2,3]
a5 = np.asarray(x5)
print (a5)
# 元组转数组
x6 = (1,2,3)
a6 = np.asarray(x6)
print (a6)
# 元组列表转为数组
x7 = [(1,2,3), (4,5)]
a7 = np.asarray(x7, dtype=object)
print (a7)
# numpy.frombuffer 接受 buffer 输入参数,以流的形式读入转化成 ndarray 对象。
# numpy.frombuffer(buffer, dtype = float, count = -1, offset = 0)
s8 = b'Hello World'
a8 = np.frombuffer(s8, dtype = 'S1')
print (a8)
# numpy.fromiter 方法从可迭代对象中建立 ndarray 对象,返回一维数组。
# numpy.fromiter(iterable, dtype, count=-1)
# 使用 range 函数创建列表对象
list9=range(5)
it9=iter(list9)
# 使用迭代器创建 ndarray
x9=np.fromiter(it9, dtype=float)
print(x9)
# 从数值范围创建数组
# numpy.arange(start, stop, step, dtype):
# start 起始值,默认为0
# stop 终止值(不包含)
# step 步长,默认为1
# dtype 返回ndarray的数据类型,如果没有提供,则会使用输入数据的类型。
x10 = np.arange(10,20,2)
print (x10)
# numpy.linspace 函数用于创建一个一维数组,数组是一个等差数列构成的
# np.linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None)
a11 = np.linspace(1,10,10)#以下实例用到三个参数,设置起始点为 1 ,终止点为 10,数列个数为 10。
print(a11)
# numpy.logspace 函数用于创建一个于等比数列
# np.logspace(start, stop, num=50, endpoint=True, base=10.0, dtype=None):base 参数意思是取对数的时候 log 的下标。
# 默认底数是 10
a12 = np.logspace(1.0, 2.0, num = 10)
print (a12)
a13 = np.logspace(0,9,10,base=2)
print (a13)
结果:
[[0 1]
[2 3]
[4 5]]
[0. 0. 0. 0. 0.]
[0 0 0 0 0]
[1. 1. 1. 1. 1.]
[[1 1]
[1 1]]
====3
[1 2 3]
[1 2 3]
[(1, 2, 3) (4, 5)]
[b'H' b'e' b'l' b'l' b'o' b' ' b'W' b'o' b'r' b'l' b'd']
[0. 1. 2. 3. 4.]
[10 12 14 16 18]
[ 1. 2. 3. 4. 5. 6. 7. 8. 9. 10.]
[ 10. 12.91549665 16.68100537 21.5443469 27.82559402
35.93813664 46.41588834 59.94842503 77.42636827 100. ]
[ 1. 2. 4. 8. 16. 32. 64. 128. 256. 512.]
6. 矩阵、数组、向量、矢量
矩阵、数组区别
矩阵,英文matrix。和array的区别是矩阵必须是二维的,但array可以是多维的。比如:
1 2
3 4
5 6
如上面这个是3 * 2矩阵,即3行2列。矩阵的维数即行数*列数。 A(ij)指第i行j列。
向量
向量是一种特殊的矩阵,一般是一行或者一列,称为行向量或者列向量。里面有n个元素就代表n维。比如:
[1 2] 是个2维行向量。 [1 3 5] 是个3维列向量
矢量
矢量也常称为向量,但是矢量有方向
矩阵的加法:行列数相等的可以相加(a、b矩阵对应位置的两个元素相加)。矩阵的乘法是每个元素都要乘(3 * a = 3 * a每个位置的元素)。
矩阵向量乘法: m * n 的矩阵 乘以 n * 1 的向量,得到的是 m * 1 的向量
矩阵乘法遵循: (M行, N列)*(N行, L列) = (M行, L列)
矩阵乘法性质满足:结合律,不满足交换律。 A * (B * C) = A * B * C
矩阵的逆
如果一个矩阵是m * m 的方阵,如果有逆矩阵B,则A * B = B * A = C
矩阵转置
将 A 的所有元素绕着一条从第 1 行第 1 列元素出发的右下方 45 度的射线作 镜面反转,即得到 A 的转置。可以简单的理解就是列转行、行转列。
测试一:
a = np.arange(12).reshape(3,4)
print ('原数组:')
print (a)
print ('\n')
print ('转置数组:')
print (a.T)
结果:
原数组:
[[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]]
转置数组:
[[ 0 4 8]
[ 1 5 9]
[ 2 6 10]
[ 3 7 11]]
测试二:
# 矩阵相乘
a1 = np.array([[80, 86],
[82, 80],
[85, 78],
[90, 90],
[86, 82],
[82, 90],
[78, 80],
[92, 94]])
b1 = np.array([[0.7], [0.3]])
print("(8 * 2) 矩阵 * (2 * 1) = 8 * 1 矩阵")
np2 = np.matmul(a1, b1)
print(np2)
print("二者都是矩阵乘法。 np.matmul中禁止矩阵与标量的乘法。 在矢量乘矢量的內积运算中,np.matmul与np.dot没有区别。")
np3 = np.dot(a1, b1)
print(np3)
'''
(8 * 2) 矩阵 * (2 * 1) = 8 * 1 矩阵
[[81.8]
[81.4]
[82.9]
[90. ]
[84.8]
[84.4]
[78.6]
[92.6]]
二者都是矩阵乘法。 np.matmul中禁止矩阵与标量的乘法。 在矢量乘矢量的內积运算中,np.matmul与np.dot没有区别。
[[81.8]
[81.4]
[82.9]
[90. ]
[84.8]
[84.4]
[78.6]
[92.6]]
'''
7. np.linalg 使用
linalg = linear(线性)+ algebra(代数),norm则表示范数。范数是对向量(或者矩阵)的度量,是一个标量(scalar)。
import numpy as np
x = np.array([1, 1])
y = np.array([4, 4])
# x_norm=np.linalg.norm(x, ord=None, axis=None, keepdims=False)
print(np.linalg.norm(x))
print(np.linalg.norm(x, ord=2))
print(np.linalg.norm(x, ord=1))
print(np.linalg.norm(x, ord=np.inf))
print("======0")
print(np.linalg.norm(x - y, ord=2)) # 欧式距离
print(np.linalg.norm(x - y, ord=1)) # 曼哈顿距离
print(np.linalg.norm(x - y, ord=np.inf)) # 切比雪夫距离
print("====1")
x1 = np.array([[1, 2], [3, 4]])
x2 = np.linalg.inv(x1)
# np.linalg.inv 矩阵求逆
print(x2)
print("====2")
print(np.dot(x1, x2))
print(np.dot(x2, x1))
'''
二阶矩阵: [[a, b], [c, d]] 的行列式为 ad - bc
三阶矩阵:
'''
print("======3")
# 求矩阵的行列式
print(np.linalg.det(x1))
结果:
1.4142135623730951
1.4142135623730951
2.0
1.0
======0
4.242640687119285
6.0
3.0
====1
[[-2. 1. ]
[ 1.5 -0.5]]
====2
[[1.0000000e+00 0.0000000e+00]
[8.8817842e-16 1.0000000e+00]]
[[1.00000000e+00 0.00000000e+00]
[1.11022302e-16 1.00000000e+00]]
======3
-2.0000000000000004
上面ord 表示范数类型:
8. 索引
1. 普通索引
a = np.arange(10)
s = slice(2,7,2) # 从索引 2 开始到索引 7 停止,间隔为2
print (a[s])
b = a[2:7:2] # 从索引 2 开始到索引 7 停止,间隔为 2
print(b)
# 冒号 : 的解释:如果只放置一个参数,如 [2],将返回与该索引相对应的单个元素。如果为 [2:],表示从该索引开始以后的所有项都将被提取。如果使用了两个参数,如 [2:7],那么则提取两个索引(不包括停止索引)之间的项
a1 = np.arange(10) # [0 1 2 3 4 5 6 7 8 9]
print(a1[5])
print(a1[2:])
print(a1[2:5])
结果:
[2 4 6]
[2 4 6]
5
[2 3 4 5 6 7 8 9]
[2 3 4]
2. 高级索引
# 整数数组索引
# 以下实例获取数组中 (0,0),(1,1) 和 (2,0) 位置处的元素
x1 = np.array([[1, 2], [3, 4], [5, 6]])
y1 = x1[[0,1,2], [0,1,0]]
print (y1)
# 布尔索引
x2 = np.array([[ 0, 1, 2],[ 3, 4, 5],[ 6, 7, 8],[ 9, 10, 11]])
print (x2 > 5)
print ('大于 5 的元素是:')
print (x2[x2 > 5])
结果:
[1 4 5]
大于 5 的元素是:
[ 6 7 8 9 10 11]
[[False False False]
[False False False]
[ True True True]
[ True True True]]
9. 数组广播
# 广播(Broadcast)是 numpy 对不同形状(shape)的数组进行数值计算的方式, 对数组的算术运算通常在相应的元素上进行。
# 如果两个数组 a 和 b 形状相同,即满足 a.shape == b.shape,那么 a*b 的结果就是 a 与 b 数组对应位相乘。这要求维数相同,且各维度的长度相同。
a = np.array([1,2,3,4])
b = np.array([10,20,30,40])
c = a * b
print (c)
'''
对两个数组,分别比较他们的每一个维度(若其中一个数组没有当前维度则忽略),满足:
数组拥有相同形状。
当前维度的值相等。
当前维度的值有一个是 1。
'''
a1 = np.array([[ 0, 0, 0],
[10,10,10],
[20,20,20],
[30,30,30]])
b1 = np.array([0,1,2])
print(a1 + b1)
10. 迭代数组
a = np.arange(6).reshape(2,3)
print ('原始数组是:')
print (a)
print ('\n')
print ('迭代输出元素:')
for x in np.nditer(a):
print (x, end=", " )
print ('\n')
'''
for x in np.nditer(a, order='F'):Fortran order,即是列序优先;
for x in np.nditer(a.T, order='C'):C order,即是行序优先;
'''
a = np.arange(0,60,5)
a = a.reshape(3,4)
print ('原始数组是:')
print (a)
print ('\n')
print ('原始数组的转置是:')
b = a.T
print (b)
print ('\n')
print ('以 C 风格顺序排序:')
c = b.copy(order='C')
print (c)
for x in np.nditer(c):
print (x, end=", " )
print ('\n')
print ('以 F 风格顺序排序:')
c = b.copy(order='F')
print (c)
for x in np.nditer(c):
print (x, end=", " )
结果:
原始数组是:
[[0 1 2]
[3 4 5]]
迭代输出元素:
0, 1, 2, 3, 4, 5,
原始数组是:
[[ 0 5 10 15]
[20 25 30 35]
[40 45 50 55]]
原始数组的转置是:
[[ 0 20 40]
[ 5 25 45]
[10 30 50]
[15 35 55]]
以 C 风格顺序排序:
[[ 0 20 40]
[ 5 25 45]
[10 30 50]
[15 35 55]]
0, 20, 40, 5, 25, 45, 10, 30, 50, 15, 35, 55,
以 F 风格顺序排序:
[[ 0 20 40]
[ 5 25 45]
[10 30 50]
[15 35 55]]
0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55,
11. 数组运算
# NumPy 算术函数包含简单的加减乘除: add(),subtract(),multiply() 和 divide()
a = np.arange(9, dtype = np.float_).reshape(3, 3)
print ('第一个数组:')
print (a)
b = np.array([2, 3, 4], dtype=np.float_)
print ('两个数组相加:')
print (np.add(a,b))
print ('两个数组相除:')
print (np.divide(a,b))
# numpy.reciprocal() 返回参数逐元素的倒数
print(np.reciprocal(b))
12. 数组统计
# numpy.amin() 用于计算数组中的元素沿指定轴的最小值。
# numpy.amax() 用于计算数组中的元素沿指定轴的最大值。
# axis 为 0,在纵列上求; 为1 在行上求
a = np.arange(9).reshape(3, 3)
print(a)
print (np.amin(a))
print (np.amin(a, 1))
print (np.amin(a,axis = 0))
print("====")
# numpy.ptp():
print ('调用 ptp() 函数:')
print (np.ptp(a))
# numpy.median() 函数用于计算数组 a 中元素的中位数(中值)
print ('调用 median() 函数:')
print (np.median(np.array([1, 2 ,2 ,3])))
# numpy.mean() 函数返回数组中元素的算术平均值。 如果提供了轴,则沿其计算。
# 算术平均值是沿轴的元素的总和除以元素的数量。
print ('调用 mean() 函数:')
a = np.array([[1,2,3],[3,4,5],[4,5,6]])
print(np.mean(a)) # 等价于 33 / 9
print ('沿轴 0 调用 mean() 函数:')
print (np.mean(a, axis = 0))
# numpy.average() 函数根据在另一个数组中给出的各自的权重计算数组中元素的加权平均值。
# 该函数可以接受一个轴参数。 如果没有指定轴,则数组会被展开。
# 不指定权重时相当于 mean 函数
print ('调用 average() 函数:')
a = np.array([1, 2, 3, 4])
print (np.average(a))
print (np.average(a,weights = [4,3,2,1])) #加权平均值 = (1*4+2*3+3*2+4*1)/(4+3+2+1)
# 标准差:std = sqrt(mean((x - x.mean())**2))
# 标准差是一组数据平均值分散程度的一种度量。标准差是方差的算术平方根。
print ('调用 std() 函数:')
# 如果数组是 [1,2,3,4],则其平均值为 2.5。 因此,差的平方是 [2.25,0.25,0.25,2.25],并且再求其平均值的平方根除以 4,即 sqrt(5/4) ,结果为 1.1180339887498949。
print (np.std([1,2,3,4]))
# 方差:统计中的方差(样本方差)是每个样本值与全体样本值的平均数之差的平方值的平均数,即 mean((x - x.mean())** 2)。
# 换句话说,标准差是方差的平方根。
print (np.var([1,2,3,4]))
结果:
[[0 1 2]
[3 4 5]
[6 7 8]]
0
[0 3 6]
[0 1 2]
====
调用 ptp() 函数:
8
调用 median() 函数:
2.0
调用 mean() 函数:
3.6666666666666665
沿轴 0 调用 mean() 函数:
[2.66666667 3.66666667 4.66666667]
调用 average() 函数:
2.5
2.0
调用 std() 函数:
1.118033988749895
1.25
补充:关于方差和标准差
- 方差计算公式
(1) 1 2 3 4 的均值为2.5
(2) 依次计算每个元素与均值差的平方之和,也就是1.5 * 1.5 * 2 + 0.5 * 0.5 * 2 = 5
(3) 求均值: 5 / 4 = 1.25 - 标准差计算公式:
校准差就是对方差求平方根。 sqrt(1.25) = 1.1180