Numpy
是Python
的外部库,不在标准库中。因此,要使用它,需要先导入Numpy
。
import numpy as np
Numpy
封装了一个新的数据类型ndarry(N-dimensional Array)
,是一个多维数组对象。该对象封装了许多常用的数学运算函数,方便我们做数据处理。ndarray
的生成有多种方式,如从已有数据中创建,利用random
创建,创建特定形状的多维数组,利用arange
、linspace
函数生成等。
直接对python
的基础数据类型(如列表,元组等)进行转换来生成ndarray
。
ndarray
:lst1=[3.14,2.17,0,1,2]#使用元组一样适用
nd1=np.array(lst1)
print(nd1)
print(type(nd1))
[3.14 2.17 0. 1. 2. ]
ndarray
:lst2=[[3.14,2.17,0,1,2],[1,2,3,4,5]]#使用元组一样适用
nd2=np.array(lst2)
print(nd2)
print(type(nd2))
[[3.14 2.17 0. 1. 2. ]
[1. 2. 3. 4. 5. ]]
深度学习中,需要对一些参数进行初始化,有些初始化需要满足一定的条件,如满足正态分布或均匀分布,下面列举了np.random
模块常用的函数。
函数 | 描述 |
---|---|
np.random.random |
生成0到1之间的随机数 |
np.random.uniform |
生成均匀分布的随机数 |
np.random.randn |
生成标准正态的随机数 |
np.random.randint |
生成随机的整数 |
np.random.normal |
生成正态分布 |
np.random.shuffle |
随机打乱顺序 |
np.random.seed |
设置随机数种子 |
np.random.random_sample |
生成随机[0,1)的浮点数 |
nd3=np.random.random([3,3])#生成0到1之间的随机数
print(nd3)
[[0.46819442 0.59525306 0.76373578]
[0.43170894 0.38926815 0.36379689]
[0.56934243 0.76384178 0.08548735]]
为了每次生成同一份数据,可以指定一个随机种子,使用shuffle
函数可以打乱生成的随机数。
np.random.seed(123)
nd4=np.random.randn(2,3)
print(nd4)
np.random.shuffle(nd4)#随机打乱数据
print(nd4)
[[-1.0856306 0.99734545 0.2829785 ]
[-1.50629471 -0.57860025 1.65143654]]
[[-1.50629471 -0.57860025 1.65143654]
[-1.0856306 0.99734545 0.2829785 ]]
参数初始化时,需要生成一些特殊矩阵,如全为0或全为1的矩阵,可以利用一下函数来实现。
函数 | 描述 |
---|---|
np.zeros((3,4)) |
创建3×4的元素全为0的数组 |
np.ones((3,4)) |
创建3×4的元素全为1的数组 |
np.empty((2,3)) |
创建2×3的空数组,空数据中的值并不为0,而是未初始化的垃圾值 |
np.zero_like(ndarr) |
以ndarr相同维度创建元素全为0数组 |
np.ones_like(ndarr) |
以ndarr相同维度创建元素全为1数组 |
np.empty_like(ndarr) |
以ndarr相同维度创建空数组 |
np.eye(5) |
该函数用于创建一个5×5的矩阵,对角线为1,其余为0 |
np.full((3,5),666) |
创建3×5的元素全为666的数组,666为指定值 |
np.diag(array) |
array是一个1维数组时,结果形成一个以一维数组为对角线元素的矩阵,array是一个二维数组时,结果输出数组的对角线元素 |
生成全是0的3×3矩阵
nd5=np.zeros([3,3])
print(nd5)
[[0. 0. 0.]
[0. 0. 0.]
[0. 0. 0.]]
生成与nd5
形状一样的全0矩阵
np.zeros_like(nd5)
array([[0., 0., 0.],
[0., 0., 0.],
[0., 0., 0.]])
生成全是1的3×3矩阵
nd6=np.ones([3,3])
print(nd6)
[[1. 1. 1.]
[1. 1. 1.]
[1. 1. 1.]]
生成3阶的单位矩阵
nd7=np.eye(3)
print(nd7)
[[1. 0. 0.]
[0. 1. 0.]
[0. 0. 1.]]
生成3阶对角矩阵
a=[1,2,3]
print(a)
nd8=np.diag(a)
print(nd8)
b=[[1,2,3],[4,5,6],[7,8,9]]
print(b)
nd8=np.diag(b)
print(nd8)
[1, 2, 3]
[[1 0 0]
[0 2 0]
[0 0 3]]
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
[1 5 9]
还可以将数据暂存起来,以备后续使用
nd9=np.random.random([5,5])
np.savetxt(X=nd9,fname='test1.txt')
nd10=np.loadtxt('test1.txt')
print(nd10)
[[0.41092437 0.5796943 0.13995076 0.40101756 0.62731701]
[0.32415089 0.24475928 0.69475518 0.5939024 0.63179202]
[0.44025718 0.08372648 0.71233018 0.42786349 0.2977805 ]
[0.49208478 0.74029639 0.35772892 0.41720995 0.65472131]
[0.37380143 0.23451288 0.98799529 0.76599595 0.77700444]]
arange
、linspace
函数生成数组arange
是numpy
模板中的函数,其格式为:
arange([start,] stop[,step,], dtype=None)
其中start
与stop
用来指定范围,step
用来设定步长。start
默认为0,步长可谓小数。Python
中的range
与该函数功能类似。
print(np.arange(10))
print(np.arange(0,10))
print(np.arange(1,4,0.5))
print(np.arange(9,-1,-1))#倒序生成
[0 1 2 3 4 5 6 7 8 9]
[0 1 2 3 4 5 6 7 8 9]
[1. 1.5 2. 2.5 3. 3.5]
[9 8 7 6 5 4 3 2 1 0]
linspace
也是numpy
中常用的函数,其格式为:
np.linspace(start,stop,num=50,endpoint=True,retstep=False,dtype=None)
linspace
可根据输入的指定数据范围以及等份数量,自动生成一个线形等分向量,其中endpoint(包含终点)
默认为True
,等分数量num
默认为50。如果将retstep
设置为True
,则会返回一个带步长的ndarry
。
logspace
函数的用法与linspace
类似
print(np.linspace(0,1,10))
print(np.logspace(1,2,20))
[0. 0.11111111 0.22222222 0.33333333 0.44444444 0.55555556
0.66666667 0.77777778 0.88888889 1. ]
[ 10. 11.28837892 12.74274986 14.38449888 16.23776739
18.32980711 20.69138081 23.35721469 26.36650899 29.76351442
33.59818286 37.92690191 42.81332399 48.32930239 54.55594781
61.58482111 69.51927962 78.47599704 88.58667904 100. ]
在数据生成之后,需要读取生成的数据,下面介绍使用切片的方式获取数据。
首先生成10个随机数据。
np.random.seed(2019)
nd11=np.random.random([10])
nd11
array([0.90348221, 0.39308051, 0.62396996, 0.6378774 , 0.88049907,
0.29917202, 0.70219827, 0.90320616, 0.88138193, 0.4057498 ])
nd11[4]
0.8804990687782621
nd11[3:6]
array([0.6378774 , 0.88049907, 0.29917202])
nd11[1:6:2]
array([0.39308051, 0.6378774 , 0.29917202])
nd11[::-2]
array([0.4057498 , 0.90320616, 0.29917202, 0.6378774 , 0.39308051])
获取多维数组中的数据
nd12=np.arange(25).reshape([5,5])
nd12
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]])
nd12[1:3,1:3]
array([[ 6, 7],
[11, 12]])
nd12[(nd12>3)&(nd12<10)]
array([4, 5, 6, 7, 8, 9])
nd12[[1,2]]#或使用nd12[1:3,:]
array([[ 5, 6, 7, 8, 9],
[10, 11, 12, 13, 14]])
nd12[:,1:3]
array([[ 1, 2],
[ 6, 7],
[11, 12],
[16, 17],
[21, 22]])
获取数组中的部分元素除了可以使用切片的方式实现,还可以使用函数实现,如通过random.choice
函数从指定的样本中随机抽取数据。
首先创建一个数组
a=np.arange(1,25,dtype=float)
a
array([ 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13.,
14., 15., 16., 17., 18., 19., 20., 21., 22., 23., 24.])
size
参数指定输出数组形状c1=np.random.choice(a,size=(3,4))
c1
array([[19., 6., 24., 22.],
[21., 17., 16., 2.],
[23., 15., 13., 11.]])
replace
缺省为True
,即可重复抽取c2=np.random.choice(a,size=(3,4),replace=False)
c2
array([[ 5., 14., 23., 15.],
[ 8., 24., 6., 18.],
[13., 10., 21., 11.]])
c3=np.random.choice(a,size=(3,4),p=a/np.sum(a))
c3
array([[19., 21., 18., 11.],
[10., 21., 23., 19.],
[18., 19., 11., 20.]])
下面介绍逐元乘法,运算符为np.multiply()
或*。和点积或内积元素,运算符为np.dot()
对应元素相乘是两个矩阵中对应元素乘积。np.multipy
函数用于数组或矩阵对应元素相乘,输出与相乘数组或矩阵的大小一致。其格式如下
numpy.multiply(x1,x2,/,out=None,*,where=True,casting='same_kind',order='K',dtype=None,subok=True[,signature,extobj])
x1,x2之间的对应元素相乘遵守广播机制。
A=np.array([[1,2],[-1,4]])
B=np.array([[2,0],[3,4]])
print(A*B)
print(np.multiply(A,B))
[[ 2 0]
[-3 16]]
[[ 2 0]
[-3 16]]
Numpy
数组不仅可以和数组进行对应元素的相乘,还可以和单一数值进行运算。运算时,Numpy数组中的每个元素都和标量进行运算,其间会用到广播机制
print(A*2.0)
print(A/2.0)
[[ 2. 4.]
[-2. 8.]]
[[ 0.5 1. ]
[-0.5 2. ]]
点积运算又称为内积,在Numpy
用np.dot
表示,其一般格式为:
numpy.dot(a,b,out=None)
使用方法
X1=np.array([[1,2],[3,4]])
X2=np.array([[5,6,7],[8,9,10]])
X3=np.dot(X1,X2)
X3
array([[21, 24, 27],
[47, 54, 61]])
矩阵X1和矩阵X2进行点积运算,X1的第二个维度与X2的第一个维度的元素个数必须保持一致,矩阵X3的形状是由矩阵X1行数和矩阵X2的列数构成的。
在深度学习的任务中,通常需要将处理好的数据以模型能接收的格式输入给模型,然后由模型通过一系列的运算,最终返回一个处理结果。在矩阵或数组运算中,还需要把多个向量或矩阵按某轴方向合并或展平的情况,下面介绍常用的数据变形方法。
修改指定数组的形状是Numpy
中最常见的操作之一,下面列出了一些常用的函数。
函数 | 描述 |
---|---|
arr.reshape |
重新将向量arr维度进行改变,不修改向量本身 |
arr.resize |
重新将向量arr维度进行改变,修改向量本身 |
arr.T |
对向量arr进行转置 |
arr.ravel |
对向量arr进行展平,即将多维数组变成1维数组,不会产生原数组的副本 |
arr.flatten |
对向量arr进行展平,即将多维数组变成1维数组,返回原数组的副本 |
arr.squeeze |
只能对维数为1的维度降维。对多维数组使用时不会报错。但是不会产生任何影响 |
arr.transpose |
对高维矩阵进行轴对换 |
改变向量的维度(不修改向量本身)
arr=np.arange(10)
print(arr)
#将arr的维度变为2行5列
print('将arr的维度变为2行5列:')
print(arr.reshape(2,5))
#指定维度时可以只指定行数或者列数,其他用-1代替
print('...............分隔符......................')
print(arr.reshape(5,-1))
print(arr.reshape(-1,5))
[0 1 2 3 4 5 6 7 8 9]
将arr的维度变为2行5列:
[[0 1 2 3 4]
[5 6 7 8 9]]
...............分隔符......................
[[0 1]
[2 3]
[4 5]
[6 7]
[8 9]]
[[0 1 2 3 4]
[5 6 7 8 9]]
reshape
不支持指定行数或列数,所以-1
在这里是必须的。且所指定的行数或列数一定要能整除。以上是以二维数组为例,其他维数使用方法相同。
改变向量的维度(修改向量本身) 不能和reshape
方法一样使用-1
arr=np.arange(10)
print(arr)
#将向量arr维度变换为2行5列
arr.resize(5,2)
print('修改后,原向量改变:')
print(arr)
[0 1 2 3 4 5 6 7 8 9]
修改后,原向量改变:
[[0 1]
[2 3]
[4 5]
[6 7]
[8 9]]
向量转置,不改变原来的向量。
#向量为3行4列
arr=np.arange(12).reshape(3,4)
print('原向量为3行4列:')
print(arr)
print('将向量进行转置,转置后为4行3列')
print(arr.T)
原向量为3行4列:
[[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]]
将向量进行转置,转置后为4行3列
[[ 0 4 8]
[ 1 5 9]
[ 2 6 10]
[ 3 7 11]]
向量展平,不改变原来的向量。
arr=np.arange(6).reshape(2,-1)
print(arr)
#按照列优先,展平
print('按照列优先,展平')
print(arr.ravel('F'))
#按照行优先,展平
print('按照行优先,展平')
print(arr.ravel())
[[0 1 2]
[3 4 5]]
按照列优先,展平
[0 3 1 4 2 5]
按照行优先,展平
[0 1 2 3 4 5]
把矩阵转换为向量,不改变原来向量。这种需求经常出现在卷积神经网络与全连接层之间。
a=np.floor(10*np.random.random((3,4)))
print(a)
print('展平后')
print(a.flatten())
[[6. 7. 0. 6.]
[1. 2. 9. 4.]
[5. 0. 2. 6.]]
展平后
[6. 7. 0. 6. 1. 2. 9. 4. 5. 0. 2. 6.]
该函数主要用来降维,把矩阵中含1的维度去掉,不改变原来的向量。
arr=np.arange(3).reshape(3,1)
#原向量形状
print('原向量形状:')
print(arr.shape)
#降维后
print('降维后:')
print(arr.squeeze().shape)
arr1=np.arange(6).reshape(3,1,2,1)
print('原向量形状:')
print(arr1.shape)
print('降维后:')
print(arr1.squeeze().shape)
原向量形状:
(3, 1)
降维后:
(3,)
原向量形状:
(3, 1, 2, 1)
降维后:
(3, 2)
对高维矩阵进行轴对换,在深度学习中经常使用,比如把图片中表示颜色顺序的RGB转为GBR。其参数代表维度的顺序。不改变原向量
arr2=np.arange(24).reshape(2,3,4)
print('原向量形状')
print(arr2.shape)
print(arr2.transpose(1,2,0).shape)
原向量形状
(2, 3, 4)
(3, 4, 2)
合并数组是常见的操作之一,下面列举了常见的用于数组或向量合并的方法。
函数 | 描述 |
---|---|
np.append |
内存占用大 |
np.concatenate |
没有内存问题 |
np.stack |
沿着新的轴加入一系列数组 |
np.hstack |
堆栈数组垂直顺序(行) |
np.vstack |
堆栈数组垂直顺序(列) |
np.dstack |
堆栈数组按顺序深入(沿第3维) |
np.vsplit |
将数组分解成垂直的多个子数组的列表 |
append
、concatenate
以及stack
都有一个axis
参数,用于控制数组的合并方式是按行还是按列。append
和concatenate
,待合并的数组必须有相同的列数或者行数(满足一个即可)。stack
、hstack
、dstack
,要求待合并的数组必须具有相同的形状(shape)合并一维数组:
a=np.array([1,2,3])
b=np.array([4,5,6])
c=np.append(a,b)
print(c)
[1 2 3 4 5 6]
合并多维数组
a=np.arange(4).reshape(2,2)
b=np.arange(4).reshape(2,2)
#按行合并
c=np.append(a,b,axis=0)
print('按行合并后的结果:')
print(c)
print('合并后的数据维度',c.shape)
#按列合并
d=np.append(a,b,axis=1)
print('按列合并后的结果:')
print(d)
print('合并后数据维度',d.shape)
按行合并后的结果:
[[0 1]
[2 3]
[0 1]
[2 3]]
合并后的数据维度 (4, 2)
按列合并后的结果:
[[0 1 0 1]
[2 3 2 3]]
合并后数据维度 (2, 4)
沿指定轴连接数组或者矩阵
a=np.array([[1,2],[3,4]])
b=np.array([[5,6]])
c=np.concatenate((a,b),axis=0)
print(c)
d=np.concatenate((a,b.T),axis=1)
print(d)
[[1 2]
[3 4]
[5 6]]
[[1 2 5]
[3 4 6]]
沿指定轴堆叠数组或者矩阵
a=np.array([[1,2],[3,4]])
b=np.array([[5,6],[7,8]])
print('按行:')
print(np.stack((a,b),axis=0))
print('按列:')
print(np.stack((a,b),axis=1))
按行:
[[[1 2]
[3 4]]
[[5 6]
[7 8]]]
按列:
[[[1 2]
[5 6]]
[[3 4]
[7 8]]]
Numpy
提供了两种基本的对象,即ndarray
和ufunc
对象。前文已经介绍了ndarray
,下面介绍Numpy
的另一个对象通用函数(ufunc),它是一种能对数组的每个元素进行操作的函数。计算速度非常快,利用矩阵或者向量可以避免使用循环语句。下列是几个常用的通用函数。
函数 | 描述 |
---|---|
sqrt |
计算序列化数据的平方根 |
sin,cos |
三角函数 |
abs |
计算序列化数据的绝对值 |
dot |
矩阵运算 |
log,log10,log2 |
对数函数 |
exp |
指数函数 |
cumsum,cumproduct |
累计求和,求积 |
sum |
对一个序列化数据进行求和 |
mean |
计算均值 |
median |
计算中位数 |
std |
计算标准差 |
var |
计算方差 |
corrcoef |
计算相关系数 |
math
与numpy
函数的性能比较import time
import math
import numpy as np
#创建一个大小为1000000数组
x=[i*0.001 for i in np.arange(1000000)]
#计时开始
start=time.clock()
#使用循环对x中的每个数据求sin值
for i,t in enumerate(x):
x[i]=math.sin(t)
#计算所使用的的时间
print("math.sin:",time.clock()-start)
#创建一个大小为1000000数组
x=[i*0.001 for i in np.arange(1000000)]
#转为ndarray数据类型
x=np.array(x)
start=time.clock()
#使用numpy通用函数进行计算
np.sin(x)
print("numpy.sin:",time.clock()-start)
D:\environment\Anaconda3\envs\pytorchGpuEnv\lib\site-packages\ipykernel_launcher.py:8: DeprecationWarning: time.clock has been deprecated in Python 3.3 and will be removed from Python 3.8: use time.perf_counter or time.process_time instead
D:\environment\Anaconda3\envs\pytorchGpuEnv\lib\site-packages\ipykernel_launcher.py:13: DeprecationWarning: time.clock has been deprecated in Python 3.3 and will be removed from Python 3.8: use time.perf_counter or time.process_time instead
del sys.path[0]
math.sin: 0.41290119999757735
numpy.sin: 0.011343300000589807
D:\environment\Anaconda3\envs\pytorchGpuEnv\lib\site-packages\ipykernel_launcher.py:19: DeprecationWarning: time.clock has been deprecated in Python 3.3 and will be removed from Python 3.8: use time.perf_counter or time.process_time instead
D:\environment\Anaconda3\envs\pytorchGpuEnv\lib\site-packages\ipykernel_launcher.py:22: DeprecationWarning: time.clock has been deprecated in Python 3.3 and will be removed from Python 3.8: use time.perf_counter or time.process_time instead
充分使用python的Numpy库中的内建函数,实现计算的向量化,可以大大提高速度。如果使用GPU,其性能将更强大,Numpy不支持GPU,pytroch支持GPU。
import time
import numpy as np
x1=np.random.rand(1000000)
x2=np.random.rand(1000000)
#使用循环计算向量点积
tic=time.process_time()
dot=0
for i in range(len(x1)):
dot+=x1[i]*x2[i]
toc=time.process_time()
print("dot = "+str(dot) +"\n for loop ---- Computation time = "+str(1000*(toc-tic))+"ms")
#使用numpy求函数点积
tic=time.process_time()
dot=0
dot=np.dot(x1,x2)
toc=time.process_time()
print("dot = "+str(dot) +"\n verctor version ---- Computation time = "+str(1000*(toc-tic))+"ms")
dot = 250442.85544558725
for loop ---- Computation time = 656.25ms
dot = 250442.8554455913
verctor version ---- Computation time = 0.0ms
Numpy中有些计算中要求数组的shape是一致的,当数组的shape不相等时,则会使用广播机制。在进行广播机制的时候,满足以下的规则。
a: 2×3×2 b: 3×2
则b向a看齐,在b的前面加1,变为:1×3×2
下面的图代表广播的过程。
代码实现:
import numpy as np
#生成一个行向量和一个列向量
A=np.arange(0,40,10).reshape(4,1)
B=np.arange(0,3)
print("A矩阵的形状:{},B矩阵的形状:{}".format(A.shape,B.shape))
#将A,B相加
C=A+B
print("C矩阵的形状:{}".format(C.shape))
print(C)
A矩阵的形状:(4, 1),B矩阵的形状:(3,)
C矩阵的形状:(4, 3)
[[ 0 1 2]
[10 11 12]
[20 21 22]
[30 31 32]]