- 参考:《利用python进行数据分析》第4章
- 注意,由于本文是jupyter文档转换来的,代码不一定可以直接运行,有些注释是jupyter给出的交互结果,而非运行结果!!
文章目录
- 1. 生成网格数据:np.meshgrid方法
- 1.1 np.meshgrid
- 1.2 使用示例
- 2. 将条件逻辑作为数组操作:np.where方法
- 2.1 np.where
- 2.2 使用示例
- 2.2.1 基础用法
- 2.2.2 数组原位替换
- 3. 数学和统计方法
- 4. 布尔数组的方法
- 4.1 统计True的个数
- 4.2 与、或真值检查
- 5. 排序
- 6. 唯一值与其他集合逻辑
- NumPy 数组允许用户利用简单的数组表达式完成多种数据操作任务,而无需编写大量循环。这种利用数组表达式替代显式循环语句的方法,称为
向量化
- 通常,向量化的数组操作会比纯Python等价实现快一到两个数量级
1. 生成网格数据:np.meshgrid方法
1.1 np.meshgrid
- 此方法利用坐标向量返回坐标矩阵,给定n个一维坐标数组 x1,x2,…,xn,生成 N 维坐标数组,可用于 N 维网格上 N 维标量/向量的矢量化表示
- 原型:
np.meshgrid(*xi, copy=True, sparse=False, indexing='xy')
-
x1,x2,...,xn
(array_like):表示网格坐标的一维数组 -
indexing
({‘xy’,‘ij’},optional):可设为 ‘xy’(输出数组使用笛卡尔索引) 或 ‘ij’(输出数组使用矩阵索引),默认值为’xy’ -
sparse
(bool, optional):如果为True,则返回稀疏网格以节省内存,默认值为False -
copy
(bool, optional):如果为False,则返回原始数组的视图以节省内存,默认值为True。 请注意sparse=False, copy=False
可能会返回不连续的数组
- 返回值:n个n维数组 X1, X2,…, XN
- 对于输入参数向量
x1
, x2
,…, ‘xn’,用 Ni=len(xi)
表示各向量长度,则缺省 indexing='xy'
时返回数组形状为 .shape = (N1, N2, N3 ,...Nn)
;indexing='ij'
时返回数组形状为 (N2, N1, N3,...Nn)
。 - 缺省
indexing='xy'
时,X1的第0轴(行)使用x1重复填充,X2的第1轴(列)使用x2重复填充;indexing='ij'
时X1的第1轴(列)使用x1重复填充,X2的第0轴(行)使用x2重复填充。X1和X2在两种设定下的返回值都是互为转置关系。 - 对于更高的维度,可以看作把二维状态下的每个元素扩展为一维向量,
indexing
参数不再有作用
- 说明:
indexing
参数可以有点抽象,这个参数仅仅对前两个维度有效,举个二维的例子,假设输入两个一维数组x和y,则
-
indexing='xy'
时,可以像笛卡尔坐标系一样把xy理解为x轴和y轴,返回二维数组的尺寸就是 .shape = (y.size,x.size)
-
indexing='ij'
时,则像矩阵一样把xy理解为行数和列数,返回二维数组的尺寸就是 .shape = (x.size,y.size)
- 测试
import numpy as np
x = np.arange(5)
y = np.arange(3)
x1,y1 = np.meshgrid(x,y,indexing='ij')
x2,y2 = np.meshgrid(x,y)
print('indexing = ij')
print(x1)
print(y1,'\n')
print('indexing = xy')
print(x2)
print(y2,'\n')
print('转置关系')
print(x1[4,2],y1[4,2])
print(x2[2,4],y2[2,4])
'''
indexing = ij
[[0 0 0]
[1 1 1]
[2 2 2]
[3 3 3]
[4 4 4]]
[[0 1 2]
[0 1 2]
[0 1 2]
[0 1 2]
[0 1 2]]
indexing = xy
[[0 1 2 3 4]
[0 1 2 3 4]
[0 1 2 3 4]]
[[0 0 0 0 0]
[1 1 1 1 1]
[2 2 2 2 2]]
转置关系
4 2
4 2
'''
1.2 使用示例
- 现在要对一些网格数据计算函数
import matplotlib.pyplot as plt
# 生成网格数据
points = np.arange(-5,5,0.01)
xs,ys = np.meshgrid(points,points)
# 计算函数
z = np.sqrt(xs**2 + ys**2)
# 可视化
plt.imshow(z,cmap=plt.cm.gray)
plt.colorbar()
2. 将条件逻辑作为数组操作:np.where方法
2.1 np.where
- 此函数是三元表达式 x if condition else y 的向量化版本
- 原型:
where(condition, [x, y])
-
condition
(array_like,bool):如果为真,则选则 x
,否则选则 y
-
x,y
(array_like):可供选择的值,可以是数组,也可以是标量。x
、y
和 condition
需要可以广播到某种形状
- 注意:当仅提供
condition
时,此函数是 np.asarray(condition).nonzero()
的简写
2.2 使用示例
2.2.1 基础用法
- 假设我们有两个数值数组
xarr
和 yarr
,我们希望依据一个布尔数组cond
选择元素。当 cond
中元素为 True
时,取 xarr
中的对应元素值,否则取 yarr
中的对应元素值。通常我们使用列表推导式完成这种操作
xarr = np.array([1,2,3,4,5])
yarr = np.array([6,7,8,9,0])
cond = np.array([True,False,True,True,False])
result = [(x if c else y) for x,y,c in zip(xarr,yarr,cond)]
print(result)
# [1, 7, 3, 4, 0]
- 这样做的问题在于,
- 数组很大时,速度缓慢
- 仅适用于一维情况
这时就适于使用np.where
方法
result = np.where(cond,xarr,yarr)
print(result) # [1 7 3 4 0]
2.2.2 数组原位替换
-
np.where
的后两个参数 [x, y]
不一定是数组,也可以是标量。where的一个经典用法,就是根据一定的条件,对数组中元素进行原位替换
print('随机数组')
arr = np.random.randn(4,4)
print(arr,'\n')
print('标量原位替换')
print(np.where(arr>0,2,-2),'\n')
print('数组原位替换')
print(np.where(arr>0,2,arr))
'''
随机数组
[[ 0.6818313 1.10788644 0.60707372 -0.7961009 ]
[-0.69947074 1.57684828 1.97240362 0.6681626 ]
[-0.78550736 -0.65122289 0.44938015 -1.86345715]
[ 0.18658391 -1.19279691 0.20794079 -0.86630991]]
标量原位替换
[[ 2 2 2 -2]
[-2 2 2 2]
[-2 -2 2 -2]
[ 2 -2 2 -2]]
数组原位替换
[[ 2. 2. 2. -0.7961009 ]
[-0.69947074 2. 2. 2. ]
[-0.78550736 -0.65122289 2. -1.86345715]
[ 2. -1.19279691 2. -0.86630991]]
'''
3. 数学和统计方法
- NumPy提供了许多关于计算整个数组统计值或关于轴向数据的数学函数,可以作为数组类型的方法被调用。
方法 | 描述 |
sum | 沿轴向计算所有元素的累加和,0长度的数组,累加和为0 |
mean | 数学平均,0长度的数组平均值为NaN |
std, var | 标准差和方差,可以选择自由度调整(默认分母为n) |
min, max | 最小值 & 最大值 |
argmin, argmax | 最小值索引 & 最大值索引 |
cumsum | 从0开始元素累积和 |
cumprod | 从1开始元素累积积 |
- 在调用时有两种等价方法
- 直接调用数组示例的方法,如
arr.sum()
- 使用顶层的NumPy函数,如
np.sum(arr)
- 部分测试
print('生成一些随机数据')
arr = np.random.randn(5,4)
print(arr,'\n')
print('数组均值')
print(np.mean(arr),'\n')
print('数组累加和')
print(arr.sum(),'\n')
print('第0轴(行)轴向均值')
print(arr.mean(axis = 0),'\n')
print('第1轴(列)轴向累加和')
print(arr.sum(axis = 1),'\n')
'''
生成一些随机数据
[[-1.14758004 -0.672113 -0.13183887 -2.47382142]
[-0.41932578 -1.3022716 1.79016834 0.61126159]
[-0.76037654 0.81149644 -2.15071079 -0.97268024]
[ 2.12643459 0.44006178 0.57575081 -1.47044089]
[ 1.11763418 0.72242666 -0.4468634 -1.48691387]]
数组均值
-0.26198510217397003
数组累加和
-5.239702043479401
第0轴(行)轴向均值
[ 1.83357284e-01 -7.99443369e-05 -7.26987828e-02 -1.15851897e+00]
第1轴(列)轴向累加和
[-4.42535333 0.67983255 -3.07227113 1.67180629 -0.09371643]
'''
arr = np.array([1,2,3,4,5,6,7])
print('原始数据')
print(arr,'\n')
print('cumsum返回累加中间结果')
print(arr.cumsum(),'\n')
print('cumprod返回累积极中间结果')
print(arr.cumprod(),'\n')
arr = np.array([[0,1,2],[3,4,5],[6,7,8],[9,10,11]])
print('原始数据')
print(arr,'\n')
print('第0轴(行)轴向累加')
print(arr.cumsum(axis=0),'\n')
print('第1轴(列)轴向累积')
print(arr.cumprod(axis=1))
'''
原始数据
[1 2 3 4 5 6 7]
cumsum返回累加中间结果
[ 1 3 6 10 15 21 28]
cumprod返回累积极中间结果
[ 1 2 6 24 120 720 5040]
原始数据
[[ 0 1 2]
[ 3 4 5]
[ 6 7 8]
[ 9 10 11]]
第0轴(行)轴向累加
[[ 0 1 2]
[ 3 5 7]
[ 9 12 15]
[18 22 26]]
第1轴(列)轴向累积
[[ 0 0 0]
[ 3 12 60]
[ 6 42 336]
[ 9 90 990]]
'''
4. 布尔数组的方法
4.1 统计True的个数
- NumPy中布尔值通常会被视作1 (True) 和0 (False),因此可以用
sum
方法计算布尔数组中 True
的个数
arr = np.random.randn(100)
print((arr>0).sum()) # 51
4.2 与、或真值检查
- 布尔数组的典型用法是判断其所有元素的与、或结果,这需要用到两个方法
-
any
:检查数组中是否至少有一个 True
,即或结果 -
all
:检查数组中是否全部都是 True
,即与结果
这两个方法也可用于非布尔值数组,所有非零元素按True处理
bools = np.array([False,False,True,False])
print(bools.any()) # True
print(bools.all()) # False
5. 排序
- 类似Python中的列表类型,NumPy数组可以使用
sort
方法按位置排序 - 原型
arr.sort(axis=-1, kind=None, order=None)
-
axis
(int, optional):要排序的轴,默认值-1,表示沿最后一个轴排序,设置None
代表所有元素拉平后排序 -
kind
({‘quicksort’, ‘mergesort’, ‘heapsort’, ‘stable’},optional):可选的排序算法,默认为 “quicksort”。注意,“stable” 和 “mergesort” 都在底层使用 timsort,通常,实际实现会因数据类型而异。 保留 “mergesort” 选项是为了向后兼容 -
order
(str 或 str list,optional):多级排序的顺序,需要构建一个field
- 说明:
- 可以在多维数组中,传入
axis
参数以指定排序的维度 - 可以使用两种方式调用排序方法,
arr.sort
在原位进行排序;np.sort(arr)
返回一个排序好的数组的拷贝 - NumPy中的sort函数仅支持排升序,要排降序,可以用这种技巧
arr = np.sort(arr)[::-1]
- 示例
arr = np.random.randn(6)
print('原数组')
print(arr)
print('排升序')
print(np.sort(arr))
print('排降序')
print(np.sort(arr)[::-1],'\n')
arr = np.arange(14,0,-1)
arr.resize(5,3)
print('原数组')
print(arr)
print('第0轴(行)轴向排序')
print(np.sort(arr,axis=0))
print('第1轴(列)轴向排序')
print(np.sort(arr,axis=1))
'''
原数组
[-0.42145353 -0.68593585 0.0829771 -0.23195342 -0.12941807 -1.91235085]
排升序
[-1.91235085 -0.68593585 -0.42145353 -0.23195342 -0.12941807 0.0829771 ]
排降序
[ 0.0829771 -0.12941807 -0.23195342 -0.42145353 -0.68593585 -1.91235085]
原数组
[[14 13 12]
[11 10 9]
[ 8 7 6]
[ 5 4 3]
[ 2 1 0]]
第0轴(行)轴向排序
[[ 2 1 0]
[ 5 4 3]
[ 8 7 6]
[11 10 9]
[14 13 12]]
第1轴(列)轴向排序
[[12 13 14]
[ 9 10 11]
[ 6 7 8]
[ 3 4 5]
[ 0 1 2]]
'''
6. 唯一值与其他集合逻辑
- NumPy包含一些针对一维ndarray的基础集合操作
方法 | 描述 |
unique(x) | 计算x的唯一值 |
intersect1d(x,y) | 计算x和y的交集,并排序 |
union1d(x,y) | 计算x和y的并集,并排序 |
in1d(x,y) | 计算x中的元素是否包含在y中,返回一个布尔数组 |
setdiff1d(x,y) | 差集,在x中但不在y中的元素 |
setxor1d(x,y) | 异或集,在x或y中,但不属于x , y交集的元素 |
- 部分测试
names = np.array(['Tom','Bob','Bill','Tom','Bob'])
print(np.unique(names)) # ['Bill' 'Bob' 'Tom']
ints = np.array([1,1,2,2,3,3,3,4,5,6,6,6,6])
print(np.unique(ints)) # [1 2 3 4 5 6]
values = np.array([6,0,0,3,2,5,6])
print(np.in1d(values,[2,3,6])) # [ True False False True True False True]
v1 = np.array([4,3,2,1])
v2 = np.array([8,7,6,3,1])
print(np.intersect1d(v1,v2)) # [1 3]