NumPy 基础:数组和矢量计算

1. 前言

这是我在学习这是我在学习《利用Python进行数据分析》第四章的记录。

NumPy介绍

NumPy(Numerical Python)是Python数值计算最重要的基础包。大多数提供科学计算的包都是用NumPy的数组作为构建基础。

NumPy工具从底层到顶层完全大同,底层提供了简单易用的C API。上层又提供了适量算数运算和复杂广播能力。

NumPy的效率很高,它在连续的内存块中存储数据,独立于其他Python内置对象;C语言库可以操作内存,而不必进行类型检查或其它前期工作,使用的内存更少;NumPy可以在整个数组上执行复杂的计算,而不需要Python的for循环。基于NumPy的算法比纯Python快10到100倍,并且使用的内存更少。

2. NumPy的ndarray:一种多维数组对象

ndarray是一个通用的同构数据多维容器,也就是说,其中的所有元素必须是相同类型的。每个数组都有一个shape元组和一个dtype对象。

创建ndarray

array函数:它接受一切序列行的对象,产生一个新的含有传入数据的NumPy数组。嵌套序列会被转换为多维数组。至于类型,np.array会自动进行推导。

zeros, ones, empty这些函数利用输入形状元组创建arrayempty返回的是未初始化的垃圾值。

arange 是Python内置函数range的数组版。

image-20201010143223125
image-20201010143223125
ndarray的数据类型

dtype是一个特殊的对象,它含有ndarray将一块内存解释为特定数据类型所需的信息。

image-20201010143654842
image-20201010143654842
image-20201010143714808
image-20201010143714808

astype方法可以明确地将一个数组从一个dtype转换成另一个dtype

np.string_类型使用要小心,因为NumPy字符串数据是大小固定的,发生截取时不会警告。

注意:调用astype总会创建一个新的数组,即使类型相同。

NumPy数组的运算

数组很重要,它让我们不用编写循环即可对数据执行批量运算,即矢量化。

+, -, *, /, **

数组和数组间:会转化成对元素的操作。

数组和标量间:会传播到各个元素。

> < == !=

会生成布尔值数组。

基本的索引和切片

视图:ndarray和列表最重要的区别就是,数组接片是原始数组的视图,视图上的任何修改都会反映到源数组上。

copy如果不想要视图,而是要副本,用这个方法。

arr2d[0][2]arr2d[0,2]两种索引方式等价。

切片索引

:ndarray的切片语法使用:,只有冒号表示选取整个轴。

布尔型索引
1
2
a = array([ True, False, False, True, False, False, False ], dtype=bool)
data[a]

!=, ~都可以对条件进行否定。

data[data < 0] = 0通过布尔型数组设定了值。

花式索引

花式索引(Fancy indexing)是一个NumPy属于,它指的是利用整数数组进行索引。

1
2
arr[[4, 3, 0, 6]]
arr[[1, 5, 7, 2], [0, 3, 1, 2]]

注意:花式索引跟切片不同,它总是将新数据复制到新数组中。

数组转置和轴对换

转置:是重塑的一种特殊形式,它返回的是源数据的视图(而非复制)。

transpose(), T进行矩阵计算时,经常用到该操作。

高维数组的转置需要一个由轴编号组成的元组才能对这些轴进行转置。其实完全可以理解为对轴的次序进行了一个重新排列。

.T 简单的转置可以使用.T,它就是进行轴对换。

swapaxes 接受一对轴编号,并将其交换。

3. 通用函数:快速的元素级数组函数

通用函数(即ufunc)是一种对ndarray中的数据执行元素级运算的函数。可以将其看做简单函数的矢量化包装器。

np.sqrt(arr)

np.exp(arr)

np.maximum(x, y)计算两个数组中最大的元素。

np.modf(arr) 可以返回多个数组,它会返回浮点数数组的小数和整数部分。

注意:Ufuncs可以接受一个out可选参数,这样就能在数组原地进行操作。如np.sqrt(arr, arr)

image-20201010192608054
image-20201010192608054
image-20201010192621394
image-20201010192621394
image-20201010192755464
image-20201010192755464

4. 利用数组进行数据处理

NumPy数组使我们可以将许多种数据处理任务表述为简洁的数组表达式。用数组表达式代替循环的做法,通常被称为矢量化。

sqrt(x^2+y^2)假设我们要在网格上计算该函数,我们需要用到xs, ys = np.meshgrid(points, points)然后再利用z = np.sqrt(xs ** 2 + ys ** 2)计算即可。

将条件逻辑表述为数组运算

result = np.where(cond, xarr, yarr)的作用相当于result = [(x if c else y) for x,y,c in zip(xarr, yarr, cond)]

np.where(arr>0,2,-2)帮助我们完成了对于一个矩阵,将所有正值替换成2,所有负值替换成-2.

数学和统计方法

可以通过数组上的一组数学函数对整个数组或某个轴向的数据进行统计计算。sum, mean, std等聚合计算(aggregation,通常叫做约简)

注意:这些聚合函数既可以当作数组的实例方法调用,也可以当做顶级NumPy函数使用。

arr.mean()np.mean(arr)

axis对于mean, sum这类的函数可以接受一个axis选项参数,用于计算该轴上的统计值,最终结果使一个少一维的数组。

arr.mean(1)是计算行的平均值。

cumsum, cumprod之类的方法不聚合,而是产生一个由中间结果组成的数组。

image-20201010195342262
image-20201010195342262
用于布尔型数组的方法

注意:在上面的这些方法中,布尔值会被强制转换成1和0,因此,sum经常被用来对布尔型数组中的True值计数。

any方法对布尔型数组非常有用,测试数组中是否存在一个或多个True

all检查数组中所有值是否都是True

排序

sort方法,跟Python内置的列表一样,NumPy数组也可以通过sort方法就地排序。

注意:多维数组可以在任何一个轴上进行排序。

np.sort()顶级方法返回的是已排序副本。

唯一化以及其它的集合逻辑

np.unique()用于找出数组中的唯一值并返回已排序的结果。与之等价的纯Python代码为sorted(set(names))

np.in1d()函数用于测试一个数组中的值再另一个数组中的成员资格,返回一个布尔型数组。

image-20201010200337608
image-20201010200337608

5. 用于数组的文件输入输出

NumPy能够读写磁盘上的文本数据或二进制数据。这一小节只讨论NumPy的内置二进制格式,因为加载文本或表格数据pandas更方便。

np.save, np.load是读写磁盘数组数据的两个主要函数。默认情况下,数组是以未压缩的原始二进制格式保存在扩展名为.npy中的。

1
2
3
arr = np.arange(10)
np.save('some_array', arr)
np.load('some_array.npy')

np.savez可以将多个数组保存到一个为压缩文件中,将数组以关键字参数的形式传入其中。如np.savez('array_archive.npz',a=arr,b=arr)

.npz文件加载时,hide到一个类似字典的对象,该对象会对哥哥数组进行延迟加载。

np.savez_compressed可以将数据压缩。

6. 线性代数

NumPy不像某些语言,通过*对两个二维数组相乘得到的是一个元素级的积,而不是一个矩阵点积。

x.dot(y), np.dot(x, y)矩阵点积。

@也可以用作中缀运算符,进行矩阵乘法。

numpy.linalg中有一组标准的矩阵分解运算以及注入求逆和行列式之类的东西。它们跟Matlab和R等语言所使用的是相同的行业标准线性代数库,如BLASLAPACK等。

image-20201010202737358
image-20201010202737358

7. 伪随机数生成

np.random模块对Python内置的random进行了补充,增加了一些用于高效生成多种概率分布的样本值的函数。

np.random.seed(1234)全局的随机种子。

rng = np.random.RandomState(1234)创建一个与其它隔离的随机数生成器。

np.random.normal(size=(4,4))高斯分布。

image-20201010203853106
image-20201010203853106

image-20201010203431044