算术运算
对应元素相乘
简单的理解就是2个维度相同的Numpy数组,各个对应位置互相相乘得到的一个新的Numpy数组。图解如下:
将上面的图转换为代码如下所示:
import numpy as np A = np.array([[1, 2], [3, 4]]) B = np.array([[4, 5], [6, 7]]) print(A * B) print(np.multiply(A, B))
运行结果与上图一致,当然Numpy数组对应元素相乘有2种方式:一种直接通过“*”号进行运算,一种是通过multiply()函数进行运算,结果一样。
有时候我们在进行图像处理时,会对对应的像素进行乘积运算,但每个像素的变更运算是一样的,难道我们创建一个同样维度的数组进行运算吗?显然不划算。
假如,每个像素只是+2,或者*2,我们可以直接将Numpy数组加乘这个值即可。如下面代码所示:
A = np.array([[1, 2], [3, 4]]) print(A + 2) print(A * 2)
运算之后,效果如下:
点积运算
点积就是Dot Product,又称之为内积,也就是我们线性代数中常常用到的矩阵运算,在Numpy中的函数为:np.dot(),其具体定义如下所示:
np.dot(a,b,out=None)
运算的过程如下所示:
简单的理解点积就是第1行*第1列,对应元素乘完相加就是矩阵的第1个值。第1行*第2列,对应元素相乘得到第2个值,之后的以此类推。代码如下:
A = np.array([[1, 2], [3, 4]]) B = np.array([[4, 5], [6, 7]]) print(np.dot(A, B))
点积运算的2个数组必须行列数相等才能运算,不然无法进行点积运算。
数组变形
改变向量的维度
有过OpenGL开发经验的读者,应该都使用过改变向量的维度,这也是深度学习中常常需要的基础处理步骤。而Numpy改变维度的函数如下表所示:
函数 | 意义 |
nd.reshape | 将向量nd维度进行改变,不修改向量本身 |
nd.resize | 将向量nd维度进行改变,修改向量本身 |
nd.T | 将向量nd进行转置 |
nd.ravel | 将向量nd进行展平,即多维变一维,不会产生原向量的副本 |
nd.flatten | 将向量nd进行展平,即多维变一维,返回原数组的副本 |
nd.squeeze | 只能对一维数组进行降维,多维不会报错,但没有任何影响 |
nd.transpose | 对高维矩阵进行轴对换 |
示例代码如下所示:
# 改变向量维度 nd = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) print(nd.reshape(5, 2)) nd = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) print(nd.resize(5, 2)) # 行列对换 nd = np.arange(12).reshape(3, 4) print(nd.T) # 按照列优先展平,没有参数按照行优先展平 nd = np.array([[1, 2], [3, 4]]) print(nd.ravel('F'))
# 展平为一维 nd = np.array([[1, 2], [3, 4]]) print(nd.flatten()) # 将矩阵中含1的维度去掉 nd = np.arange(3).reshape(3, 1) print(nd) print(nd.squeeze()) # 矩阵轴对换 nd = np.arange(24).reshape(2, 3, 4) print(nd.shape) print(nd.transpose().shape)
比如transpose()函数,在RGB转GBR时就可以用到
合并数组
除了改变数组维度之外,我们还需要合并数组。比如在对股票进行处理的时候,需要将多个表格进行合并等。下面,也有一张合并函数的表格:
函数 | 意义 |
np.append | 内存占用大 |
np.concatenate | 没有内存问题 |
np.stack | 沿新轴加入一系列数组 |
np.hstack | 堆栈数组垂直顺序(行) |
np.vstack | 堆栈数组垂直顺序(列) |
np.dstack | 堆栈数组按顺序深入,作用于第3维 |
np.vsplit | 将数组分解成垂直的多个子数组的列表 |
其中,stack、hstack、dstack要求合并的数组具有相同的shape,也就是维度必须一模一样。
而append与concatenate操作的数组必须有相同的行数或者列数(满足一个即可)。
append、concatenate以及stack都有一个axis参数,控制数组的合并是按行还是列进行。
举例如下:
# append a = np.arange(4).reshape(2, 2) b = np.arange(4).reshape(2, 2) print(np.append(a, b, axis=0)) print(np.append(a, b, axis=1)) print("-------------") # concatenate a = np.array([[1, 2], [3, 4]]) b = np.array([[5, 6]]) print(np.concatenate((a, b), axis=0)) print(np.concatenate((a, b.T), axis=1)) print("-------------") # stack a = np.array([[1, 2], [3, 4]]) b = np.array([[5, 6], [7, 8]]) print(np.stack((a, b), axis=0))
运行之后,效果如下:
速度优势
在前面我们介绍time库时,就详细讲解了time也可以进行算法时间复杂度的测试。今天,我们就来测试一下,Numpy与普通运算哪个更快。
首先,我们计算100万以内每个数的sin值。常规的代码如下所示:
import numpy as np import time a = [i for i in range(1, 1000001)] start_time = time.perf_counter() for i, num in enumerate(a): a[i]=np.sin(num) print("执行的时长为:", time.perf_counter() - start_time)
然后我们进行Numpy计算的测试:
a = [i for i in range(1, 1000001)] start_time = time.perf_counter() a = np.sin(num) print("执行的时长为:", time.perf_counter() - start_time)
运行之后两者时间的对比如下:
可以看到numpy的速度比math快多了。而且如果是大量的点积运算,Numpy与普通的方式对比几乎能快400倍的速度。所以,在深度学习,科学计算等领域,Numpy具有绝对的优势。