4.《Python数据分析》numpy基础:数组和向量计算

NumPy(Numerical Python)是Python用于数值计算的基础包

  • 内置高效的多维数组ndarray,提供快速向量计算和灵活的广播机制
  • 具备常见的数学计算函数(线性代数、傅里叶变换等)和读写数据的能力
  • 在一个连续的内存块中存储数据,节省内存并且计算效率高
  • 提供动态、易用的接口,也很方便与其他常用编程语言对接

关于广播机制可参阅1.3 广播机制

1 多维数组

ndarray数组是一个通用的同构数据多维容器,即所有元素的类型应该是相同的

数组基本操作:

import numpy as np # 库重命名

data = np.random.randn(2, 3) # 随机生产2*3的数组
data = data * 10 + data # 基本向量运算
data.shape # 查看数组维度
data.dtype # 查看元素类型
data.astype(str) # 转换元素类型
data = np.array([[1, 2, 3], [6, 7, 8]]) # 列表转数组
data[2:,:-1].copy() # 支持灵活的切片操作(第2行以后,倒数第1列之前)
data[~(data < 6)] = 1 # 过滤与复制,~用来表示非这一逻辑操作

细节补充:

  1. 尽量不要在numpy中使用str格式,因为其内部空间是固定的,所以可能出现数据截断的问题
  2. 当数据与指定格式不兼容时,astype可能会报错;转换成功后会生成一个新对象(即使格式前后一样)
  3. 数组的切片操作其实是一种视图,并不会复制数据(减少内存负担),使用copy()可以显式复制数据
  4. Python在进行逻辑操作时会使用andor等关键字,但在数组中要使用&|来实现

内置函数用于便捷地生成矩阵:ones 全1矩阵、zeros 全0矩阵、empty 空矩阵、eye 单位矩阵

数组操作常用:

dara.T # 数组转置
data.reshape((3,2)) # 数组维度变换
np.dot(data.T, data) # 计算矩阵点积
arr = np.arange(16).reshape((2, 2, 4))
arr.transpose((0, 2, 1)) # 轴变换(2轴变3轴,3轴变2轴)
arr.swapaxes(1, 2) # 指定两个轴进行转置(也是视图操作)

2 伪随机数生成

# 从标准正态分布中得到一个4 × 4的样本数组
samples = np.random.standard_normal(size=(4, 4))
new_samples = np.random.permutation(samples) # 随机打乱
np.random.shuffle(samples) # 原地随机打乱

除了标准正态分布,numpy的随机生成还支持uniform均匀分布、integers整数随机、binomial二项分布、normal普通正态、beta贝塔分布、chisquare卡方分布、gamma伽马分布

numpy的随机数是基于生成器种子进行的伪随机,可通过seed固定随机种子,方便结果的复现

3 数组相关通用函数

通用函数(Universal Functions,简称ufunc)是指针对数组每个元素进行运算的函数(矢量化运算)

常见一元ufunc:abs 绝对值、fabs 绝对值(对于非复数,更快)、sqrt 开方、aquare 平方、exp 指数、log,log10,log2 不同底数的对数(默认为e)、sign 正负号、ceil 向上取整、floor 向下取整、modf 切分整数和小数部分、isna 判断是否为空、isinf 判断是否为无穷、sin,cos,tan,sinh,cosh,tanh 常见三角函数

常见二元ufunc(输入项为两个数组):add 元素相加、subtract 元素相减、multiply 元素相乘、divide 元素相除、floor_divide 元素整除(丢弃余数)、power底数^指数、maximum,fmax 比较取最大、minimum,fmin 比较取最小、mod 求模(取余数)、copysign 元素替换(后者替代前者)、>,<,==,!=, 逻辑运算

4 数组相关数据分析

用数组表达式代替循环的做法被称为矢量化(vectorization),相比于循环效率会高很多

# 数据初始化
xarr = np.array([1.1, 1.2, 1.3, 1.4, 1.5])
yarr = np.array([2.1, 2.2, 2.3, 2.4, 2.5])
cond = np.array([True, False, True, True, False])

# 按照条件筛选两组数据
result = [(x if c else y) for x, y, c in zip(xarr, yarr, cond)]
# 数组的矢量化等价写法
result = np.where(cond, xarr, yarr)

常用聚合计算:mean均值、var,std方差/标准差、sum求和、cumsum累积加、cumprod累积乘、min最小值、max最大值、argmin最小值对应位置、argmax最大值对应位置、any数组内元素or运算、all数据内元素and运算

聚合运算可以通过参数axis指定轴,以进行不同维度的聚合

集合相关运算:sort排序、unique去重、intersect1d(x,y)计算x和y的公共元素并排序、union1d(x,y)计算x和y的并集并排序、in1d(x,y)判断x中元素是否属于y、setdiff1d(x,y)在x中且不属于y的元素、setxor1d(x,y)在其中一个数组中存在且不同时存在于两个数组的元素

5 数组的存储与读取

数组的存储与读取示例:

arr = np.arange(10)
np.save('some_array', arr) # 普通存储
np.load('some_array.npy') # 普通读取
np.savez('array_archive.npz', a=arr, b=arr) # 多数组存储
np.load('array_archive.npz')['b'] # 多数组读取
np.savez_compressed('arrays_compressed.npz', a=arr, b=arr) # 多数组压缩存储

6 数组与线性代数

矩阵乘法示例:

x = np.array([[1., 2., 3.], [4., 5., 6.]])
y = np.array([[6., 23.], [-1, 7], [8, 9]])

x.dot(y) # 矩阵乘法 写法1
np.dot(x,y) # 矩阵乘法 写法2
x @ np.ones(3) # 矩阵乘法 写法3

其他常用矩阵运算:diag获取对角线元素、trace对角线求和、det计算行列式、eig计算特征值和特征向量、inv矩阵求逆、pinv广义逆矩阵(伪逆)、qr正交三角分解、svd奇异值分解、solve求解线性方程组、lstsq计算Ax = b最小二乘解

7 案例:随机游走

纯Python实现一次随机游走:

import random
position = 0
walk = [position]
steps = 1000
for i in range(steps):
    step = 1 if random.randint(0, 1) else -1
    position += step
    walk.append(position)

numpy实现一次随机游走:

nsteps = 1000
draws = np.random.randint(0, 2, size=nsteps)
steps = np.where(draws > 0, 1, -1)
walk = steps.cumsum()

numpy实现5000次随机游走:

nwalks = 5000
nsteps = 1000
draws = np.random.randint(0, 2, size=(nwalks, nsteps)) # 0 or 1
steps = np.where(draws > 0, 1, -1)
walks = steps.cumsum(1)

往年同期文章