NumPy介绍
NumPy(Numerical Python) 是 Python 语言的一个扩展程序库,支持大量的维度数组与矩阵运算,此外也针对数组运算提供大量的数学函数库。NumPy 是一个运行速度非常快的数学库,主要用于数组计算,包含:
- 一个强大的N维数组对象 ndarray
- 广播功能函数
- 整合 C/C++/Fortran 代码的工具
- 线性代数、傅里叶变换、随机数生成等功能
NumPy 通常与 SciPy(Scientific Python)和 Matplotlib(绘图库)一起使用, 这种组合广泛用于替代 MatLab,是一个强大的科学计算环境,有助于我们通过 Python 学习数据科学或者机器学习。
SciPy 是一个开源的 Python 算法库和数学工具包。
SciPy 包含的模块有最优化、线性代数、积分、插值、特殊函数、快速傅里叶变换、信号处理和图像处理、常微分方程求解和其他科学与工程中常用的计算。
Matplotlib 是 Python 编程语言及其数值数学扩展包 NumPy 的可视化操作界面。它为利用通用的图形用户界面工具包,如 Tkinter, wxPython, Qt 或 GTK+ 向应用程序嵌入式绘图提供了应用程序接口(API)。
Numpy官方教程网站 https://www.numpy.org.cn/。
ndarray数组
ndarray(全称The N-dimensional array)是存储着相同类型和大小的元素的多维数组。数组的维度和每个数组中的元素是由shape来决定的。数组中的元素类型是由dtype决定的。与其他python中的对象容器一样,ndarray中的内容可以由数组的下标来访问。
一、创建数组:
numpy.array(object, dtype = None, copy = True, order = None, subok = False, ndmin = 0)
举例如下:
import numpy as np
a = np.array([1, 2, 3], dtype='int') # Create a rank 1 array 创建数组, 确定元素类型
print(type(a)) # Prints "<class 'numpy.ndarray'>" 打印数组矩阵的类型
print(a.shape) # Prints "(3,)" 打印数组矩阵的维度
print(a[0], a[1], a[2]) # Prints "1 2 3"
a[0] = 5 # Change an element of the array
print(a) # Prints "[5, 2, 3]"
b = np.array([[1,2,3],[4,5,6]]) # Create a rank 2 array
print(b.shape) # Prints "(2, 3)"
print(b[0, 0], b[0, 1], b[1, 0]) # Prints "1 2 4"
特定的代码:
1、ndarray.T 矩阵转置
2、height,width = ndarray.shape 输出矩阵的行与列
3、ndarray[i,:] 取矩阵第i行的所有元素,结果是单行ndarray格式,拥有ndarray的所有属性(ndarray[:,j] 矩阵第j列的所有元素)
4、ndarray.max() ndarray.min() 矩阵中的最大值最小值
5、ndarray.all() 矩阵中是否所有值都为非零 ndarray.any() 矩阵中是否有一个值为非零
6、ndarray = np.append(ndarray, 12) 在矩阵中插入一个数据,如果不是一维数组则会变成一维数组
7、np.ones((m,n)) 生成m行,n列的全1矩阵
8、np.zeros((m,n)) 生成m行,n列的零矩阵
9、np.eye(n) 生成n维单位矩阵
10、np.random.randint(0,100,(m,n)) 生成m行,n列的随机矩阵,数值在0-100之间
11、np.arange(20) 将值20传递给arange
函数会创建一个值范围为0到19的一维数组numpy.
arange
([start, ]stop, [step, ]dtype=None) 这是numpy中arange函数的使用方法,np.arange(20)相当于是np.arange(0,20,1)。np.arange(2,42,2).reshape(4,5) 使其成为二维数组,使用reshape函数链接其输出
12、np.linspace(1,10,num=50) 在1到10之间等间隔生成50个数字
13、np.random.shuffle(np.arange(ndarray)) 随机打乱一个矩阵,np.random.shuffle(np.arange(10))输出如[1 7 5 2 9 4 3 6 0 8],注意这一操作没有返回值。shuffle为洗牌的意思,打乱一个矩阵
举例如下:(注意zeros,ones,full,random中需要有两个括号,第一个括号内部还可以设置dtype = 'int'等)
import numpy as np
a = np.zeros((2,2)) # Create an array of all zeros
print(a) # Prints "[[ 0. 0.]
# [ 0. 0.]]"
b = np.ones((1,2)) # Create an array of all ones
print(b) # Prints "[[ 1. 1.]]"
c = np.full((2,2), 7) # Create a constant array
print(c) # Prints "[[ 7. 7.]
# [ 7. 7.]]"
d = np.eye(2) # Create a 2x2 identity matrix
print(d) # Prints "[[ 1. 0.]
# [ 0. 1.]]"
e = np.random.random((2,2)) # Create an array filled with random values
print(e) # Might print "[[ 0.91940167 0.08143941]
# [ 0.68744134 0.87236687]]"
>>> np.arange(3)
array([0, 1, 2])
>>> np.arange(3.0)
array([ 0., 1., 2.])
>>> np.arange(3,7)
array([3, 4, 5, 6])
>>> np.arange(3,7,2)
array([3, 5])
二、数组索引
1、切片(Slicing)
与Python列表类似,可以对numpy数组进行切片。由于数组可能是多维的,因此必须为数组的每个维指定一个切片。切片后的矩阵与母体矩阵会产生对应关系的联系。
import numpy as np
# Create the following rank 2 array with shape (3, 4)
# [[ 1 2 3 4]
# [ 5 6 7 8]
# [ 9 10 11 12]]
a = np.array([[1,2,3,4], [5,6,7,8], [9,10,11,12]])
( 上语句相当于 a = np.arange(1,13,1).reshape(3,4) )
# Use slicing to pull out the subarray consisting of the first 2 rows
# and columns 1 and 2; b is the following array of shape (2, 2):
# [[2 3]
# [6 7]]
b = a[:2, 1:3]
# A slice of an array is a view into the same data, so modifying it
# will modify the original array.
print(a[0, 1]) # Prints "2"
b[0, 0] = 77 # b[0, 0] is the same piece of data as a[0, 1]
print(a[0, 1]) # Prints "77"
神经网络中多维数组降维(举例)
y = model.predict(x) # y为神经网络中预测的结果,维度为(1,24,64,7)
y_an = y # 将y赋值给y_an
y = np.squeeze(y, axis=0) # y的结果为(24,64,7),从数组的形状中删除单维度条目,即把shape中为1的维度去掉
y_an = y_an[0, :, :, :] # y_an的结果为(24,64,7)
y_an_0 = y_an[:, :, 0] # y_an的结果为(24,64)
2、整数数组索引
使用切片索引到numpy数组时,生成的数组视图将始终是原始数组的子数组。 相反,整数数组索引允许你使用另一个数组中的数据构造任意数组。以下是索引的例子
import numpy as np
a = np.array([[1,2], [3, 4], [5, 6]])
# An example of integer array indexing.
# The returned array will have shape (3,) and
print(a[[0, 1, 2], [0, 1, 0]]) # Prints "[1 4 5]"
# The above example of integer array indexing is equivalent to this:
print(np.array([a[0, 0], a[1, 1], a[2, 0]])) # Prints "[1 4 5]"
# When using integer array indexing, you can reuse the same
# element from the source array:
print(a[[0, 0], [1, 1]]) # Prints "[2 2]"
# Equivalent to the previous integer array indexing example
print(np.array([a[0, 1], a[0, 1]])) # Prints "[2 2]"
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]"
三、数组中的数学
与MATLAB不同,*
是元素乘法,而不是矩阵乘法。 我们使用dot
函数来计算向量的内积,将向量乘以矩阵,并乘以矩阵。 dot
既可以作为numpy模块中的函数,也可以作为数组对象的实例方法。
import numpy as np
x = np.array([[1,2],[3,4]], dtype=np.float64)
y = np.array([[5,6],[7,8]], dtype=np.float64)
# Elementwise sum; both produce the array
# [[ 6.0 8.0]
# [10.0 12.0]]
print(x + y)
print(np.add(x, y))
# Elementwise difference; both produce the array
# [[-4.0 -4.0]
# [-4.0 -4.0]]
print(x - y)
print(np.subtract(x, y))
# Elementwise product; both produce the array
# [[ 5.0 12.0]
# [21.0 32.0]]
print(x * y)
print(np.multiply(x, y))
# Elementwise division; both produce the array
# [[ 0.2 0.33333333]
# [ 0.42857143 0.5 ]]
print(x / y)
print(np.divide(x, y))
# Elementwise square root; produces the array
# [[ 1. 1.41421356]
# [ 1.73205081 2. ]]
print(np.sqrt(x))
x = np.array([[1,2],[3,4]])
y = np.array([[5,6],[7,8]])
v = np.array([9,10])
w = np.array([11, 12])
# Inner product of vectors; both produce 219
print(v.dot(w))
print(np.dot(v, w))
# Matrix / vector product; both produce the rank 1 array [29 67]
print(x.dot(v))
print(np.dot(x, v))
# Matrix / matrix product; both produce the rank 2 array
# [[19 22]
# [43 50]]
print(x.dot(y))
print(np.dot(x, y))
Numpy为在数组上执行计算提供了许多有用的函数;其中最有用的函数之一是 SUM。
import numpy as np
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]"
四、广播
广播是一种强大的机制,它允许numpy在执行算术运算时使用不同形状的数组。通常,我们有一个较小的数组和一个较大的数组,我们希望多次使用较小的数组来对较大的数组执行一些操作。
例如,假设我们要向矩阵的每一行添加一个常数向量。我们可以这样做:
import numpy as np
# We will add the vector v to each row of the matrix x,
# storing the result in the matrix 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) # Create an empty matrix with the same shape as x
# Add the vector v to each row of the matrix x with an explicit loop
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中计算显式循环可能会很慢。注意,向矩阵 x
的每一行添加向量 v
等同于通过垂直堆叠多个 v
副本来形成矩阵 vv
,然后执行元素的求和x
和 vv
。 我们可以像如下这样实现这种方法:
import numpy as np
# We will add the vector v to each row of the matrix x,
# storing the result in the matrix 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)) # Stack 4 copies of v on top of each other
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
# We will add the vector v to each row of the matrix x,
# storing the result in the matrix 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]]"
广播通常会使你的代码更简洁,效率更高,因此你应该尽可能地使用它。以下例子为利用广播功能变换图像的通道值。
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)"
# We can tint the image by scaling each of the color channels
# by a different scalar constant. The image has shape (400, 248, 3);
# we multiply it by the array [1, 0.95, 0.9] of shape (3,);
# numpy broadcasting means that this leaves the red channel unchanged,
# and multiplies the green and blue channels by 0.95 and 0.9
# respectively.
img_tinted = img * [1, 0.95, 0.9]
五、经典问题
1、 如何从一维数组中提取满足指定条件的元素?&& 如何将满足条件的数置换?
给定一个数组arr = np.array([0,1,2,3,4,5,6,7,8]),若要将这个数组中大于4的数取出。一般容易想到arr_select = arr>4,但此时得出的arr_select只是布尔类型的输出[false,false,false,false,false,true,true,true,true],需要这一布尔类型重新带入筛选,arr_select = arr[arr>4](注意是中括号)。可参照数组索引中的布尔索引。
例如arr中将大于4的数字全部置换为2,可以得出arr[arr>4]=2。
2、如何在不影响原始数组的情况下替换满足条件的元素项?(where)
1中主要介绍了如何替换数组中满足条件的元素,但是1中的替换影响了原始数组。若要arr = np.array([0,1,2,3,4,5,6,7,8])数组中奇数项置为-1,保存于另一个out数组中,但又不影响arr数组,方法是调用np.where。具体方法为out = np.where(arr%2!=0, -1, arr)。
3、 如何改变数组的形状?(reshape)
在生成数组中有提到过用reshape的方法可以改变数组的维度。例如由10个数组成的数组arr = np.array([0,1,2,3,4,5,6,7,8,9])要组成2*5的矩阵,out = arr.reshape(2,5)(也可以是out = arr.reshape(2,-1),只需输入行数,列数输入-1会自动进行预测)。
4、数组的垂直叠加和水平叠加
vstack中的v代表vertical水平,即vertical stack水平叠加的意思。对应垂直叠加为hstack。
r_代表rows水平方向叠加, c_代表cols垂直方向叠加。
a = np.arange(10).reshape(2,-1)
b = np.repeat(1, 10).reshape(2,-1)
# 垂直叠加[水平叠加]
# Method 1:
np.concatenate([a, b], axis=0) [ np.concatenate([a, b], axis=1) ]
# Method 2: vstack中的v代表vertical水平
np.vstack([a, b]) [ np.hstack([a, b]) ]
# Method 3: r_代表rows水平方向叠加, c_代表cols垂直方向叠加
np.r_[a, b] [ np.c_[a, b] ]
垂直叠加结果
# > array([[0, 1, 2, 3, 4],
# > [5, 6, 7, 8, 9],
# > [1, 1, 1, 1, 1],
# > [1, 1, 1, 1, 1]])
水平叠加结果
# > array([[0, 1, 2, 3, 4, 1, 1, 1, 1, 1],
# > [5, 6, 7, 8, 9, 1, 1, 1, 1, 1]])
5、repeat与tile方法的区别
repeat是重复,tile是平铺。当只有数组中只有一个元素时,两者的使用方法没有区别。
>>> b = np.array([1],dtype = np.float32)
>>> print(b)
[1.]
>>> print(np.tile(b,3))
[1. 1. 1.]
>>> print(np.repeat(b,3))
[1. 1. 1.]
当只有数组中大于一个元素时,两者的使用方法有区别。无论数组的维度为多少,repeat方法都转化为一维数组,然后重复每个数字;tile相当于是垂直的重复np.c_。
>>> a = np.array([1,2,3])
>>> print(a)
[1 2 3]
>>> print(np.repeat(a,3))
[1 1 1 2 2 2 3 3 3]
>>> print(np.tile(a,3))
[1 2 3 1 2 3 1 2 3]
>>> arr = np.arange(10).reshape(2,5)
>>> print(arr)
[[0 1 2 3 4]
[5 6 7 8 9]]
>>> print(np.repeat(arr,2))
[0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9]
>>> print(np.tile(arr,2))
[[0 1 2 3 4 0 1 2 3 4]
[5 6 7 8 9 5 6 7 8 9]]
>>> print(np.c_[arr,arr])
[[0 1 2 3 4 0 1 2 3 4]
[5 6 7 8 9 5 6 7 8 9]]
6、取出两个数组之间的公共项 && 从一个数组中删除在另外一个数组中的项
无论是取出数组的公共项还是从一个数组中删除另外一个数组中的项,最终结果都是变为一个一维数组。
np.intersect1d(a, b)
>>> b = np.array([7,2,10,2,7,4,9,4,9,8])
>>> a = np.arange(1,20,2).reshape(2,5)
>>> print(a)
[[ 1 3 5 7 9]
[11 13 15 17 19]]
>>> print(np.intersect1d(a,b))
[7 9]
np.setdiff1d(a, b)
a = np.array([1,2,3,4,5])
b = np.array([5,6,7,8,9])
# From 'a' remove all of 'b'
np.setdiff1d(a,b)
# > array([1, 2, 3, 4])
7、判断两个数组之间的相同元素的位置索引
np.where(a == b) 如果不同元素则 np.where(a != b)
a = np.array([1,2,3,2,3,4,3,4,5,6])
b = np.array([7,2,10,2,7,4,9,4,9,8])
np.where(a == b)
# > (array([1, 3, 5, 7]),)
8、交换数组的行与列 && 提取数组的行与列
通过[:, [x,x,x]]方法实现交换
>>> a = np.arange(9).reshape(3,3)
>>> print(a)
[[0 1 2]
[3 4 5]
[6 7 8]]
>>> print(a[:,[2,0,1]]) # 交换列
[[2 0 1]
[5 3 4]
[8 6 7]]
>>> print(a[[2,0,1],:]) # 交换行
[[6 7 8]
[0 1 2]
[3 4 5]]
>>> print(a[:,[2,0]]) # 提取指定列
[[2 0]
[5 3]
[8 6]]
9、如何创建包含5到10之间随机浮动的二维数组
# Solution Method 1:
rand_arr = np.random.randint(low=5, high=10, size=(5,3)) + np.random.random((5,3))
# np.random.randint中有low、high、size三个参数。默认high是None,如果只有low,那范围就是[0,low)。如果有high,范围就是[low,high)。
# Solution Method 2:
rand_arr = np.random.uniform(5,10, size=(5,3))
print(rand_arr)
# > [[ 8.50061025 9.10531502 6.85867783]
# > [ 9.76262069 9.87717411 7.13466701]
# > [ 7.48966403 8.33409158 6.16808631]
# > [ 7.75010551 9.94535696 5.27373226]
# > [ 8.0850361 5.56165518 7.31244004]]
10、判断两个numpy数组元素是否相同
判断numpy数组时,不能使用if语句。如a,b是两个数组,如果需要判断两数组之间的所有数值都是相等(a == b).all(),两个数组只要有一个相等即可(a == b).any()。
有关numpy教程:
【1】Numpy官方网站 https://www.numpy.org.cn/