正文共: 5937 字 5 图

预计阅读时间: 15 分钟

Numpy_python

每日分享

You cannot protect yourself from sadness without protecting yourself from happiness.

稳不住幸福,亦躲不过悲伤。


Numpy_python_02


Numpy

1.简单了解Numpy

Numpy​是一个开源的Python科学计算库,用于快速处理任意维度的数组,支持常见的数组和矩阵操作。

使用Numpy需要先安装这个模块。

Numpy​使用 ​ndarray​对象来处理多维数组,而且 ​ndarray​中所有元素的类型都是相同的。我们先来看看怎么创建一个 ​ndarray​:

import numpy as npnp.array(列表)

注意:​本文中所使用的np都指 ​numpy

2.Numpy的优势

2.1内存块的分割

ndarray​在存储数据的时候,数据与数据的地址都是连续的,一体式存储使得批量操作数组元素的时候速度更快。而python中的列表元素类型是任意的,采用分离式存储,这样就使得list只能通过地址方式找到下一个元素。因此 ​numpy​的 ​ndarray​在科学计算中大放异彩。

2.2ndarray支持并行化运算(向量化运算)

2.3解除了GIL

numpy​底层使用了C语言编写,内部解除了GIL,其对数组的操作速度不受python解释器的限制,所以其效率远高于纯python代码。

3.N维数组-ndarray

3.1属性

ndarray.shape​代表的是数组维度的元组。

In [3]: np.array([[1,2,3],[4,5,6]]).shapeOut[3]: (2, 3)   # 二维数组

ndarray.ndim​代表的是数组维数。

In [4]: np.array([[1,2,3],[4,5,6]]).ndimOut[4]: 2

ndarray.size​代表的是数组中元素数量。

In [5]: np.array([[1,2,3],[4,5,6]]).sizeOut[5]: 6

ndarray.itemsize​代表的是一个数组元素的长度(字节)。

In [7]: np.array([[1,2,3],[4,5,6]]).itemsizeOut[7]: 8

ndarray.dtype​代表的是数组元素类型。

In [8]: np.array([[1,2,3],[4,5,6]]).dtypeOut[8]: dtype('int64')

3.2形状

数组分为一维数组、二位数组、三维数组到N维数组。一维数组类似是线性结构;二维数组则是有两个方向,可以简单的理解为咱们的表;三维数组则可以理解为多张表在另一个方向的叠加。N维数组无法比喻。

3.3类型

我们上面说过了, ​dtype​属性即元素类型,我们也知道 ​ndarray​中的元素类型一致,那么类型都有哪些呢?看下面表格:

名称

描述

简写

np.bool

用一个字节存储的布尔类型(True或False)

'b'

np.int8

一个字节大小,-128 至 127

'i'

np.int16

整数,-32768 至 32767

'i2'

np.int32

整数,-2^31 至 2^31 -1

'i4'

np.int64

整数,-2^63 至 2^63 - 1

'i8'

np.uint8

无符号整数,0 至 255

'u'

np.uint16

无符号整数,0 至 65535

'u2'

np.uint32

无符号整数,0 至 2^32 - 1

'u4'

np.uint64

无符号整数,0 至 2^64 - 1

'u8'

np.float16

半精度浮点数:16位,正负号1位,指数5位,精度10位

'f2'

np.float32

单精度浮点数:32位,正负号1位,指数8位,精度23位

'f4'

np.float64

双精度浮点数:64位,正负号1位,指数11位,精度52位

'f8'

np.complex64

复数,分别用两个32位浮点数表示实部和虚部

'c8'

np.complex128

复数,分别用两个64位浮点数表示实部和虚部

'c16'

np.object_

python对象

'O'

np.string_

字符串

'S'

np.unicode_

unicode类型

'U'

我们创建数组的时候可以指定类型:

In [17]: np.array(['python','ethanyan'],dtype=np.string_).dtypeOut[17]: dtype('S8')

注意​:如果不指定类型,整数默认是 ​int64​,小数默认是 ​float64​。

4.基本操作

4.1生成数组

4.1.1生成0和1的数组

np.zeros()
np.ones()
np.zeros_like()
np.ones_like()

以生成0的数组为例:

In [18]: np.zeros([3,4])Out[18]: array([[0., 0., 0., 0.],       [0., 0., 0., 0.],       [0., 0., 0., 0.]])In [19]: np.zeros_like([[1,2],[1,1]])Out[19]: array([[0, 0],       [0, 0]])

可以看到 ​zeros​中指定数组的形状维度,而 ​zeros_like​是传入一个数组,仿照其形状生成一个新的数组。

4.1.2从现有的数组中生成

a = np.array([[1,2,3],[4,5,6]])# 从现有的数组当中创建a1 = np.array(a)# 相当于索引的形式,并没有真正的创建一个新的a2 = np.asarray(a)

需要传入一个数组,然后生成一个一模一样的数组。 ​array​类似于深拷贝, ​asarray​则类似于浅拷贝。

4.1.3生成固定范围的数组

np.linspace(start,stop,num,endpoint)# start 序列的起始值# stop 序列的终止值,# num 要生成的等间隔样例数量,默认为50# endpoint 序列中是否包含stop值,默认为turenp.arange(start,stop, step, dtype)np.logspace(start,stop, num)

linspace​生成等间隔的数组,其中num指定的是生成的数组中有多少个样例。

In [21]: np.linspace(0,100,11)Out[21]: array([  0.,  10.,  20.,  30.,  40.,  50.,  60.,  70.,  80.,  90., 100.])

arange​生成固定间隔的数组,其中的step指的是间隔大小。

In [22]: np.arange(10,50,2)Out[22]: array([10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42,44, 46, 48])

logspace​生成的则是10的指数的数据。

In [23]: np.logspace(0,2,3)Out[23]: array([  1.,  10., 100.])

其中0,2代表的是从 ​10^0​到 ​10^2​也就是1到100。3指的是生成固定间隔的3个样例。

4.1.4生成随机数组

生成均匀分布数组:

np.random.uniform(low, high, size)# low: 采样下界,float类型,默认值为0;# high: 采样上界,float类型,默认值为1;# size: 输出样本数目,为int或元组(tuple)类型。缺省时输出1个值。# 返回值:ndarray类型,其形状和参数size中描述一致。例如,size=(m,n,k),仿照我们之前看到的维度的元组。

上面的功能是从一个均匀分布左开右闭的区间 ​[low,high)​中随机采样。

生成正态分布数据:

np.random.normal(loc=0.0, scale=1.0, size=None)# loc:float;此概率分布的均值(对应着整个分布的中心centre)# scale:float;此概率分布的标准差(对应于分布的宽度,scale越大越矮胖,scale越小,越瘦高)# size:int or tuple of ints;输出的shape,默认为None,只输出一个值

4.2数组的索引和切片

我们用一个难一点的例子来说明一下:

In [25]: a1 = np.array([ [[1,2,3],[4,5,6]], [[12,3,34],[5,6,7]]])In [26]: a1        Out[26]: array([[[ 1,  2,  3],        [ 4,  5,  6]],       [[12,  3, 34],        [ 5,  6,  7]]])In [27]: a1[0,0,1]Out[27]: 2

注意​:获取的时候先行后列,直接通过 ​[]​获取即可。

4.3形状修改

对象.reshape(shape)# shape代表的是要转换成的数组的形状# shape可以不指定行或者列,然后通过-1表示。最后的结果计算机自动计算,但是结果必须可以整除,不能来一个1.5行的数组。# 如:[-1,20]代表的是不知道多少行,但是生成20列。

注意​:没有进行行列互换,而是按顺序原先元素顺序重新分组,新产生了一个 ​ndarray​。

对象.resize()

注意​:没有进行行列互换,而且是在原来的 ​ndarray​上修改。

对象.T

注意​:进行了行列互换,而且产生了新的 ​ndarray​。

4.4类型修改

ndarray.astype(type)ndarray.tostring()ndarray.tobytes()

4.5数组去重

np.unique(ndarray)

例如:

In [28]: np.unique(np.array([[1, 2, 3, 4],[3, 4, 5, 6]]))    Out[28]: array([1, 2, 3, 4, 5, 6])

5.ndarray运算

5.1逻辑运算

可以直接通过大于号小于号进行运算,返回的是一个数组,其中符合条件的地方标记为True,不符合条件的地方标记为False。

5.2通用判断函数

判断所有元素是否符合条件,如果符合返回True,反之False。

np.all()

判断其中是否有满足条件的元素,有则返回True。

np.any()

5.3三元运算符

我们可以使用 ​where​来进行更加复杂的运算。比如我们判断股票的涨跌幅,数据为 ​temp​,大于0的置为1,否则为0。

np.where(temp > 0, 1, 0)

还可以进行更加复杂的判断。结合两个函数的使用。 ​np.logical_and​和 ​np.logical_or​代表的是与和或。

# 判断股票涨跌幅 大于0.5并且小于1的,换为1,否则为0np.where(np.logical_and(temp > 0.5, temp < 1), 1, 0)# 判断股票涨跌幅 大于0.5或者小于-0.5的,换为1,否则为0np.where(np.logical_or(temp > 0.5, temp < -0.5), 1, 0)

5.4统计运算

np.max()​是最大。​np.main()​是最小。​np.std​是标准差。​np.mean()​是平均值。​np.argmax()​是数组中最大值的位置。​np.argmin()​是数组中最小值的位置。

注意:在运算的函数里都有一个参数axis,其中0代表列,1代表行。

6.数组间的运算

6.1数组和数的运算

In [29]: arr = np.array([[1,2,3,2,1,4],[5,6,1,2,3,1]])In [30]: arr + 1Out[30]: array([[2, 3, 4, 3, 2, 5],       [6, 7, 2, 3, 4, 2]])In [31]: arr / 2Out[31]: array([[0.5, 1. , 1.5, 1. , 0.5, 2. ],       [2.5, 3. , 0.5, 1. , 1.5, 0.5]])

可以看到数组和数能进行计算,而且类似咱们线性代数中的矩阵运算。

6.2数组和数组运算

数组和数组之间的运算符合广播机制。那么什么是广播机制呢?

在进行矩阵运算的时候,我们都知道加法是行列相等的时候才可以进行,而且对应位置元素进行加法运算。进行乘法的时候,m×n 的矩阵乘以 n×1 的向量,得到的是 m×1 的向量。

在数组与数组进行运算的时候,如果两个数组形状不相等,我们可以通过扩展数组的方法来实现相加减等运算,这种机制就是广播机制。但是它也是有原则的人,并不是所有的数组都可以进行运算的。只有符合下面情况,才可以:

1.维度相同,其中有个对应的轴长为1。

给大家举个例子。比如有两个数组,他们的shape分别为(4,3)和(4,1)。或者shape分别为(3,5,6)和(3,1,6)。再或者(1,2,1)和(5,2,6)。他们都符合维度相同,在不同轴上,要么相同,要么对应的轴有一个为1。

2.维度不相同,后缘维度(从末尾开始算起的维度)的轴长相同。

同样举例子说明。两个数组分别为(256,256,3)和(3,),虽然维度不同,但是都从尾部开始算,后一个数组后缘维度的轴长为3,前一个数组也是如此,符合广播机制可以运算。再比如(12,5,2)和(5,2)。

3.前两条可以综合。如(9,1,7,1)和(8,1,5)也符合广播机制,可以运算。

9 x 1 x 7 x 1    8 x 1 x 5

6.3矩阵乘法

矩阵乘法有两个api,分别是:

np.matmul(a,b)  # a和b为两个数组np.dot(a,b)

我们先来演示一下:

In [35]: a = np.array([[80, 86],     ...: [82, 80],     ...: [85, 78],     ...: [90, 90],     ...: [86, 82],     ...: [82, 90],     ...: [78, 80],     ...: [92, 94]])In [36]: b = np.array([[0.7],[0.3]])In [37]: np.matmul(a,b)Out[37]: array([[81.8],       [81.4],       [82.9],       [90. ],       [84.8],       [84.4],       [78.6],       [92.6]])In [39]: np.dot(a,b)Out[39]: array([[81.8],       [81.4],       [82.9],       [90. ],       [84.8],       [84.4],       [78.6],       [92.6]])

可以看到两种方法在计算上面的例子时,结果一样。那么他们有区别吗?答案是肯定的。

区别​:

 ​np.matmul​中禁止矩阵与标量的乘法。 在矢量乘矢量的內积运算中, ​np.matmul​与 ​np.dot​没有区别。

6.4矩阵应用场景

大部分的机器学习算法都需要用到矩阵。当然也不难理解,算法嘛,为什么很多岗位招的是计算机或者数学,因为算法运用的都是数学知识,计算机像这些模块只是工具,算法数学才是精髓。

Numpy_数组_03


Numpy_数组_04