矩阵操作函数库(Numpy)
Numpy的安装
pip install numpy
验证安装。
from numpy import *
使用随机命令random.rand(4,4)生成一个4乘4矩阵。
生成随机矩阵
Numpy的基本使用
标准安装的Python中用列表(list)保存的一组值,可以用来当作数组使用,但是由于列表的元素可以是任何对象,因此列表中所保存的是对象的指针。这样为了保存一个简单的[1,2,3],需要有3个指针和3个整数对象。对于数值运算来说,这样结构显然比较浪费内存和CPU的计算时间。
此外,Python还提供了一个array模块。array对象和列表不同,它直接保存数值,和C语言的一维数组比较类似。但是由于它不支持多维,也没有各种运算函数,因此也不适合做数值运算。
Numpy的诞生弥补了这些不足,Numpy提供了两种基本的对象:ndarray(N-dimensional array object),存储单一数据类型的多维数组;ufunc(universal function object),能够对数组进行处理的函数。
函数的导入
在使用Numpy之前,首先必须导入该函数库,导入方式如下:
import numpy as np
数组的创建
需要创建数组才能对其进行其他操作。可以通过给array函数传递Python的序列对象创建数组,如果传递的是多层嵌套的序列,将创建多维数组。
例如,下面分别创建一维和二维数组。
a = np.array([1,2,3,4])
b = np.array((5,6,7,8))
c = np.array([[1,2,3,4], [4,5,6,7], [7,8,9,10]])
数组的大小可以通过其shape属性获得。
例如,要获得上面数组a、b、c的大小,可以使用下面的代码。
a.shape
显示结果为(4,),这表示四行一列。
c.shape
显示结果为(3,4),这表示这个数组是三行四列。
数组a的shape只有一个元素,因此它是一位数组。而数组c的shape有两个元素,因此它是二维数组,其中第0轴的长度为3,第1轴的长度为4。
可以通过修改数组的shape属性,在保持数组元素个数不变的情况下,改变数组每个轴的长度。
下面的例子将数组c的shape改为(4,3)。注意:从(3,4)改为(4,3)并不是对数组进行转置,而只是改变每个轴的大小,数组元素在内存中的位置并没有改变。
c.shape = 4,3
显示结果如下:
运行结果
当某个轴的元素为-1时,将根据数组元素的个数自动计算此轴的长度,因此下面的程序将数组c的shape改为了(2,6)。
c.shape = 2, -1
显示结果如下:
运行结果
此外,使用数组的reshape方法,可以创建一个改变了尺寸的新数组,原数组的shape保持不变。
d = a.reshape((2,2))
显示结果如下:
运行结果
在上面的代码中,数组a和d其实共享数据存储内存区域,因此修改其中任意一个数组的元素都会同时修改另外一个数组的内容。
数组的类型
数组的元素类型可以通过dtype属性获得。上面例子中的参数序列的元素都是整数,因此所创建的数组的元素类型也是整数,并且是32位的长整型。
例如,查看数组a的类型。
a.dtype
显示结果如下:
dtype('int32')
可以通过dtype参数在创建时执行元素类型。
e = np.array([[1,2,3,4], [4,5,6,7], [7,8,9,10]], dtype=np.float)
运行结果
可以发现,现在数组元素都是浮点数据。
数组的其他创建方式
Numpy提供了很多专门用来创建数组的函数。
(1)arange函数类似于Python的range函数,通过指定开始值、终值和步长来创建一维数组,注意数组不包括终值。例如:
f = np.arange(0, 1, 0.1)
显示结果如下:
运行结果
(2)linspace函数通过指定开始值、终值和元素个数来创建一维数组,可以通过endpoint关键字指定是否包括终值,默认设置包括终值。例如:
g = np.linspace(0, 1, 12)
运行结果
(3)logspace函数和linspace类似,但是它创建的是等比数列,下面的例子显示从1到100有10个元素的等比数列。
h = np.logspace(0,2,10)
显示结果如下:
运行结果
数组元素的存取
数组元素的存取方法和Python的标准方法相同。
例如,下面代码可以实现对数组元素的基本存取。
a = np.arange(10)
上面代码产生一维数组,元素为:
运行结果
下面代码访问不同的元素。
a[3:5]
a[5]
a[:5]
a[:-1]
运行结果
ufunc运算
ufunc是一种能对数组的每个元素进行操作的函数。Numpy内置的很多ufunc函数都是在C语言级别实现的,因此他们的计算速度非常快。
import time
import math
import numpy as np
x = [i * 0.001 for i in range(1000000)]
start = time.clock()
for i, t in enumerate(x):
x[i] = math.sin(t)
print("math.sin:", time.clock() - start)
x = [i * 0.001 for i in range(1000000)]
x = np.array(x)
start = time.clock()
np.sin(x, x)
print("numpy.sin:", time.clock() - start)
最后显示的运行时间分别为:
math.sin: 2.5434800000000006
numpy.sin: 0.11287300000000045
可以发现,numpy.sin比math.sin快的多。
矩阵的运算
Numpy和Matlab不一样,对于多维数组的运算,默认情况下并不使用矩阵运算,如果希望对数组进行矩阵运算,可以调用相应的函数。
Numpy库提供了matrix类,使用matrix类创建的是矩阵对象,它们的加、减、乘、除运算默认采用矩阵方式,因此其用法和Matlab十分相似。但是由于在Numpy中同时存在ndarray和matrix对象,因此用户很容易将两者弄混。这有违Python的“显式优于隐士”的原则,因此并不推荐在较复杂的程序中使用matrix。
矩阵的乘积可以使用dot函数计算。对于二维数组,它计算的是矩阵乘积,对于一维数组,它计算的是其点积。例如:
a = np.arange(12).reshape(4,3)
b = np.arange(12,24).reshape(3,4)
c = np.dot(a,b)
运行结果
矩阵中更高级的一些运算可以在Numpy的线性代数子库linalg中找到。例如,inv函数可以计算逆矩阵,solve函数可以求解多元一次方程组。下面是solve函数的例子。
a = np.random.rand(10,10)
b = np.random.rand(10)
x = np.linalg.solve(a,b)
np.sum(np.abs(np.dot(a,x) -b))
计算结果如下:
1.6209256159527285e-14
文件存取
Numpy提供了多种文件操作函数一方便用户存取数组内容。文件存取的格式分为两类:二进制和文本。而二进制格式的文件又分为Numpy专用的格式化二进制类型和无格式类型。
由于在数据处理中经常设计文本数据,因此可以使用numpy.savetxt和numpy.loadtxt可以读写一维和二维数组。例如:
a = np.arange(0,12,0.5).reshape(4, -1)
np.savetxt("a.txt", a)
np.loadtxt("a.txt")
运行结果:
array([[ 0. , 0.5, 1. , 1.5, 2. , 2.5],
[ 3. , 3.5, 4. , 4.5, 5. , 5.5],
[ 6. , 6.5, 7. , 7.5, 8. , 8.5],
[ 9. , 9.5, 10. , 10.5, 11. , 11.5]])
也可以改为整数保存数据。
np.savetxt("a.txt", a, fmt="%d", delimiter=",")
np.loadtxt("a.txt", delimiter=",")
现实结果如下:
array([[ 0., 0., 1., 1., 2., 2.],
[ 3., 3., 4., 4., 5., 5.],
[ 6., 6., 7., 7., 8., 8.],
[ 9., 9., 10., 10., 11., 11.]])