三剑客之Numpy
Numpy是一个开源的python科学计算库,里面包含了很多实用的数学函数,涵盖了线性代数、傅里叶变换和随机数生成等函数。原来的numpy其实是scipy的一部分,后来从scipy中分离出来。
numpy不是python的标准库,需要单独安装。假设你的运行环境已经安装了python包管理工具pip,numpy的安装非常简单:
pip install numpy
一、数组对象
ndarray 是一个多维数组对象,是 numpy 的核心对象。在 numpy 中,数组的维度称为轴,轴的数量称为秩。通常,一个numpy数组的所有元素都是同一类型的数据,这些数据的存储与数组的形式无关。
下面的例子创建一个三维数组(导入numpy时,一般简写为np)。
import numpy as np
a = np.array([[1,2,3],[4,5,6],[7,8,9]])
1、数据类型
numpy支持的数据类型主要有布尔型(bool)、整型(integrate)、浮点型(float)和复数(complex),每种数据类型又根据其子类型占用的字节数分为多个不同的类型。常见的数据类型如下表所示。
2、创建数组
通常,我们使用 np.array() 创建数组。如果只是创建一维数组,也可以使用 np.arange() 或 np.linspace() 方法。 np.zeros()、np.ones()、np.eye()可以构造特殊数据。 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)) # 全1数组
array([[ 1., 1., 1.],
[ 1., 1., 1.]])
>>> np.eye(3) # 主对角线元素为1其他元素为0
array([[ 1., 0., 0.],
[ 0., 1., 0.],
[ 0., 0., 1.]])
>>> np.random.random((2,3)) # 生成[0,1)之间的随机浮点数
array([[ 0.84731148, 0.8222318 , 0.85799278],
[ 0.59371558, 0.92330741, 0.04518351]])
>>> np.random.randint(0,10,(3,2)) # 生成[0,10)之间的随机整数
array([[2, 4],
[8, 3],
[8, 5]])
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]])
(2)重复元素:repeat
>>> a = np.arange(5)
>>> a
array([0, 1, 2, 3, 4])
>>> a.repeat(2)
array([0, 0, 1, 1, 2, 2, 3, 3, 4, 4])
(3)一维数组网格化: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]])]
>>>
(4)指定范围和分割方式的网格化: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)
4、数组的属性
numpy 的数组对象除了一些常规属性外,还有几个看起来更像方法的属性,比如转置和平面迭代器。平面迭代器可能是一种遍历多维数组的简洁方式,下面的代码给出了一个例子。
>>> a = np.array([[1,2,3],[4,5,6]])
>>> a.dtype # 数组元素的数据类型
dtype('int32')
>>> a.dtype.itemsize # 数组元素占据的内存字节数
4
>>> a.itemsize # 数组元素占据的内存字节数
4
>>> a.shape # 数组的维度
(2, 3)
>>> a.size # 数组元素个数
6
>>> a.T # 数组行变列,类似于transpose()
array([[1, 4],
[2, 5],
[3, 6]])
>>> a.flat # 返回一个扁平迭代器,用于遍历多维数组
<numpy.flatiter object at 0x037188F0>
>>> for item in a.flat:
print item
5、改变数组维度
numpy数组的存储顺序与数组的维数无关,所以改变数组的维数是一个非常方便的操作。除了resize(),这类操作不会改变被操作数组本身的存储顺序。
>>> a = np.array([[1,2,3],[4,5,6]])
>>> 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.transpose() # 行变列(类似于矩阵转置)
array([[1, 4],
[2, 5],
[3, 6]])
>>> a.resize((3,2)) # 类似于reshape,但会改变所操作的数组
>>> a
array([[1, 2],
[3, 4],
[5, 6]])
6、索引和切片
对于一维数组的索引和切片,numpy 和 python 的列表一样灵活。
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,:,:] # 1楼的所有房间,等价与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])
7、数组合并
除了下面介绍的水平合并、垂直合并和深度合并外,数组合并还包括行合并、列合并和concatenate()。如果你比我懒,那么只了解前三种方法就够了。
>>> 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]]])
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]]])]
9、数组运算
数组和常量的四种算术运算分别是数组的每个元素和常量的运算;数组与数组的四次算术运算是对两个数组对应元素的运算(两个数组的shape相同,否则抛异常)。
>>> 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]], dtype=bool)
>>> (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]], dtype=bool)
>>> a[(a>2)&(a<=4)]
array([3, 4])
>>> a[(a>2)&((a<=4))] += 10
>>> a
array([[ 0, 1, 2],
[13, 14, 5]])
10、数组方法和常用函数
数组对象本身提供了计算算术平均数、求最小值等内置方法,而numpy也提供了很多有用的函数。为了减少篇幅,下面的代码只以一维数组为例来展示这些方法和函数的用法。事实上,这些方法和函数中的大多数对于多维数组同样适用,只有少数例外,例如 compress 函数。
>>> 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.66666666666666663
>>> a.std() # 计算标准差(方差的算术平方根)
0.81649658092772603
>>> a.ptp() # 返回数组的值和最小值之差
2
>>> a.argmin() # 返回最小值在扁平数组中的索引
1
>>> a.argmax() # 返回值在扁平数组中的索引
2
>>> np.where(a == 2) # 返回所有值为2的元素的索引
(array([1]),)
>>> 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 ])
二、矩阵对象
matrix是一个矩阵对象,继承自ndarray类型,所以包含了ndarray的所有数据属性和方法。但是,将矩阵对象作为数组进行操作时,需要注意以下几点:
矩阵对象永远是二维的,即使是展平(ravel函数)操作或者成员选择,返回值也是二维的
matrix对象和ndarray对象混合的运算总是返回matrix对象
1、创建矩阵
矩阵对象可以创建为 Matlab 样式的字符串(以空格分隔的列和以分号分隔的行)或作为数组。
>>> np.mat('1 4 7; 2 5 8; 3 6 9')
matrix([[1, 4, 7],
[2, 5, 8],
[3, 6, 9]])
>>> np.mat(np.arange(1,10).reshape(3,3))
matrix([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
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([[ -4.50359963e+15, 9.00719925e+15, -4.50359963e+15],
[ 9.00719925e+15, -1.80143985e+16, 9.00719925e+15],
[ -4.50359963e+15, 9.00719925e+15, -4.50359963e+15]])
>>> m.A # 返回自身数据的二维数组的一个视图
array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
3、矩阵乘法
对于 ndarray 对象,星号按元素相乘,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]])
三、线性代数模块
numpy.linalg是numpy的线性代数模块,可以用来求解逆矩阵、特征值、线性方程、行列式等问题。
1、计算逆矩阵
虽然矩阵对象本身具有逆矩阵的属性,但是使用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.]])
2、计算行列式
我不记得如何计算行列式,但我仍然记得手动计算行列式的痛苦。现在好了,你可以在手机上用numpy轻松搞定(前提是你手机上安装了python + numpy)。
m = np.mat('0 1 2; 1 0 3; 4 -3 8')
np.linalg.det(m) # 什么?这就成了?
2.0
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]]))
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)
array([ 29., 16., 3.]) # x = 29, y = 16, z = 3
python学习网,大量的免费
,欢迎在线学习!
1、
2、
本文为原创文章,版权归知行编程网所有,欢迎分享本文,转载请保留出处!
你可能也喜欢
- ♥ python交换两个变量的值10/01
- ♥ 在 python 中 import os 是什么意思?08/16
- ♥ python中的isinstance函数判断各类小细节10/25
- ♥ python如何加载文件路径01/02
- ♥ Python replace() 函数:替换字符串中的一个字符10/14
- ♥ 如何在python中反转字符串11/23
内容反馈