第一章 Numpy数组与矩阵运算
文章目录
前言
扩展库numpy是Python支持科学计算的重要扩展库,是数据分析和科学计算领域如scipy、pandas、sklearn等众多扩展库中的必备扩展库之一,提供了强大的N维数组及其相关运算、复杂的广播函数、C/C++和Fortran代码集成工具以及线性代数、傅里叶变换和随机数生成等功能。本章重点介绍数组与矩阵及其相关运算,为学习和图像处理打下基础。一、Arrays是什么?
一个numpy数组是一个由不同数值组成的网格。网格中的数据都是同一种数据类型,可以通过非负整型数的元组来访问。维度的数量被称为数组的阶,数组的大小是一个由整型数构成的元组,可以描述数组不同维度上的大小。
二、numpy数组与常用操作
1.创建数组
代码如下(示例):
>>> import numpy as np
>>> np.array([1,2,3,4,5])#把列表转换为数组
array([1, 2, 3, 4, 5])
>>> np.array((1,2,3,4,5))#元组转换为数组
array([1, 2, 3, 4, 5])
>>> np.array([[1,2,3],[4,5,6]])
array([[1, 2, 3],
[4, 5, 6]])
>>> np.linspace(0,9,4)#等差数组
array([0., 3. ,6., 9.])
>>> np.zeros((3,3))#全0二维数组
array([[0., 0., 0.],
[0., 0., 0.],
[0., 0., 0.]])
>>> np.identity(3)#单位矩阵
array([[1., 0., 0.],
[0., 1., 0.],
[0., 0., 1.]])
>>> np.full((3,3),6)#全6数组
array([[6, 6, 6],
[6, 6, 6],
[6, 6, 6]])
>>> np.diag([1,2,3,4])#对角数组
array([[1, 0, 0, 0],
[0, 2, 0, 0],
[0, 0, 3, 0],
[0, 0, 0, 4]])
2.数据访问
用户可以使用下标和切片的形式来访问数组中的某个或多个元素代码如下(示例):
>>> a = np.array([[1,2,3,4], [5,6,7,8], [9,10,11,12]])
>>> print(a)
[[ 1 2 3 4]
[ 5 6 7 8]
[ 9 10 11 12]]
>>> a[0,2]#使用下标访问
3
>>> a[[0,2,1],[2,1,0]]#第一个列表表示行下标,第二个列表表示列下标
array([ 3, 10, 5])
>>> b = a[:2, 1:3]#前两行中列下标为1到3的元素
>>> print(b)
[[2 3]
[6 7]]
>>> a[::-1]#反向切片
array([[ 9, 10, 11, 12],
[ 5, 6, 7, 8],
[ 1, 2, 3, 4]])
>>> a[::2]#间隔2取元素
array([[ 1, 2, 3, 4],
[ 9, 10, 11, 12]])
>>> a[:5]#前五个元素
array([[ 1, 2, 3, 4],
[ 5, 6, 7, 8],
[ 9, 10, 11, 12]])
>>> c=np.arange(25)
>>> c.shape = 5,5 #修改数组形状
>>> c
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, 24]])
>>> c[0,2:5]#行下标为0列下标介于[2,5)之间的元素
array([2, 3, 4])
>>> c[1]
array([5, 6, 7, 8, 9])
>>> c[2:5,3:5]#行下标介于[2,5)之间,列下标介于[3,5]之间的元素值
array([[13, 14],
[18, 19],
[23, 24]])
>>> c[[1,3],[2,4]]#第2行和第3列的元素和第4行第5列的元素
array([ 7, 19])
>>> a = np.array([[1,2,3], [4,5,6], [7,8,9], [10, 11, 12]])
>>> print(a)
[[ 1 2 3]
[ 4 5 6]
[ 7 8 9]
[10 11 12]]
>>> b = np.array([0, 2, 0, 1])# Create an array of indices
>>> print(a[np.arange(4), b])# Select one element from each row of a using the indices in b
[ 1 6 7 11]
>>> a[np.arange(4), b] += 10# Mutate one element from each row of a using the indices in b
>>> print(a)
[[11 2 3]
[ 4 5 16]
[17 8 9]
[10 21 12]]
3. 数组布尔运算
import numpy as np
a = np.array([[1,2], [3, 4], [5, 6]])
bool_idx = (a > 2) # Find the elements of a that are bigger than 2;
# this returns a numpy array of Booleans of the same
# shape as a, where each slot of bool_idx tells
# whether that element of a is > 2.
print(bool_idx) # Prints "[[False False]
# [ True True]
# [ True True]]"
# We use boolean array indexing to construct a rank 1 array
# consisting of the elements of a corresponding to the True values
# of bool_idx
print(a[bool_idx]) # Prints "[3 4 5 6]"
# We can do all of the above in a single concise statement:
print(a[a > 2]) # Prints "[3 4 5 6]"
>>> np.all(a<25)
True
>>> np.any(a>5)
True
4.数组堆叠
堆叠数组是指沿着特定的方向把多个数组合并到一起,numpy的hstack()和vstack()函数分别用于实现多个数组的水平堆叠和垂直堆叠
>>> a = np.arange(5)
array([0, 1, 2, 3, 4])
>>> b = np.arange(5,10)
>>> b
array([5, 6, 7, 8, 9])
>>> np.hstack((a,b))#水平堆叠
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
>>> np.vstack((a,b))#垂直堆叠
array([[0, 1, 2, 3, 4],
[5, 6, 7, 8, 9]])
5.数组运算
数组内积
扩展库numpy提供了dot()函数用来计算两个数组的内积,也可以使用内置sum()函数来计算两个数组的内积,也就是矩阵乘法
>>> np.dot(a,b)
80
>>> sum(a*b)
80
数组求和
x = np.array([[1,2],[3,4]])
print np.sum(x) # Compute sum of all elements; prints "10"
print np.sum(x, axis=0) # Compute sum of each column; prints "[4 6]"
print np.sum(x, axis=1) # Compute sum of each row; prints "[3 7]"
6.广播
广播是一种强大的机制,允许numpy在执行算术运算时处理不同形状的数组。通常我们有一个更小的数组和一个更大的数组,我们希望多次使用较小的数组来对较大的数组执行一些操作。
例如,假设我们要向矩阵的每一行添加一个常数向量。 我们可以这样做:
import numpy as np
# 我们将向矩阵x的每一行添加向量v,将结果存储在矩阵y中,将结果存储在矩阵y中
x = np.array([[1,2,3], [4,5,6], [7,8,9], [10, 11, 12]])
v = np.array([1, 0, 1])
y = np.empty_like(x) #创建一个与x形状相同的空矩阵
# 用一个显式循环将向量v添加到矩阵x的每一行中
for i in range(4):
y[i, :] = x[i, :] + v
# Now y is the following
# [[ 2 2 4]
# [ 5 5 7]
# [ 8 8 10]
# [11 11 13]]
print(y)
这有效; 但是,当矩阵x很大时,在Python中计算显式循环可能会很慢。 请注意,将向量v添加到矩阵x的每一行等效于通过垂直堆叠v的多个副本,然后对x和vv进行逐元素求和来形成矩阵vv。 我们可以像这样实现这种方法:
import numpy as np
# 我们将把向量v加到矩阵x的每一行,将结果存储在矩阵y中
x = np.array([[1,2,3], [4,5,6], [7,8,9], [10, 11, 12]])
v = np.array([1, 0, 1])
vv = np.tile(v, (4, 1)) # 将v的4个副本堆叠在一起
print(vv) # Prints "[[1 0 1]
# [1 0 1]
# [1 0 1]
# [1 0 1]]"
y = x + vv # Add x and vv elementwise
print(y) # Prints "[[ 2 2 4
# [ 5 5 7]
# [ 8 8 10]
# [11 11 13]]"
Numpy广播使我们无需实际创建v的多个副本即可执行此计算。请考虑以下版本,使用广播:
import numpy as np
# 我们将向量v添加到矩阵x的每一行,将结果存储在矩阵y中
x = np.array([[1,2,3], [4,5,6], [7,8,9], [10, 11, 12]])
v = np.array([1, 0, 1])
y = x + v # Add v to each row of x using broadcasting
print(y) # Prints "[[ 2 2 4]
# [ 5 5 7]
# [ 8 8 10]
# [11 11 13]]"
广播两个数组遵循以下规则:
-
如果数组的秩不同,则将低秩数组的形状加1s,直到两个形状的长度相同。
-
如果两个数组的尺寸相同,或者其中一个数组的尺寸为1,则称这两个数组在尺寸上兼容。
-
如果阵列在所有维度上都兼容,则可以一起广播。
-
广播之后,每个数组的行为就好像它们的形状等于两个输入数组的形状的元素最大值一样。
-
在一个数组的大小为1而另一个数组的大小大于1的任何维度中,第一个数组的行为就像是沿着该维度复制的一样
import numpy as np
#计算向量的外积
v = np.array([1,2,3])#v的形状为(3,)
w = np.array([4,5])#w的形状为(2,)
#为了计算外积,我们首先将v整形为列
#形状的向量(3,1); 然后我们可以针对w广播它以产生
#形状(3,2)的输出,它是v和w的外积:
#[[4 5]
#[8 10]
#[12 15]]
print(np.reshape(v,(3,1))* w)
#向矩阵的每一行添加一个向量
x = np.array([[1,2,3],[4,5,6]])
#x的形状为(2,3),而v的形状为(3,),因此它们广播到(2,3),
#给出以下矩阵:
#[[2 4 6]
#[5 7 9]
print(x + v)
#向矩阵的每一列添加一个向量
#x的形状为(2,3),w的形状为(2,)。
#如果我们对x进行转置,则它的形状为(3,2)并且可以广播
#对w产生形状(3,2)的结果; 转置此结果
#产生形状(2,3)的最终结果,即矩阵x
#添加到每列的向量w。 给出以下矩阵:
#[[5 6 7]
#[9 10 11]]
print((x.T + w).T)
#另一个解决方案是将w重塑为形状为(2,1)的列向量;
#然后我们可以直接针对x广播它以产生相同的
#输出。
print(x + np.reshape(w,(2,1)))
#将矩阵乘以一个常数:
#x的形状为(2,3)。 Numpy将标量视为shape()的数组;
#这些可以一起广播以成形(2,3),产生
#以下数组:
#[[2 4 6]
#[8 10 12]]
print(x * 2)
三、矩阵生成与常用操作
1.矩阵生成
扩展库numpy中提供的matrix函数可以把列表、元组、range对象扽gpython可迭代对象转换为矩阵
import numpy as np
x = np.matrix([[1,2,3],[4,5,6]])
y = np.matrix([1,2,3,4,5,6])
#x[1,1]返回行下标和列下标都为1的元素
# 注意,对于矩阵x来说,x[1,1]和x[1][1]的含义不一样
print(x,y,x[1,1],sep='\n\n')
prints"
[[1 2 3]
[4 5 6]]
[[1 2 3 4 5 6]]
5"
2.矩阵转置
print(x.T,y.T,sep='\n')
[[1 4]
[2 5]
[3 6]]
[[1]
[2]
[3]
[4]
[5]
[6]]
3.查看矩阵特征
矩阵特征主要指矩阵最大值、最小值、元素求和、平均值等,扩展库numpy中的矩阵提供了相应的max()、min()、sum()、mean()等方法。在大部分的矩阵方法中都支持用参数axis来指定计算方向,axis=1表示横向计算,axis=0表示纵向计算
>>> x
matrix([[1, 2, 3],
[4, 5, 6]])
>>> print(x.mean())
3.5
>>> print(x.mean(axis=0))
[[2.5 3.5 4.5]]
>>> print(x.mean(axis=0).shape)#数组形状
(1, 3)
>>> print(x.mean(axis=1).shape)
(2, 1)
>>> print(x.mean(axis=1))
[[2.]
[5.]]
>>> print(x.sum())#所有元素和
21
>>> print(x.max(axis=1))#横向最大值
[[3]
[6]]
>>> print(x.argmax(axis=))#横向最大值的下标
SyntaxError: invalid syntax
>>> print(x.argmax(axis=1))#横向最大值的下标
[[2]
[2]]
>>> print(x.diagonal())#对角线元素
[[1 5]]
>>> print(x.nonzero())#非0元素下标
(array([0, 0, 0, 1, 1, 1], dtype=int64), array([0, 1, 2, 0, 1, 2], dtype=int64))
4.矩阵乘法
>>> x
matrix([[1, 2, 3],
[4, 5, 6]])
>>> y
matrix([[1, 2, 3, 4, 5, 6]])
>>> y = np.matrix([[1,2],[3,4],[5,6]])
>>> print(x*y)
[[22 28]
[49 64]]
四、Scipy库常见操作
Numpy提供了高性能的多维数组和基本工具,可以使用这些数组进行计算和操作。 SciPy以此为基础,并提供了可在numpy数组上运行的大量功能,可用于不同类型的科学和工程应用程序。
1.图像操作
SciPy提供了一些处理图像的基本功能。 例如,它具有从磁盘读取图像到numpy数组,将numpy数组作为图像写入磁盘以及调整图像大小的功能。 这是一个简单的示例,展示了这些功能:
from scipy.misc import imread, imsave, imresize
# Read an JPEG image into a numpy array
img = imread('assets/cat.jpg')
print(img.dtype, img.shape) # Prints "uint8 (400, 248, 3)"
# 我们可以通过用不同的标量常数缩放每个颜色通道来给图像着色。
#图像具有形状(400,248,3);我们将它乘以数组[1,0.95,0.9]的形状(3,);
#numpy广播意味着这将保持红色频道不变,并将绿色和蓝色频道分别乘以0.95和0.9。
img_tinted = img * [1, 0.95, 0.9]
# Resize the tinted image to be 300 by 300 pixels.
img_tinted = imresize(img_tinted, (300, 300))
# Write the tinted image back to disk
imsave('assets/cat_tinted.jpg', img_tinted)
总结
对numpy库和Scipy的常用操作进行了介绍