[Python3] NumPy基础


[ NumPy version: 1.18.1 ]


import numpy as np

一、创建数组

# 1.从python列表创建数组
# 整型数组
np.array([1, 4, 2, 5, 3])
# 明确数据类型
np.array([1, 2, 3, 4], dtype='float32')
# 嵌套列表构成的多维数组
np.array([range(i, i + 3) for i in [2, 4, 6]])

# 2.从头创建数组
np.zeros(10, dtype=int)
np.ones((2, 5), dtype=float)
np.full((3, 5), 3.14)
np.arange(0, 20, 2)		#线性序列
np.linspace(0, 1, 5)	#5个元素均匀分布0~1(含1)
np.random.random((3, 3))	#3x3,0~1均匀分布随机数
np.random.normal(0, 1, (3, 3))	#3x3,均值0,标准差1的正态分布随机数
np.random.randint(0, 10, (3, 3))	#3x3,[0, 10)区间随机整型数组
np.eye(3)	#3x3单位矩阵
np.empty(3)	#3个整型数的未初始化数组,值为内存空间中任意值

np.random.seed(0)	#设置随机数种子

二、数组操作类型

1. 数组属性

np数组属性:ndim维度,shape维度大小,size数组总大小,dtype数据类型,itemsize元素字节大小,nbytes数组总字节大小 nbytes = itemsize x size

2. 数组索引:获取单个元素

x[1]
x[2, -1]

3. 切片

数组切片 x[start:stop:step] 默认start=0, stop=维度大小, step=1

# 1.一维子数组
x = np.arange(10)
x[::-1]
x[5::-2] #从索引5开始到索引0结束,间隔1倒序
# 2.多维子数组
x2 = np.array([[12, 5, 2, 4], [7, 6, 8, 8], [1, 6, 7, 7]])
x2[:2, :3]	#2行3列
x2[:3, ::2]	#所有行隔一列
x2[::-1, ::-1]	#行列均逆序
# 3.获取数组行和列
x2[:, 0]	#x2第1列
x2[0, :]	#第1行
x2[0]		#第1行,空切片:可省略
# 4.非副本视图的子数组
#数组切片返回的是数组数据的视图,不是数值数据的副本(python列表中切片是值的副本)。
#处理大数据集时可以获取或处理这些数据集的片段而不用复制底层的数据缓存。
# 5.创建数组的副本
x2[:2, :2].copy()

4. 数组的变形

x = np.arange(1, 10).reshape((3, 3))
x.reshape((1, 3)) = x[np.newaxis, :]	#通过newaxis获取行向量
x.reshape((3, 1)) = x[:, np.newaxis]	#获取列向量

5. 数组拼接和分裂

# 1.拼接
x = np.array([1, 2, 3])
y = np.array([3, 2, 1])
np.concatenate([x, y])
np.concatenate([x, y, z])
np.concatenate([grid, grid])	#默认axis=0,沿第一个轴拼接
np.concatenate([grid, grid], axis=1)	#沿第二个轴拼接
# 沿着固定维度处理数组
np.vstack([x, grid]) 	#垂直栈
np.hstack([grid, y]) 	#水平栈
np.dstack 				#沿第三个维度拼接数组

# 2.分裂
x1, x2, x3 = np.split(x, [3, 5])	#索引列表记录的是分裂点位置索引,N分裂点会得到N+1个子数组
upper, lower = np.vsplit(grid, [2])	#上下分裂
left, right = np.hsplit(grid, [2])	#左右分裂
np.dsplit 							#第三维度分裂

三、数组计算:通用函数

# 算数运算符
np.add
np.substract
np.negtive 			#负数运算
np.multiply
np.divide
np.floor_divide 	#向下整除运算 3//2=1
np.power 			#指数运算 3^2
np.mod 				#模,余数 %
# 绝对值
np.absolute(x) = np.abs(x)
# 三角函数
theta = np.linspace(0, np.pi, 3)
np.sin(theta)
np.cos(theta)
np.tan(theta)
# 逆三角函数
x = [-1, 0, 1]
np.arcsin(x)
np.arccos(x)
np.arctan(x)
# 指数和对数
np.exp(x)		#e^x
np.exp2(x)		#2^x
np.power(3, x)	#3^x
np.log(x)		#ln(x)
np.log2(x)		
np.log10(x)
# x值很小时,下面函数的值更精确
np.expm1(x) 	#exp(x)-1
np.log1p(x) 	#log(1+x)

高级通用函数特性

  1. 指定输出:制定一个用于存放运算结果的数组。对于较大数组,慎重使用out参数有效节约内存
x = np.arange(5)
y = np.empty(5)
np.multiple(x, 10, out=y)

z = np.zeros(10)
np.power(2, x, out=z[::2])
  1. 聚合

reduce方法对给定元素和操作重复执行至得到单个结果(np.sum, np.prod, np.cumsum, np.cumprod也可以实现reduce功能)

x = np.arange(1, 6)
np.add.reduce(x)
np.multiply.reduce(x)

# accumulate可以存储每次计算的中间结果
np.add.accumulate(x)
  1. 外积:任何通用函数都可以用outer方法获得两个不同输入数组所有元素对的函数运算结果(实现乘法表)
x = np.arange(1, 6)
np.multiply.outer(x, x)

四、聚合

# 聚合函数
np.sum			#和
np.prod			#积
np.mean 		#平均值
np.std			#标准差
np.var			#方差
np.min 			#最小值
np.max 			#最大值
np.argmin 		#找出最小值的索引
np.argmax 		#找出最大值的索引
np.median 		#中位数
np.percentile 	#计算基于元素排序的统计值
np.any 			#验证是否存在元素为真
np.all 			#验证所有元素是否为真
  1. 聚合函数参数axis用于指定沿着哪个轴的方向进行聚合。axis=0每列,axis=1每行
  2. 大多数聚合有对NaN值的安全处理策略(NaN-safe)(以上除any all均有,在方法前加nan,如np.nansum),计算时忽略所有的缺失值。(NumPy1.8版本后可用)

五、数组计算:广播

广播(broadcast):可将二元运算符用于不同大小的数组。(如标量与数组相加)

广播规则(适用任意二进制通用函数):

  1. 如果两个数组的维度数不相同,那么小维度数组的形状将会在最左边补1。
  2. 如果两个数组的形状在任何一个维度上都不匹配,那么数组的形状会沿着维度为1的维度扩展以匹配另外一个数组的形状。
  3. 如果两个数组的形状在任何一个维度上都不匹配并且没有任何一个维度等于1,那么会引发异常。
# 标量与一维数组
a = np.array([0, 1, 2])
a + 5
# 一维数组与二维数组
M = np.ones((3, 3))
M + a 		#一维数组被广播,沿第二维度扩展到匹配M数组的形状
# 两个数组同时广播
b = np.arange(3)[:, np.newaxis]
a + b 		#a,b同时扩展匹配至公共形状

解读:

# 一维数组 + 二维数组
一维数组 a.shape -> (n,)
二维数组 b.shape -> (m, n)
第一步 a.shape -> (n,)补足为(1, n)
第二步 a.shape -> (1, n)扩展(m, n) -> a,b形状匹配开始运算
如果b.shape为(m, k)任何维度均不匹配,会引发异常ValueError

例:
a.shape (3, 1)
b.shape (3,)  ->(1, 3) 
a.shape ->(3, 3)
b.shape ->(3, 3)
如果a.shape为(3, 2),b扩展后依然不匹配,就会引发异常

广播的应用:

  1. 数组归一化
  2. 二维函数可视化

六、比较、掩码和布尔逻辑

1. 比较

比较运算通用函数适用任意形状、大小的数组。结果输出为布尔数组。

# 通用函数			# 运算符
np.equal 			# ==
np.not_equal 		# !=
np.less 			# <
np.less_equal 		# <=
np.greater 			# >
np.greater_equal 	# >=
rng = np.random.RandomState(0)
x = rng.randint(10, size=(3, 4))
x < 6

2. 操作布尔数组

  1. 统计记录的个数
np.count_nonzero(x < 6) 	#统计True的个数
np.sum(x < 6) 				#False=0,True=1
np.sum(x < 6, axis=1) 		#sum()函数可以沿特定轴进行

# 快速检查任意或所有值是否为True(结果返回True或False)
np.any(x > 8)
np.all(x == 8)
np.any(x < 0, axis=1) 		#any(), all()也可沿轴进行
  1. 布尔运算符(数组的逐位运算)
# 通用函数 				# 运算符
np.bitwise_and 			# & 		# 交集
np.bitwise_or 			# | 		# 并集
np.bitwise_xor 			# ^ 		# 异或
np.bitwise_not 			# ~ 		# 非
# 复合表达式
np.sum((x > 1) & (x < 5))
# A AND B 等价于 NOT(NOT A OR NOT B)
np.sum(~((x <= 5) | (x >= 1)))

3. 将布尔数组作为掩码

# 利用比较运算符得到布尔数组,通过索引将特定值选出,即掩码操作
x < 5 		#输出布尔数组
x[x < 5] 	#输出满足条件的值

# 构建掩码
rainy = (inches > 0)
# 布尔操作、掩码操作和聚合结合
np.median(inches[rainy])

七、花哨索引

  1. 花哨索引(fancy indexing):传递一个索引数组来一次性获得多个数组元素。
rand = np.random.RandomState(42) 	#使用RandomState获得随机数生成器,42为随机种子数
x = rand.randint(100, size=10)

# 方法一
[x[3], x[7], x[2]]

# 方法二:通过传递索引的单个列表或数组来获得同样的结果
ind = [3, 7, 4]
x[ind]
# 利用花哨索引使结果的形状与索引数组形状一致,而不是与被索引数组形状一致
ind = np.array([[3, 7], [4, 5]])
x[ind]
# 适用多维度数组
X = np.arange(12).reshape((3, 4))
row = np.array([0, 1, 2])
col = np.array([2, 1, 3])
X[row, col] 				#第一个索引指行,第二个索引指列,即[0,2],[1,1],[2,3]
X[row[:, np.newaxis], col] 	#矩阵运算逻辑取行列索引
row[:, np.newaxis] * col 	#矩阵运算
  1. 组合索引:花哨索引与其他索引结合
# 与简单索引组合
X[2, [2, 0, 1]]

# 与切片组合
X[1:, [2, 0, 1]] 	#行索引可分别取1,2

# 与掩码组合
mask = np.array([1, 0, 1, 0], dtype=bool)
X[row[:, np.newaxis], mask]
  1. 花哨索引应用
  • 用于获取部分数组:从一个矩阵中选择行的子集。快速分割数据(需要分割训练/测试数据集以验证统计模型)
  • 用于修改部分数组
# 索引值重复次数累加 at()函数
x = np.zeros(10)
i = [2, 3, 3, 4, 4, 4]
np.add.at(x, i, 1) 		#输出x:[0. 0. 1. 2. 3. 0. 0. 0. 0. 0.],内含3个重复值
# at()函数在这里对给定的操作,给定的索引,给定的值执行就地操作
# 类似方法:reduceat()函数

八、数组的排序

  1. 快速排序
# 算法复杂度O[NlogN]

# 不修改原始数组的基础上返回一个排好序的数组
np.sort(x)

# 用排好序的数组替代原始数组
x.sort()

# 函数argsort返回的是原始数组排好序的索引值
i = np.argsort(x)
# 索引值可用于通过花哨索引创建有序数组
x[i] 	#结果等同np.sort(x)

# 沿着多维数组的行或列排序(将行或列作为独立数组,行列值之间的关系将丢失)
np.sort(X, axis=0) 	#对X的每一列排序
np.sort(X, axis=1) 	#每一行排序
  1. 部分排序:分隔

不对整个数组进行排序,只需找到数组中第K小的值。

np.partition函数的输入是数组和数字K,输出一个新数组,最左边K个数是最小的K个值,往右是原始数组剩下的值,在这两个分隔区间中元素都是任意排列的。

x = np.array([7, 2, 3, 1, 6, 5, 4])
np.partition(x, 3)
# 可以沿着多维数组任意轴进行分隔
np.partition(X, 2, axis=1)

总结自《Python数据科学手册》

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章