利用NumPy进行统计分析


利用NumPy进行统计分析

使用NumPy数组可以使你利用简单的数组表达式完成多种数据操作任务,而无须写些大量循环。这种利用数组表达式来替代显式循环的方法,称为向量化。通常,向量化的数组操作会比纯Python的等价实现在速度上快一到两个数量级(甚至更多),这对所有种类的数值计算产生了最大的影响。

1、使用数组进行面向数组编程

作为一个简单的示例,假设对一些网格数据来计算函数sqrt(x^2 + y^2)的值。np.meshgrid函数接收两个一维数组,并根据两个数组的所有(x, y)对生成一个二维矩阵:

现在,可以用和两个坐标值同样的表达式来使用函数:

1.1 将条件逻辑作为数组操作

numpy.where函数是三元表达式x if condition else y的向量化版本。假设有一个布尔值数组和两个数值数组:

假设cond中的元素为True时,我们取xarr中的对应元素值,否则取yarr中的元素。我们可以通过列表推导式来完成,像下列代码这样:

这样会产生多个问题。首先,如果数组很大的话,速度会很慢(因为所有的工作都是通过解释器解释Python代码完成)。其次,当数组是多维时,就无法凑效了。而使用np.where时,就可以非常简单地完成:

np.where的第二个和第三个参数并不需要是数组,它们可以是标量。where在数据分析中的一个典型用法是根据一个数组来生成一个新的数组。假设你有一个随机生成的矩阵数据,并且你想将其中的正值都替换为2,将所有的负值替换为-2,使用np.where会很容易实现:

1.2 数学和统计方法

许多关于计算整个数组统计值或关于轴向数据的数学函数,可以作为数组类型的方法被调用。你可以使用聚合函数(通常也叫缩减函数),比如sum、mean和std(标准差),既可以直接调用数组实例的方法,也可以使用顶层的NumPy函数。

像mean、sum等函数可以接收一个可选参数axis,这个参数可以用于计算给定轴向上的统计值,形成一个下降一维度的数组:

arr.mean(1)表示“计算每一列的平均值”,而arr.sum(0)表示“计算行轴向的累和”。其他的方法,例如cumsum和cumprod并不会聚合,它们会产生一个中间结果:

在多维数组中,像cumsum这样的累积函数返回相同长度的数组,但是可以在指定轴向上根据较低维度的切片进行部分聚合:

下表是统计方法的列表:

1.3 布尔值数组的方法

在前面介绍的方法,布尔值会被强制为1(True)和0(False)。因此,sum通常可以用于计算布尔值数组中的True的个数:

对于布尔值数组,有两个非常有用的方法any和all。any检查数组中是否至少有一个True,而all检查是否每个值都是True:

这些方法也可适用于非布尔值数组,所有的非0元素都会按True处理。

1.4 排序

和Python的内建列表类型相似,NumPy数组可以使用sort方法按位置排序:

可以在多维数组中根据传递的axis值,沿着轴向对每个一维数据段进行排序:

1.5 唯一值与其他集合逻辑

NumPy包含一些针对一维ndarray的基础集合操作。常用的一个方法是np.unique,返回的是数组中唯一值排序后形成的数组:

将np.unique和纯Python实现相比较:

另一个函数,np.in1d,可以检查一个数组中的值是否在另外一个数组中,并返回一个布尔值数组:

2、使用数组进行文件输入和输出

NumPy可以在硬盘中将数据以文本或二进制文件的形式进行存入硬盘或由硬盘载入。np.save和np.load是高效存取硬盘数据的两大工具函数。数组在默认情况下是以未压缩的格式进行存储的,后缀名是.npy:

如果文件存放路径中没写.npy时,后缀名会被自动加上。硬盘上的数组可以使用np.load进行载入:

可以使用np.savez并将数组作为参数传递给该函数,用于在未压缩文件中保存多个数组:

当载入一个.npy文件的时候,会获得一个字典型的对象,并通过该对象很方便地载入单个数组:

如果数据已经压缩好了,使用numpy.savez_compressed将数据存入已经压缩的文件:

3、线性代数

线性代数,比如矩阵乘法、分解、行列式等方阵数学,是所有数组类库的重要组成部分。和Matlab等其他语言相比,NumPy的线性代数中所不同的是*是矩阵的逐元素乘积,而不是矩阵的点乘积。因此NumPy的数组方法和numpy命名空间中都有一个函数dot,用于矩阵的操作:

x.dot(y)等价于np.dot(x, y):

一个二维数组和一个长度合适的一维数组之间的矩阵乘积,其结果是一个一维数组:

特殊符号@也作为中缀操作符,用于点乘矩阵操作:

4、伪随机数生成

numpy.random模块填补了Python内建的random模块的不足,可以高效地生成多种概率分布下的完整样本值数组。例如,可以使用normal来获得一个4×4的正态分布样本数组:

然而Python内建的random模块一次只能生成一个值。你可以从下面的示例中看到,numpy.random在生成大型样本时比纯Python的方式快了一个数量级。

numpy.random中的数据生成函数公用了一个全局的随机数种子。为了避免全局状态,可以使用numpy.random.RandomState生成一个随机数生成器,使数据独立于其他的随机数状态:

下表是numpy.random中可用的部分函数:


评论区(0)

评论