Numpy详解
ndarray 是多维数组对象, 也是numpy最核心的对象。 在numpy中数组的维度(dimensions)叫做轴(axes), 轴的个数叫做秩(rank). 通常, 夜歌numpy数组的所有元素都是同一类型的数据, 而这些数据的存储和数组的形式无关。
下面的例子, 创建了一个三维数组(numpy 导入时 简化为 np)
1 数组对象
import numpy as np
a = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
print(a)
[[1 2 3]
[4 5 6]
[7 8 9]]
1.1 数据类型
numpy支持比python原生更多的数据类型,常用数据类型[链接]
1.2 创建数组
通常np.array(), 一维数组:np.arange()或者np.linspace()的方法. np.zeros()、np.ones()、np.eys()则可以创建特殊的数据。np.random.randint()和np.random.random()可以构造随机数数组
np.array([[1, 2, 3], [4, 5, 6]]) # 默认类型为int32
array([[1, 2, 3],
[4, 5, 6]])
np.array([[1, 2, 3], [4, 5, 6]], dtype=np.int8) # 指定元素类型为int8
array([[1, 2, 3],
[4, 5, 6]], dtype=int8)
np.arange(5) # 默认指定元素为int32
array([0, 1, 2, 3, 4])
np.arange(3, 8, dtype=np.int8) # 指定类型为int8
array([3, 4, 5, 6, 7], dtype=int8)
np.arange(12).reshape(3, 4) # 改变shape
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]])
np.linspace(1, 2, 5) # 从1到2生成5个浮点数
array([1. , 1.25, 1.5 , 1.75, 2. ])
np.zeros((2, 3)) # 全0数组
array([[0., 0., 0.],
[0., 0., 0.]])
np.ones((2, 3)) # 全一数组
array([[1., 1., 1.],
[1., 1., 1.]])
np.eye(3) # 主对角线为一, 其他元素为0
array([[1., 0., 0.],
[0., 1., 0.],
[0., 0., 1.]])
np.random.random((2,3)) # 生成[0, 1) 之间的随机浮点数
array([[0.05146009, 0.05024011, 0.67549961],
[0.3244844 , 0.24009114, 0.71975804]])
np.random.randint(0, 10, (3 ,2)) # 生成[0, 10) 之间的随机整数
array([[5, 7],
[1, 2],
[9, 7]])
1.3 构建复杂数组
很多时候,我们需要从简单的数据结构,构造出复杂的数组。例如,用一维的数据生成二维的数据
1.3.1 重复数组:tile
a = np.arange(5)
a
array([0, 1, 2, 3, 4])
np.tile(a, 2)
array([0, 1, 2, 3, 4, 0, 1, 2, 3, 4])
np.tile(a, (3, 2))
array([[0, 1, 2, 3, 4, 0, 1, 2, 3, 4],
[0, 1, 2, 3, 4, 0, 1, 2, 3, 4],
[0, 1, 2, 3, 4, 0, 1, 2, 3, 4]])
1.3.2 一维数组网格化:meshgrid
a = np.arange(5)
b = np.arange(5, 10)
np.meshgrid(a, b)
[array([[0, 1, 2, 3, 4],
[0, 1, 2, 3, 4],
[0, 1, 2, 3, 4],
[0, 1, 2, 3, 4],
[0, 1, 2, 3, 4]]), array([[5, 5, 5, 5, 5],
[6, 6, 6, 6, 6],
[7, 7, 7, 7, 7],
[8, 8, 8, 8, 8],
[9, 9, 9, 9, 9]])]
1.3.3 指定范围和分割方式的网格化:mgrid
np.mgrid[0:1:2j, 1:2:3j]
array([[[0. , 0. , 0. ],
[1. , 1. , 1. ]],
[[1. , 1.5, 2. ],
[1. , 1.5, 2. ]]])
np.mgrid[0:1:0.3, 1:2:0.4]
array([[[0. , 0. , 0. ],
[0.3, 0.3, 0.3],
[0.6, 0.6, 0.6],
[0.9, 0.9, 0.9]],
[[1. , 1.4, 1.8],
[1. , 1.4, 1.8],
[1. , 1.4, 1.8],
[1. , 1.4, 1.8]]])
上述例子中用到了虚数。构造虚数的方法如下:
complex(2, 5)
(2+5j)
1.4 数组的属性
numpy的数组除了一些常规的属性外,也有几个类似转置、扁平迭代器等看起来更像是方法的属性。扁平迭代器也许是遍历多为数组的一个简明方法,下面的代码给出了一个例子。
a = np.array([[1, 2, 3], [4, 5, 6]])
a.dtype # 数组元素的数据类型
dtype('int32')
a.dtype.itemsize #数组元素占据的内存字节数
4
a.shape # 数组的维度
(2, 3)
a.size # 数组元素的个数
6
a.T # 数组行变列,类似于矩阵的转置
array([[1, 4],
[2, 5],
[3, 6]])
a.flat # 返回一个扁平迭代器,用于遍历多维数组
print(a.flat)
for item in a.flat:
print(item)
<numpy.flatiter object at 0x00000287DCA5DC60>
1
2
3
4
5
6
1.5 改变数组的维度
numpy数组的存储顺序和数组的维度是不相干的,一次改变数组的维度是非常便捷的操作,除resize()外,这一类操作不会改变所操作的数组本身的存储顺序。
a = np.array([[1, 2, 3], [4, 5, 6]])
print(a.shape) # 查看数组维度
(2, 3)
a.reshape(3, 2) # 返回3行2列的数组
array([[1, 2],
[3, 4],
[5, 6]])
a.ravel() # 返回一维数组
array([1, 2, 3, 4, 5, 6])
a.resize((3, 2)) # 类似于reshape,但会改变所操作的数组
a
array([[1, 2],
[3, 4],
[5, 6]])
1.6 索引与切片
对于一维数组的索引和切片,numpy和python的list一样,甚至更灵活
a = np.arange(9)
a[-1] #最后一个元素
8
a[2:5] # 返回第2到第5个元素
array([2, 3, 4])
a[:7:3] # 返回第0到第7个元素,步长为3
array([0, 3, 6])
a[::-1] # 返回逆序数组
array([8, 7, 6, 5, 4, 3, 2, 1, 0])
假设有一栋2层楼,每层楼内的房间都是3排4列,那我们可以用一个三维数组来保存每个房间的居住人数(当然,也可以是房间面积等其他数值信息)。
a = np.arange(24).reshape(2, 3, 4) # 2层3排4列
a
array([[[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]],
[[12, 13, 14, 15],
[16, 17, 18, 19],
[20, 21, 22, 23]]])
a[1][2][3] #虽然可以这样
23
a[1,2,3] # 但这才是规范的用法
23
a[:,0,0] #所有楼层的1排1列
array([ 0, 12])
a[0, :, :] #一楼所用房间,等价于a[0]或a[0,...]
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]])
a[:,:,1:3] #所有楼层所有排的第2到4列
array([[[ 1, 2],
[ 5, 6],
[ 9, 10]],
[[13, 14],
[17, 18],
[21, 22]]])
a[1,:,-1] # 2层每一排的最后一个房间
array([15, 19, 23])
1.7 数组合并
数组合并触雷下面介绍的水平合并、垂直合并、深度合并外,还有行合并、列合并,以及concatenat()等方式。假如你比我还懒,那就只了解前三种方法,足够用了
a = np.arange(9).reshape(3, 3)
b = np.arange(9, 18).reshape(3, 3)
a
array([[0, 1, 2],
[3, 4, 5],
[6, 7, 8]])
b
array([[ 9, 10, 11],
[12, 13, 14],
[15, 16, 17]])
np.hstack((a, b)) # 水平合并
array([[ 0, 1, 2, 9, 10, 11],
[ 3, 4, 5, 12, 13, 14],
[ 6, 7, 8, 15, 16, 17]])
np.vstack((a, b)) # 垂直合并
array([[ 0, 1, 2],
[ 3, 4, 5],
[ 6, 7, 8],
[ 9, 10, 11],
[12, 13, 14],
[15, 16, 17]])
np.dstack((a, b)) # 深度合并
array([[[ 0, 9],
[ 1, 10],
[ 2, 11]],
[[ 3, 12],
[ 4, 13],
[ 5, 14]],
[[ 6, 15],
[ 7, 16],
[ 8, 17]]])
1.8 数组拆分
a = np.arange(9).reshape(3, 3)
np.hsplit(a, 3) #水平拆分,返回list
[array([[0],
[3],
[6]]), array([[1],
[4],
[7]]), array([[2],
[5],
[8]])]
np.vsplit(a, 3) # 垂直拆分,返回list
[array([[0, 1, 2]]), array([[3, 4, 5]]), array([[6, 7, 8]])]
a = np.arange(27).reshape(3, 3, 3)
np.dsplit(a, 3) #深度拆分,返回list
[array([[[ 0],
[ 3],
[ 6]],
[[ 9],
[12],
[15]],
[[18],
[21],
[24]]]), array([[[ 1],
[ 4],
[ 7]],
[[10],
[13],
[16]],
[[19],
[22],
[25]]]), array([[[ 2],
[ 5],
[ 8]],
[[11],
[14],
[17]],
[[20],
[23],
[26]]])]
1.9 数组运算
数组和常数的四则运算,是数组的每一个元素分别和常数运算;数组和数组的四则运算则是两个数组对应元素的运算(两个数组有相同的shape,否则抛出异常)
import numpy as np
a = np.arange(4, dtype=np.float32).reshape(2, 2)
b = np.arange(4, 8, dtype=np.float32).reshape(2, 2)
a + 2 # 数组和常数可以进行四则运算
array([[2., 3.],
[4., 5.]], dtype=float32)
a / b # 数组和数组可以进行四则运算
array([[0. , 0.2 ],
[0.33333334, 0.42857143]], dtype=float32)
a == b # 最神奇的是, 数组可以判断对应元素是否相等
array([[False, False],
[False, False]])
(a == b).all() # 判断数组是否相等
False
特别提示:如果相对数组内符合特定条件的元素做特殊处理,下面的代码也许有用
a = np.arange(6).reshape((2, 3))
a
array([[0, 1, 2],
[3, 4, 5]])
(a > 2)&(a<=4)
array([[False, False, False],
[ True, True, False]])
a[(a>2)&(a<=4)] # a中满足条件的数组成的数组
array([3, 4])
a[(a>2)&((a<=4))] += 10 # 满足条件的进行后面的运算
a
array([[ 0, 1, 2],
[13, 14, 5]])
1.10 数组方法和常用函数
数组对象本身提供了计算算数平均值、求最大值最小值等内置方法,numpy也提供了很多实用的函数。为了缩减篇幅,下面的代码仅以一维数组为例,展示了这些方法和函数的用法。事实上,大多是情况下这些方法和函数对于多维数组同样有效,只有少数例外,比如compress函数。
import numpy as np
a = np.array([3, 2, 4])
a.sum() # 所有元素之和
9
a.prod() #所有元素的乘积
24
a.mean() #所有元素的算数平均值
3.0
a.max() # 所有元素的最大值
4
a.min() # 所有元素的最小值
2
a.clip(3, 4) # 小于3的元素替换为3,大于4的元素替换为4
array([3, 3, 4])
a.compress(a>2) # 返回大于2的元素构成的数组
array([3, 4])
a.tolist() # 返回python的list
[3, 2, 4]
a.var() # 计算方差(元素与均值之差的平方的均值)
0.6666666666666666
a.std() # 计算标准差
0.816496580927726
a.ptp() # 返回数组的最大值和最小值之差
2
a.argmin() # 返回最小值在扁平数组中的索引
1
a.argmax() # 返回最大值在扁平数组中的索引
2
np.where(a == 2) # 返回所有值为2的元素的索引
(array([1], dtype=int64),)
np.diff(a) # 返回相邻元素的差
array([-1, 2])
np.log(a) # 返回对数数组
array([1.09861229, 0.69314718, 1.38629436])
np.exp(a) # 返回指数数组
array([20.08553692, 7.3890561 , 54.59815003])
np.sqrt(a) # 返回开方数组
array([1.73205081, 1.41421356, 2. ])
np.msort(a) # 数组排序
array([2, 3, 4])
a = np.array([1, 4, 7])
b = np.array([8, 5, 2])
np.maximum(a, b) # 返回多个数组中对应位置元素的最大值数组
array([8, 5, 7])
np.minimum(a,b) # 返回多个数组中对应位置元素的最小值
array([1, 4, 2])
np.true_divide(a,b) # 对整数实现真正的数学除法运算
array([0.125, 0.8 , 3.5 ])
2 矩阵对象
矩阵有的特性可以加速运算, matrix是矩阵对象,继承自ndarray类型,因此含有ndarray的所有数据属性和方法,不过当你吧矩阵对象当作数组操作时需要注意以下几点:
- matrix对象总是二维的,即使是展平(ravel函数)操作或者是成员选择,返回值也是二维的
- matrix队形和darray对象回合的运算总是返回matrix对象
2.1 创建矩阵
matrix对象可以使用一个matlab风格的字符串来创建(以空格分隔列,已分号分隔行的字符床),也可以用数组来创建。
np.mat('1 4 5; 2 3 5; 56 3 1')
matrix([[ 1, 4, 5],
[ 2, 3, 5],
[56, 3, 1]])
np.mat(np.arange(1, 10).reshape(3, 3))
matrix([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
2.2 矩阵特有的属性
m = np.mat(np.arange(1, 10).reshape(3, 3))
m
matrix([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
m.T # 返回矩阵的转置
matrix([[1, 4, 7],
[2, 5, 8],
[3, 6, 9]])
m.H # 返回矩阵的共轭转置
matrix([[1, 4, 7],
[2, 5, 8],
[3, 6, 9]])
m.I # 返回自身的逆矩阵
matrix([[ 3.15251974e+15, -6.30503948e+15, 3.15251974e+15],
[-6.30503948e+15, 1.26100790e+16, -6.30503948e+15],
[ 3.15251974e+15, -6.30503948e+15, 3.15251974e+15]])
m.A #返回自身数据的二维数组的一个视图
array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
2.3 矩阵乘法
对ndarray对象而言,星号是按元素相乘,dot()函数则当作矩阵相乘。对于matrix而言,星号和dot()函数都是矩阵相乘。特别的,对于一维数组,dot()函数实现的是向量点乘,但星号实现的却不是叉乘
a = np.array([1, 2, 3])
b = np.array([4, 5, 6])
a * b # 一维数组元素相乘
array([ 4, 10, 18])
np.dot(a, b) # 一维数组元素相乘,再求和
32
a = np.array([[1, 2], [3, 4]])
b = np.array([[5, 6], [7, 8]])
a * b # 多维数组,元素相乘
array([[ 5, 12],
[21, 32]])
np.dot(a, b) #多维数组,实现矩阵相乘
array([[19, 22],
[43, 50]])
m = np.mat(a)
n = np.mat(b)
np.dot(m, n) # 矩阵相乘
matrix([[19, 22],
[43, 50]])
m * n # 矩阵相乘
matrix([[19, 22],
[43, 50]])
3 线性代数模块
numpy.linalg是numpy的线性代数模块, 可以用来解决逆矩阵、特征值、线性方程组以及行列式等问题
3.1 计算逆矩阵
尽管matrix对象本身有逆矩阵属性,但用numpy.linalg模块来求解矩阵的逆,也是非常简单的。
m = np.mat('0 1 2; 1 0 3; 4 -3 8')
mi = np.linalg.inv(m) # mi即为m的逆矩阵
m * mi
matrix([[1., 0., 0.],
[0., 1., 0.],
[0., 0., 1.]])
3.2 计算行列式
m = np.mat('0 1 2; 1 0 3; 4 -3 8')
np.linalg.det(m)
-2.0
3.3 计算特征值和特征向量
m = np.mat('0 1 2; 1 0 3; 4 -3 8')
np.linalg.eigvals(m) # 计算特征值
array([ 7.96850246, -0.48548592, 0.51698346])
np.linalg.eig(m) # 返回特征值及其对应的特征向量的元组
(array([ 7.96850246, -0.48548592, 0.51698346]),
matrix([[ 0.26955165, 0.90772191, -0.74373492],
[ 0.36874217, 0.24316331, -0.65468206],
[ 0.88959042, -0.34192476, 0.13509171]]))
3.4 求解线性方程组
x - 2y + z = 0
2y - 8z = 8
-4x + 5y + 9z = -9
A = np.mat('1 -2 1; 0 2 -8; -4 5 9')
b = np.array([0, 8, -9])
np.linalg.solve(A, b) # x = 29, y=16, z=3
array([29., 16., 3.])
写个博客不容易,可怜可怜博主,点个广告再走呗(✿◕‿◕✿)。