最后一次更新日期: 2019/3/8
NumPy 是一个 Python 包。 它代表 “Numeric Python”。 它是一个由多维数组对象(ndarray)和用于处理数组的例程集合组成的库。
使用NumPy,开发人员可以执行以下操作:
- 数组的算数和逻辑运算。
- 傅立叶变换和用于图形操作的例程。
- 与线性代数有关的操作。 NumPy 拥有线性代数和随机数生成的内置函数。
使用前先导入模块:
import numpy as np
1. 矩阵类型
numpy提供了一个专用的矩阵对象matrix
,是基于 ndarray
作了进一步的封装得到的,能够更加快捷地进行一些矩阵相关的运算,但相比ndarray
没有性能上的优势且维数限制在二维,并不推荐使用。
(1). 创建
In [79]: m1=np.matrix([[1,2],[3,4]])
In [81]: m1
Out[81]:
matrix([[1, 2],
[3, 4]])
创建方式与ndarray
类似。
(2). 与 ndarray
的相互转换
In [82]: a=np.array([[5,6],[7,8]])
In [83]: m2=np.matrix([[5,6],[7,8]])
In [84]: np.asmatrix(a)
Out[84]:
matrix([[5, 6],
[7, 8]])
In [85]: np.matrix(a)
Out[85]:
matrix([[5, 6],
[7, 8]])
In [88]: np.asarray(m2)
Out[88]:
array([[5, 6],
[7, 8]])
In [89]: np.array(m2)
Out[89]:
array([[5, 6],
[7, 8]])
In [90]: m2.base
Out[90]:
array([[5, 6],
[7, 8]])
(3). 矩阵运算
In [94]: m1*m2
Out[94]:
matrix([[19, 22],
[43, 50]])
In [95]: m1.I
Out[95]:
matrix([[-2. , 1. ],
[ 1.5, -0.5]])
In [96]: m1.T
Out[96]:
matrix([[1, 3],
[2, 4]])
运算符*
用在matrix
上表示矩阵乘法,等效于np.dot(m1,m2)
,要实现元素相乘需要使用np.multiply(m1,m2)
。
matrix.T
表示转置矩阵,matrix.I
表示逆矩阵。
matrix
可以使用大部分ndarray
的方法,比如max
、sum
、sort
等。
2. 张量运算
张量是向量、矩阵这类概念的推广,标量是0阶张量,向量是1阶张量,矩阵是2阶张量。
numpy提供了广义的张量点积运算np.tensordot
。
In [2]: a=np.arange(1,9).reshape((2,2,2))
In [3]: b=np.arange(1,5).reshape((2,2))
In [4]: a
Out[4]:
array([[[1, 2],
[3, 4]],
[[5, 6],
[7, 8]]])
In [5]: b
Out[5]:
array([[1, 2],
[3, 4]])
In [8]: np.tensordot(a,b,axes=1)
Out[8]:
array([[[ 7, 10],
[15, 22]],
[[23, 34],
[31, 46]]])
In [9]: np.tensordot(a,b,axes=(-1,0))
Out[9]:
array([[[ 7, 10],
[15, 22]],
[[23, 34],
[31, 46]]])
In [10]: np.tensordot(a,b,axes=2)
Out[10]: array([30, 70])
In [12]: np.tensordot(a,b,axes=([-2,-1],[0,1]))
Out[12]: array([30, 70])
In [13]: np.dot(a,b)
Out[13]:
array([[[ 7, 10],
[15, 22]],
[[23, 34],
[31, 46]]])
In [14]: np.tensordot(a,b,axes=(-1,-2))
Out[14]:
array([[[ 7, 10],
[15, 22]],
[[23, 34],
[31, 46]]])
In [15]: np.inner(a,b)
Out[15]:
array([[[ 5, 11],
[11, 25]],
[[17, 39],
[23, 53]]])
In [16]: np.tensordot(a,b,axes=(-1,-1))
Out[16]:
array([[[ 5, 11],
[11, 25]],
[[17, 39],
[23, 53]]])
前两个参数a
和b
为参与运算的两个张量。
第三个参数axes
用于指定收缩的轴,完整格式形如([a_axis1,a_axis2,...],[b_axis1,b_axis2,...])
,两个序列分别指定a
和b
的轴,轴方向上的元素会按照被指定的顺序对应、相乘并相加;可使用(a_axis,b_axis)
的形式仅指定一个轴;
可使用int
类型快速指定a
中最后N个轴和b
中前N个轴用于收缩,即0
等效于([],[])
,对应张量积运算,1
等效于([-1],[0])
,对应张量内积运算,2
等效于([-2,-1],[0,1])
,对应张量双收缩运算,axes
的默认值为2
。
np.dot
、np.inner
这类运算可视作该函数表示的几个特例,np.dot(a1,a2)
等效于np.tensordot(a1,a2,axes=(-1,-2))
,np.inner(a1,a2)
等效于np.tensordot(a1,a2,axes=(-1,-1))
。
3. 傅里叶变换
(1) 频率序列
In [12]: np.fft.fftfreq(10,1.0)
Out[12]: array([ 0. , 0.1, 0.2, 0.3, 0.4, -0.5, -0.4, -0.3, -0.2, -0.1])
返回离散傅里叶变换采样频率,第一个参数n
为窗口长度,int
类型,第二个参数d
为采样间距(采样率的倒数),默认为1.0,返回值单位与采样间距单位相对应。
返回值序列的计算方式:
如果n
是偶数,f = [0, 1, ..., n/2-1, -n/2, ..., -1] / (d*n)
;
如果n
是奇数,f = [0, 1, ..., (n-1)/2, -(n-1)/2, ..., -1] / (d*n)
。
(2) 快速傅里叶变换
In [13]: x=np.cos(np.linspace(0,2*np.pi,30))
In [14]: y=np.fft.fft(x)
In [15]: x2=np.fft.ifft(y)
In [16]: np.abs(x2-x).max()
Out[16]: 3.8864883384594504e-16
np.fft
和np.ifft
互为逆运算,用于一维快速傅里叶变换,经np.fft
变换后的序列可通过np.ifft
近似还原为原序列。
第二个参数n
指定输出的变换轴长度,超长裁剪,不足补0;
第三个参数axis
指定用于变换的轴,默认最后一个轴。
(3) 移频
In [21]: x=np.linspace(0,2*np.pi,8)
In [22]: y=np.fft.fft(x)
In [23]: y2=np.fft.fftshift(y)
In [24]: y3=np.fft.ifftshift(y2)
In [32]: np.abs(y3-y).max()
Out[32]: 0.0
np.fftshift
和np.ifftshift
互为逆运算,用于将傅里叶变换输出中的直流分量移动到频谱的中央。第二个参数axis
可指定用于转移的轴。
4. 图像处理
图像数据的存储方式是类似于数组的,可借助PIL
库读取图片,再将图像数据转成ndarray
进行计算处理。
以下提供一些使用numpy
配合PIL
处理图片数据的方法:
(1) 图片的创建、读取、缩放、保存
In [2]: from PIL import Image
...: image1= Image.open("D:\\test.jpg")
In [3]: image1.size
Out[3]: (1015, 610)
In [4]: image2=image1.resize((500,300))
In [5]: image2.save("D:\\test2.jpg")
In [6]: image0=Image.new('RGB',image2.size)
In [7]: image2
Out[7]:
Image.open
用于打开一张图片,mode
可以设置读取模式,最常用的是'L'
灰度图和'RGB'
彩色图,一般会自动匹配不需要设置。
图片对象的resize
方法可以缩放图片,大小参数以tuple
类型(width,height)
格式传入。
图片对象的save
方法可以保存图片,通过保存路径中的文件拓展名或是format
参数指定保存文件类型,quality
参数可以设置保存图像的质量,取值1(最差)~ 95(最佳),默认75。
Image.new
用于创建一个新的图片,mode
参数指定模式,size
指定大小。
在IPython
中,直接输入图片变量名就可以显示图片。
(2) 图片与数组之间的转换
In [7]: a=np.asarray(image2)
In [8]: a.shape
Out[8]: (300, 500, 3)
In [9]: image3=Image.fromarray(a,'RGB')
np.asarray
或np.array
可以将图片转换为ndarray
,np.asarray
返回图片数据的ndarray
类型视图,不能更改。根据类型的不同,得到的数组形状也不一样,常见的两种,灰度图转换得到形状为(height,width)
的数组,彩色图转换得到形状为(height,width,channel)
的数组,channel
即颜色通道,RGB
模式下channel=3
,分别对应红绿蓝。
Image.fromarray
可以将ndarray
转换为图片,可通过mode
参数指定模式,默认会根据数组形状自动匹配,当指定某个模式时,数组形状也需要匹配。
注意,数组转图片需要是uint8
数据类型,取值0~255
,如不符合要进行另外的转换。
(3) 像素点绘制
In [10]: a0=np.array(image0)
In [11]: a0+=np.random.randint(0,256,a.shape,dtype='uint8')
In [12]: image4=Image.fromarray(a0)
In [13]: image4.putpixel((0,0),(255,255,255))
In [14]: image4
Out[14]:
图片对象的putpixel
方法可以添加单个像素点,第一个参数xy
以(x,y)
的形式声明添加像素点的位置,第二个参数value
指定像素点的值,例如,L
灰度图模式下为标量值,RGB
彩色图模式下为(r,g,b)
形式的tuple
,取值均在0~255
之间。该方法一次只能绘制一个像素点,效率低,在需要批量绘制时建议转换为ndarray
处理。
上面的示例中使用ndarray
的方法为新图片的每一个像素点添加了随机色彩。
(4) 灰度图和彩色图之间的转换
In [72]: a2=np.asarray(image2,dtype='float')
In [73]: a5=(11*a2[:,:,0]+16*a2[:,:,1]+5*a2[:,:,2])/32
In [74]: image5=Image.fromarray(np.uint8(a5))
In [75]: a6=a5.repeat(3).reshape(a5.shape+(3,))
In [76]: image6=Image.fromarray(np.uint8(a6))
In [77]: image5
Out[77]:
彩色图转灰度图,
L=11*R+16*G+5*B
只是一种可行的公式,也有其他公式可用。灰度图转彩色图,较为简单,即将灰度值拷贝到
RGB
3个通道上,转换后颜色还是灰色,因为灰度图不具备色彩方面的信息,即使先将彩色图转灰度图,再转换回彩色图,色彩信息同样会丢失。
(5) 图片的翻转、旋转、裁剪
In [84]:a2=np.asarray(image2)
In [85]:Image.fromarray(a2[::-1,::-1,:])
Out[85]:
In [90]:Image.fromarray(a2.transpose([1,0,2]))
Out[90]:
In [91]:Image.fromarray(a2[:150,:,:])
Out[91]:
以上示例展示了 左右翻转+上下翻转,左右翻转+逆时针转90°,截取上半部分 三种情况,借助倒序索引和轴交换的组合可以得到90°倍数旋转和上下左右翻转的所有组合情形。精确的旋转需要使用矩阵运算,此处不作展开。
网友评论