Chapter1 Numpy基础

目录

  • 1、生成Numpy数组
    • 1.1、从已有数据中创建数组
    • 1.2、利用random模块生成数组
    • 1.3、创建特定形状的多维数组
    • 1.4、使用`arange`、`linspace`函数生成数组
  • 2、获取元素(切片)
  • 3、Numpy算术运算
    • 3.1、对应元素相乘
    • 3.2、点积运算
  • 4、数组变形
    • 4.1、更改数组的形状
    • 4.2合并数组
  • 5、通用函数
  • 6、广播机制

1、生成Numpy数组

NumpyPython的外部库,不在标准库中。因此,要使用它,需要先导入Numpy

import numpy as np

Numpy封装了一个新的数据类型ndarry(N-dimensional Array),是一个多维数组对象。该对象封装了许多常用的数学运算函数,方便我们做数据处理。ndarray的生成有多种方式,如从已有数据中创建,利用random创建,创建特定形状的多维数组,利用arangelinspace函数生成等。

1.1、从已有数据中创建数组

直接对python的基础数据类型(如列表,元组等)进行转换来生成ndarray

  1. 将列表转换成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.  ]

  1. 嵌套列表可以转换成多维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.  ]]

1.2、利用random模块生成数组

深度学习中,需要对一些参数进行初始化,有些初始化需要满足一定的条件,如满足正态分布或均匀分布,下面列举了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 ]]

1.3、创建特定形状的多维数组

参数初始化时,需要生成一些特殊矩阵,如全为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]]

1.4、使用arangelinspace函数生成数组

arangenumpy模板中的函数,其格式为:

arange([start,] stop[,step,], dtype=None)

其中startstop用来指定范围,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.        ]

2、获取元素(切片)

在数据生成之后,需要读取生成的数据,下面介绍使用切片的方式获取数据。

首先生成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 ])
  1. 获取指定位置的数据,获取第四个数据。
nd11[4]
0.8804990687782621
  1. 截取一段数据
nd11[3:6]
array([0.6378774 , 0.88049907, 0.29917202])
  1. 截取固定间隔数据
nd11[1:6:2]
array([0.39308051, 0.6378774 , 0.29917202])
  1. 倒序取数
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]])
  1. 截取多维数组中一个区域内数据
nd12[1:3,1:3]
array([[ 6,  7],
       [11, 12]])
  1. 截取一个多维数组,数值在一个值域之内的数据
nd12[(nd12>3)&(nd12<10)]
array([4, 5, 6, 7, 8, 9])
  1. 截取数组中指定行,如读取2,3行
nd12[[1,2]]#或使用nd12[1:3,:]
array([[ 5,  6,  7,  8,  9],
       [10, 11, 12, 13, 14]])
  1. 截取数组中指定列
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.])
  1. 使用size参数指定输出数组形状
c1=np.random.choice(a,size=(3,4))
c1
array([[19.,  6., 24., 22.],
       [21., 17., 16.,  2.],
       [23., 15., 13., 11.]])
  1. 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.]])
  1. 参数p指定每个元素对应的抽取概率,缺省为每个元素被抽取的概率相同。
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.]])

3、Numpy算术运算

下面介绍逐元乘法,运算符为np.multiply()或*。和点积或内积元素,运算符为np.dot()

3.1、对应元素相乘

对应元素相乘是两个矩阵中对应元素乘积。np.multipy函数用于数组或矩阵对应元素相乘,输出与相乘数组或矩阵的大小一致。其格式如下

numpy.multiply(x1,x2,/,out=None,*,where=True,casting='same_kind',order='K',dtype=None,subok=True[,signature,extobj])

Chapter1 Numpy基础_第1张图片

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. ]]

3.2、点积运算

点积运算又称为内积,在Numpynp.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]])

Chapter1 Numpy基础_第2张图片

矩阵X1和矩阵X2进行点积运算,X1的第二个维度与X2的第一个维度的元素个数必须保持一致,矩阵X3的形状是由矩阵X1行数和矩阵X2的列数构成的。

4、数组变形

在深度学习的任务中,通常需要将处理好的数据以模型能接收的格式输入给模型,然后由模型通过一系列的运算,最终返回一个处理结果。在矩阵或数组运算中,还需要把多个向量或矩阵按某轴方向合并或展平的情况,下面介绍常用的数据变形方法。

4.1、更改数组的形状

修改指定数组的形状是Numpy中最常见的操作之一,下面列出了一些常用的函数。

函数 描述
arr.reshape 重新将向量arr维度进行改变,不修改向量本身
arr.resize 重新将向量arr维度进行改变,修改向量本身
arr.T 对向量arr进行转置
arr.ravel 对向量arr进行展平,即将多维数组变成1维数组,不会产生原数组的副本
arr.flatten 对向量arr进行展平,即将多维数组变成1维数组,返回原数组的副本
arr.squeeze 只能对维数为1的维度降维。对多维数组使用时不会报错。但是不会产生任何影响
arr.transpose 对高维矩阵进行轴对换
  1. reshape

改变向量的维度(不修改向量本身)

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在这里是必须的。且所指定的行数或列数一定要能整除。以上是以二维数组为例,其他维数使用方法相同。

  1. resize

改变向量的维度(修改向量本身) 不能和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]]
  1. T

向量转置,不改变原来的向量。

#向量为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]]
  1. revel

向量展平,不改变原来的向量。

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]
  1. flatten

把矩阵转换为向量,不改变原来向量。这种需求经常出现在卷积神经网络与全连接层之间。

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. squeeze

该函数主要用来降维,把矩阵中含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)
  1. transpose

对高维矩阵进行轴对换,在深度学习中经常使用,比如把图片中表示颜色顺序的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)

4.2合并数组

合并数组是常见的操作之一,下面列举了常见的用于数组或向量合并的方法。

函数 描述
np.append 内存占用大
np.concatenate 没有内存问题
np.stack 沿着新的轴加入一系列数组
np.hstack 堆栈数组垂直顺序(行)
np.vstack 堆栈数组垂直顺序(列)
np.dstack 堆栈数组按顺序深入(沿第3维)
np.vsplit 将数组分解成垂直的多个子数组的列表
  1. appendconcatenate以及stack都有一个axis参数,用于控制数组的合并方式是按行还是按列。
  2. 对于appendconcatenate,待合并的数组必须有相同的列数或者行数(满足一个即可)。
  3. stackhstackdstack,要求待合并的数组必须具有相同的形状(shape)
  1. append

合并一维数组:

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)
  1. concatenate

沿指定轴连接数组或者矩阵

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]]
  1. stack

沿指定轴堆叠数组或者矩阵

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]]]

5、通用函数

Numpy提供了两种基本的对象,即ndarrayufunc对象。前文已经介绍了ndarray,下面介绍Numpy的另一个对象通用函数(ufunc),它是一种能对数组的每个元素进行操作的函数。计算速度非常快,利用矩阵或者向量可以避免使用循环语句。下列是几个常用的通用函数。

函数 描述
sqrt 计算序列化数据的平方根
sin,cos 三角函数
abs 计算序列化数据的绝对值
dot 矩阵运算
log,log10,log2 对数函数
exp 指数函数
cumsum,cumproduct 累计求和,求积
sum 对一个序列化数据进行求和
mean 计算均值
median 计算中位数
std 计算标准差
var 计算方差
corrcoef 计算相关系数
  1. mathnumpy函数的性能比较
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
  1. 循环与向量运算的对比

充分使用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

6、广播机制

Numpy中有些计算中要求数组的shape是一致的,当数组的shape不相等时,则会使用广播机制。在进行广播机制的时候,满足以下的规则。

  1. 让所有输入的数组都向其中shape最长的数组看齐,不足的部分则通过在前面加1补齐,如:

a: 2×3×2 b: 3×2

则b向a看齐,在b的前面加1,变为:1×3×2

  1. 输出数组的shape是输入数组shape的各个轴上的最大值;
  2. 如果输入数组的某个轴和输出数组的对应轴的长度相同或者某个轴的长度为1时,这个数组能被用来计算,否则出错。
  3. 当输入数组的某个轴的长度为1时,沿着此轴运算时都用(或复制)此轴上的第一组值。

下面的图代表广播的过程。

Chapter1 Numpy基础_第3张图片

代码实现:

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]]

你可能感兴趣的:(深度学习-Pytorch,python)