Python ndarray


掌握Numpy数组对象ndarray

Python提供了一个array模块。array 和list 不同,它直接保存数值,和C语言的一维数组比较类似。但是由于Python的array模块不支持多维,也没有各种运算函数,因此也不适合做数值运算。NumPy的诞生弥补了这些不足。NumPy提供了一种存储单一数据类型的多维数组–ndarray。

感受一下NumPy如何使用类似于Python内建对象的标量计算语法进行批量计算,首先导入NumPy,再生成一个小的随机数组:

然后给data加上一个数学操作:

在第一个数学操作中,所有的元素都同时乘以了10。在第二个数学操作中,数组中的对应元素进行了相加。

注意:使用标准的NumPy导入方式import numpy as np。也可以在代码中写from numpy import *来省略多写的一个np.,然而建议写标准导入的方式。numpy这个命名空间包含了大量与Python内建函数重名的函数(比如min和max)。

1、生成ndarray

生成数组最简单的方式就是使用array函数。array函数接收任意的序列型对象(当然也包括其他的数组),生成一个新的包含传递数据的NumPy数组。例如,列表的转换就是一个好例子:

嵌套序列,例如同等长度的列表,将会自动转换成多维数组:

因为data2是一个包含列表的列表,所以Numpy数组arr2形成了二维数组。可以通过检查ndim和shape属性来确认这一点:

除非显式地指定,否则np.array会自动推断生成数组的数据类型。数据类型被存储在一个特殊的元数据dtype中。例如,之前的两个例子:

除了np.array,还有很多其他函数可以创建新数组。例如,给定长度及形状后,zeros可以一次性创造全0数组,ones可以一次性创造全1数组。empty则可以创建一个没有初始化数值的数组。想要创建高维数组,则需要为shape传递一个元组:

arange是Python内建函数range的数组版:

2、ndarray的数据类型

数据类型,即dytpe,是一个特殊的对象,它包含了ndarray需要为某一种类型数据所申明的内存块信息(也称为元数据,即表示数据的数据):

dtype是NumPy能够与其他系统数据灵活交互的原因。数据的dtype通常都是按照一个方式命名:类型名,比如float和int,后面再接上表明每个元素位数的数字。一个标准的双精度浮点值(Python中数据类型为float),将使用8字节或64位。因此,这个类型在NumPy中称为float64。

3、NumPy数组算术

数组之所以重要是因为它允许你进行批量操作而无须任何for循环。NumPy用户称这种特性为向量化。任何在两个等尺寸数组之间的算术操作都应用了逐元素操作的方式:

带有标量计算的算术操作,会把计算参数传递给数组的每一个元素:

同尺寸数组之间的比较,会产生一个布尔值数组:

4、基础索引与切片

NumPy数组索引是一个大话题,有很多种方式可以让你选中数据的子集或某个单个元素。一维数组比较简单,看起来和Python的列表很类似:

如果传入一个数值给数组的切片,例如arr[5:8] = 12,数值被传递给了整个切片。区别于Python的内建列表,数组的切片是原数组的视图。这意味着数据并不是被复制了,任何对于视图的修改都会反映到原数组上。

如果想要一份数组切片的拷贝而不是一份视图的话,就必须显式地复制这个数组,例如arr[5:8].copy()

对更高维度的数组,会有更多选择。在一个二维数组中,每个索引值对应的元素不再是一个值,而是一个一维数组:

因此,单个元素可以通过递归的方式获得。可以通过传递一个索引的逗号分隔列表去选择单个元素,以下两种方式效果一样:

展示二维数组上的索引,将0轴看作“行”,将1轴看作“列”。

在多维数组中,可以省略后续索引值,返回的对象将是降低一个维度的数组。因此在一个2×2×3的数组arr3d中:

arr3d[0]是一个2×3的数组:

类似地,arr3d[1, 0]返回的是一个一维数组:

需要注意的是,以上的数组子集选择中,返回的数组都是视图。

4.1 数组的切片索引

与Python列表的一维对象类似,数组可以通过类似的语法进行切片:

前面的二维数组,arr2d,对数组进行切片略有不同:

数组沿着轴0进行了切片。表达式arrzd[:2]的含义为选择arr2d的前两“行”。
对切片表达式赋值时,整个切片都会重新赋值:

5、布尔索引

假设我们的数据都在数组中,并且数组中的数据是一些存在重复的人名。使用numpy.random中的randn函数来生成一些随机正态分布的数据:

假设每个人名都和data数组中的一行相对应,并且我们想要选中所有’Bob’对应的行。与数学操作类似,数组的比较操作(比如==)也是可以向量化的。因此,比较names数组和字符串’Bob’会产生一个布尔值数组:

在索引数组时可以传入布尔值数组:

为了选择除了’Bob’以外的其他数据,可以使用!=或在条件表达式前使用~对条件取反:

当要选择三个名字中的两个时,可以对多个布尔值条件进行联合,需要使用数学操作符如&(and)和|(or):

使用布尔值索引选择数据时,总是生成数据的拷贝,即使返回的数组并没有任何变化。

注意:Python的关键字and和or对布尔值数组并没有用,使用&(and)和|(or)来代替。

6、神奇索引

神奇索引是NumPy中的术语,用于描述使用整数数组进行数据索引。

假设有一个8×4的数组:

为了选出一个符合特定顺序的子集,可以简单地通过传递一个包含指明所需顺序的列表或数组来完成:

如果使用负的索引,将从尾部进行选择:

传递多个索引数组时情况有些许不同,这样会根据每个索引元组对应的元素选出一个一维数组:

即第1行第0列的元素是4,第5行第3列的元素是23,依此类推。

7、数组转置和换轴

转置是一种特殊的数据重组形式,可以返回底层数据的视图而不需要复制任何内容。数组拥有transpose方法,也有特殊的T属性:

当进行矩阵计算时,可能会经常进行一些特定操作,比如,当计算矩阵内积会使用np.dot:


评论区(2)

  • 张倩茹

    非常好

    2021年3月26日 16:36 回复

  • 朱颖

    非常好

    2021年3月25日 13:53 回复

回复 张倩茹 取消