NumPy
大约 11 分钟
NumPy
创建与类型
import numpy as np
# 处理数组
# 使用array() 方法创建一个数组 NumPy ndarray
# 可以把任何类似数组的对象传过去, 如列表、元组
# 底层用c实现的, 因此比内置的列表要快50倍
arr = np.array([1, 2, 3])
print(arr)
print(type(arr))
# [1 2 3]
# <class 'numpy.ndarray'>
维度
'''
维度
'''
# 0维 --- 表示一个元素, 直接把元素值传给
arr = np.array(1)
print(arr)
# 1维 --- 一维的数组
arr = np.array([1, 2, 3])
print(arr) # 1
# 2维
arr = np.array([[1, 2, 3], [4, 5, 6]])
'''
[[1 2 3]
[4 5 6]]
'''
print(arr)
print("###########")
# 检查数组有多少维: ndim 属性
a = np.array(42)
b = np.array([1, 2, 3, 4, 5])
c = np.array([[1, 2, 3], [4, 5, 6]])
d = np.array([[[1, 2, 3], [4, 5, 6]], [[1, 2, 3], [4, 5, 6]]])
print(a.ndim) # 0
print(b.ndim) # 1
print(c.ndim) # 2
print(d.ndim) # 3
# 更高维度的创建,ndmin 参数表示创建为几维数组,下面两个示例的结果是一样的
arr = np.array([[1, 2, 3, 4]], ndmin=5) # [[[[[1 2 3 4]]]]]
arr = np.array([1, 2, 3, 4], ndmin=5)
形状
'''
形状 Shape
'''
a = np.array(42)
b = np.array([1, 2, 3, 4, 5, 6])
c = np.array([[1, 2, 3], [4, 5, 6]])
d = np.array([[[1, 2, 3], [4, 5, 6]], [[1, 2, 3], [4, 5, 6]]])
e = np.array([[1, 2, 3, 4]], ndmin=5)
print(a.shape) # ()
print(b.shape) # (6,)
print(c.shape) # (2, 3)
print(d.shape) # (2, 2, 3)
print(e.shape) # (1, 1, 1, 1, 4)
# 重塑形状,入参为每个维度元素个数 --- 必须保证元素个数一样
# reshape方法 或者 shape 属性
b.shape = (2, 3)
arr = b.reshape(2, 3) # 1D -> 2D 两行三列
'''[[1 2 3]
[4 5 6]]
'''
print(arr)
arr = b.reshape(3, 1, 2) # 1D -> 3D
print(arr)
print(arr.base) # 可以发现reshape返回的是一个视图
# 未知 维元素个数, 传入-1会自动计算,但是最多只能有一个-1
arr = b.reshape(3, 1, -1)
print(arr.shape)
# 展平
d.reshape(-1)
d.flatten()
d.ravel()
# 压缩,去掉1个元素的维度
d.squeeze()
## 转置
arr.T
arr.transpose()
索引
'''
索引
'''
arr = np.array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9],
[8, 5, 2]])
print(arr[0]) # [1 2 3]
print(arr[0] + arr[1]) # [5 7 9] 矩阵的加法
print(arr[0, 1]) # 2 访问第一维度的第二个元素
print(arr[1, 2]) # 6 访问第二维度的第三个元素
print(arr[-1, -1]) # 2 最后一维度的最后一个元素
切片
'''
切片
'''
print(arr[1:4:2]) # 第二个元素到第四个元素,步长为2
print(arr[1:4:2, 2]) # 第二个元素到第四个元素 的第三个元素,步长为2,
print(arr[1:4:2, 0:2]) # 第二个元素到第四个元素 的第一个到第二个元素,步长为2,
数据类型
'''
数据类型
NumPy 有一些额外的数据类型,并通过一个字符引用数据类型。
l-整数 bool-布尔 u-无符号整数 f-浮点
c-复合浮点数 m-timedelta M-datetime O-对象
S-字符串 U-unicode字符串 V-固定的其他类型的内存块(void)
使用 dtype 属性检查数据类型
'''
arr = np.array([1, 2, 3, 4])
print(arr.dtype) # int64
arr = np.array(['111', '2', '3', '4'])
print(arr.dtype) # <U3 三字符
# 按类型创建
arr = np.array([1, 2, 3, 4], dtype='S')
print(arr) # [b'1' b'2' b'3' b'4']
print(int(arr[0] + arr[1])) # 12
arr = np.array([1, 2, 3, 4], dtype='i4')
print(arr.dtype) # int32
# 转换类型
arr = np.array([1, 2, 3, 4])
arr1 = arr.astype('S')
print(arr1)
arr = np.array([1.1, 2.2, 3.3, 4.4])
arr1 = arr.astype('i')
arr1 = arr.astype(int)
print(arr1)
arr = np.array([0, 1.1, 2.2, 3.3, 4.4])
arr1 = arr.astype('bool')
arr1 = arr.astype(bool)
print(arr1)
arr2 = arr1.astype(int)
print(arr2)
where
'''搜索'''
arr = np.array([1, 2, 1, 4, 5, 1])
print(np.where(arr == 1)) # (array([0, 2, 5]),)
print(np.where(arr % 2 == 1)) # (array([0, 2, 4, 5]),)
'''
搜索排序
有一个名为 searchsorted() 的方法,该方法在数组中执行二进制搜索,并返回将在其中指定值以维持搜索顺序的索引。
假定searchsorted()方法用于排序数组。
left
a[i-1]<v<=a[]
right
a[i-1]<=v<a[i]
'''
arr = np.array([6, 8, 9, 15])
# 返回第一个≥此值的索引
print(np.searchsorted(arr, 10)) # 3
# 并返回第一个>此值的索引
print(np.searchsorted(arr, 6, side='right')) # 1
# 多个值
print(np.searchsorted(arr, [6, 7, 8])) # [0 1 1]
'''排序'''
arr = np.array([16, 8, 9, 15])
print(np.sort(arr))
arr = np.array([[16, 8], [5, 1]])
'''[[ 8 16]
[ 1 5]]
'''
print(np.sort(arr))
arr = np.array([16, 8, 9, 15])
x = [True, True, False, True]
print(arr[x]) # [16 8 15]
print(arr[arr > 10]) # [16 15]
创建方式
## range
np.arange() # 0-1
np.arange(10) # 0-9
np.arange(0,10,2) # 0,2,4,6,8
np.arange(0,10,2,dtype=np.float32)
## 等差
np.linspace(0,10,5) ## 从0到10,共5个数,注意:左闭右闭
## 对数,默认以10为底
np.logspace(0,1,5) # 10的0次幂,到10的1次幂,共5个数,注意:左闭右闭
## 随机
np.random.rand(2,3)
np.random.randint(10,(2,3)) # 10为最大值
# 种子
np.random.seed(100)
# 正态分布
mu,sigma = 0, 0.1
x = np.random.normal(mu, sigma, 10)
# 保留小数
np.set_printoptions(precision=2)
# 洗牌
np.random.shuffle(arr)
## 网格
x = np.linspace(2, 10, 5)
y = np.linspace(2, 10, 5)
x, y = np.meshgrid(x, y)
print(x)
'''
[[ 2. 4. 6. 8. 10.]
[ 2. 4. 6. 8. 10.]
[ 2. 4. 6. 8. 10.]
[ 2. 4. 6. 8. 10.]
[ 2. 4. 6. 8. 10.]]
'''
print(y)
'''
[[ 2. 2. 2. 2. 2.]
[ 4. 4. 4. 4. 4.]
[ 6. 6. 6. 6. 6.]
[ 8. 8. 8. 8. 8.]
[10. 10. 10. 10. 10.]]
'''
## 向量
np.r_[0:10:1] # 行向量
np.c_[0:10:1] # 列向量
## 0矩阵
np.zeros((2,3))
np.zeros_like(a) # 创建一个和a相同形状的0矩阵
## 1矩阵
np.ones((2,3))
## 单位矩阵
np.eye(3)
## 空矩阵
a = np.empty((2,3))
a.fill(5) # 填充5
副本与视图
'''
副本与视图
副本和数组视图之间的主要区别在于副本是一个新数组,而视图只是原始数组的视图;
副本拥有数据,对副本所做的任何更改都不会影响原始数组;
视图不拥有数据,对视图所做的任何更改都会影响原始数组。
'''
arr = np.array([1, 2, 3, 4])
arr1 = arr.copy()
arr2 = arr.view()
# 检查是副本还是视图
print(arr1.base) # 副本返回None
print(arr2.base) # 视图返回原数组
运算
轴:轴数和数组的维度相同,轴的索引从0开始。
求和:np.sum() 或 arr.sum() 对应位置乘积:np.prod() 或 arr.prod() 平均值:np.mean() 或 arr.mean() 标准差:np.std() 或 arr.std() 方差:np.var() 或 arr.var() 众数:np.median() 或 arr.median() 协方差:np.cov() 或 arr.cov() 最大值:np.max() 或 arr.max() 最小值:np.min() 或 arr.min() 绝对值:np.abs() 或 arr.abs() 最小值索引:np.argmin() 或 arr.argmin() 最大值索引:np.argmax() 或 arr.argmax() 限制:np.clip() 或 arr.clip() 如arr.clip(0, 5),小于0的元素变为0,大于5的元素变为5 四舍五入:np.round() 或 arr.round(),decimals 为小数点位数
矩阵乘法:np.dot() 或 arr.dot() 或 a * b 逻辑运算:
- a == b
- np.logical_and() 或 arr.logical_and()
- np.logical_or() 或 arr.logical_or()
- np.logical_not() 或 arr.logical_not()
arr = np.array([[1, 2, 3],
[4, 5, 6]])
np.sum(arr) # 21 全部求和
# 对某个轴求和,看形状 (2, 3), 去掉当前轴索引后,就是求和后的形状
np.sum(arr, axis=0) # [ 5 7 9 ] 去掉2,就是3,形状为(3) ,即arr[0]+arr[1]
np.sum(arr, axis=1) # [ 6 15] 去掉3,就是2,形状为(2) ,即arr[:, 0] + arr[:, 1] + arr[:, 2]
## shape (2,2,3)
arr = np.array([
[
[1, 2, 3],
[4, 5, 6]],
[
[1, 2, 3],
[4, 5, 6]]])
arr.sum(axis=0) # [[ 2 4 6] [ 8 10 12]],即 arr[0] + arr[1]
arr.sum(axis=(0, 1)) # [10 14 18], 即 arr[0, 0] + arr[0, 1] + arr[1, 0] + arr[1, 1])
arr.sum(axis=(1, 2)) # [21 21] 即 arr[:, 0, 0] + arr[:, 0, 1] + arr[:, 0, 2] + arr[:, 1, 0] + arr[:, 1, 1] + arr[:, 1, 2]
排序
不太方便,pandas更方便 直接改变原数组 轴默认为-1,即最后一个轴
arr = np.array([[9, 2, 3],
[4, 1, 6]])
arr.sort()
arr.argsort() ## [[1 2 0] [1 0 2]] 返回排序后的索引
arr.searchsorted([1, 2, 3]) # 返回向有序数组中插入新数组元素的插入位置
## 第三列升序,相同时第一列降序(从后往前排,从最后一个规则开始)
index = np.lexsort([-1*arr[:,0],arr[:,2]])
print(arr[index])
文件操作
%%writefile test.txt
1 2 3
4 5 6
## 读取,skiprows跳过几行,usecols=(0,1,4)只读取指定的列
arr = np.loadtxt('test.txt', dtype=np.int32, delimiter=' ',skiprows=1)
## 保存
np.savetxt('test.txt', arr, fmt='%d', delimiter=' ')
np.save('test.npy', arr) # 用UE打开
# 加载
np.load('test.npy')
np.savez('test.npz', a=arr1, b=arr2) # 保存多个数组,压缩文件,每个是npy文件
data = np.load('test.npz')
data['a']
data['b']
迭代
'''
迭代
'''
arr = np.array([[[1, 2, 3], [4, 5, 6]], [[1, 2, 3], [4, 5, 6]]])
for x in np.nditer(arr):
# print(x)
pass
'''
使用op_dtypes参数,并传递期望的数据类型,以在选代时更改元素的数据类型
NumPy不会就地更改元素的数据类型(元素位于数组中),因此它需要一些其他空间来执行此操作,该额外空间称为buffer,为了在nditer(中
启用它,我们传参flags=['buffered']。
'''
for x in np.nditer(arr, flags=['buffered'], op_dtypes=["S"]):
# print(x)
pass
# 需要索引用 ndenumerate() 进行枚举选代
for i, x in np.ndenumerate(arr):
# print(i, x) # 格式为 (1, 1, 2) 6
pass
连接
'''
数组的连接
我们传递了一系列要与轴一起连接到 concatenate()函数的数组。如果未显式传递轴,则将其视为0。
- 第一个参数为数组的元组
- axis 参数连接轴,默认0,即把一维的元素上进行合并
'''
a = np.array([[1, 2], [6, 7]])
b = np.array([[3, 4], [5, 8]])
arr = np.concatenate((a, b))
'''
[[1 2]
[6 7]
[3 4]
[5 8]] (4, 2)
'''
print(arr, arr.shape)
# 沿着行 axis=1 连接,即把二维的元素上进行合并
arr = np.concatenate((a, b), axis=1)
'''
[[1 2 3 4]
[6 7 5 8]] (2, 4)
'''
print(arr, arr.shape)
'''
堆栈与级联相同,唯一的不同是堆栈是沿着新轴完成的。
我们可以沿着第二个轴连接两个一维数组,这将导致它们彼此重叠,即,堆叠(stacking)。
我们传递了一系列要与轴一起连接到concatenate()方法的数组。如果未显式传递轴,则将其视为0。
'''
a = np.array([[1, 2], [6, 7]])
b = np.array([[3, 4], [5, 8]])
arr = np.stack((a, b))
'''
[[[1 2]
[6 7]]
[[3 4]
[5 8]]] (2, 2, 2)
'''
print(arr, arr.shape)
a = np.array([[1, 2], [6, 7]])
b = np.array([[3, 4], [5, 8]])
arr = np.stack((a, b), axis=1)
'''
[[[1 2]
[3 4]]
[[6 7]
[5 8]]] (2, 2, 2)
'''
print(arr, arr.shape)
# 沿着行, 同 arr = np.concatenate((a, b), axis=1)
a = np.array([[1, 2], [6, 7]])
b = np.array([[3, 4], [5, 8]])
arr = np.hstack((a, b))
'''
[[1 2 3 4]
[6 7 5 8]] (2, 4)
'''
print(arr, arr.shape)
# 沿着列, 同 arr = np.concatenate((a, b))
a = np.array([[1, 2], [6, 7]])
b = np.array([[3, 4], [5, 8]])
arr = np.vstack((a, b))
'''
[[1 2]
[6 7]
[3 4]
[5 8]] (4, 2)
'''
print(arr, arr.shape)
# 沿着高,
a = np.array([[1, 2], [6, 7]])
b = np.array([[3, 4], [5, 8]])
arr = np.dstack((a, b))
'''
[[[1 3]
[2 4]]
[[6 5]
[7 8]]] (2, 2, 2)
'''
print(arr, arr.shape)
'''
拆分
'''
a = np.array([1, 2, 6, 7])
arr = np.array_split(a, 2)
print(arr) # [array([1, 2]), array([6, 7])]
a = np.array([1, 2, 6, 7])
arr = np.array_split(a, 3)
print(arr) # [array([1, 2]), array([6]), array([7])]
a = np.array([[1, 2], [6, 7]])
arr = np.array_split(a, 3)
print(arr) # [array([[1, 2]]), array([[6, 7]]), array([], shape=(0, 2), dtype=int64)]
a = np.array([[1, 2], [6, 7]])
arr = np.array_split(a, 2, axis=1)
'''
[array([[1],
[6]]), array([[2],
[7]])]
'''
print(arr)
print(333333333333333333)
练习题
# 构造一个全零的矩阵,并打印其占用的内存大小
a = np.zeros(5)
print(f'{a.size * a.itemsize} byte')
# 打印一个函数的帮助文档,比如numpy.add
print(help(np.info(np.add)))
# 创建一个10-49的数组,并将其倒序排列
np.arange(10, 50)[::-1]
# 找到一个数组中不为0的索引
a = np.nonzero([1, 2, 3, 4, 5, 6, 7, 8, 9, 0])
# 随机构造一个3*3矩阵,并打印其中最大与最小值
a = np.random.randint(0, 100, (3, 3))
print(a.max(), a.min())
# 构造一个5*5的矩阵,令其值都为1,并在最外层加上一圈0
a = np.ones((5, 5))
np.pad(a, pad_width=1, mode='constant', constant_values=0)
# 构建一个shape为(6,7,8)的矩阵,并找到第100个元素的索引值
np.unravel_index(100, (6, 7, 8)) ## (1,5,4)
# 对一个5*5的矩阵做归一化操作
a = np.random.rand(5, 5)
a_max = a.max()
a_min = a.min()
a = (a - a_min) / (a_max - a_min)
# 找到两个数组中相同的值
z1 = np.random.randint(0, 10, 10)
z2 = np.random.randint(0, 10, 10)
np.intersect1d(z1, z2)
# 得到今天明天昨天的日期
today = np.datetime64('today')
yesterday = np.datetime64('today') - np.timedelta64(1, 'D')
tomorrow = np.datetime64('today') + np.timedelta64(1, 'D')
# 得到一个月中所有的天
np.arange('2019-01', '2019-02', dtype='datetime64[D]')
# 得到一个数的整数部分
z = np.random.uniform(0, 10,4) # 均匀分布,0-10之间,4个数
np.floor(z)
# 构造一个数组,让它不能被改变
z = np.ones(10)
z.flags.writeable = False
z[0] = 12 # 报错
# 打印大数据的部分值,全部值
np.set_printoptions(threshold=5)
np.set_printoptions(threshold=np.inf)
# 找到在一个数组中,最接近一个数的索引
z = np.arange(100)
v = np.random.uniform(0, 100)
index = (np.abs(z - v)).argmin()
z[index]
# 32位float类型和32位int类型转换
z = np.arange(10,dtype=np.int32).astype(np.float32)
# 打印数组元素位置坐标与数值
z= np.arange(9).reshape(3,3)
for idx,value in np.ndenumerate(z):
print(idx,value)
# 按照数组的某一列进行排序
z = np.random.randint(0,10,(3,3))
print(z)
print(z[z[:,1].argsort()])
# 统计数组中每个数值出现的次数
z = np.array([1,1,2,3,4,5,6,7,8,9,10])
np.bincount(z)
# 如何对一个四维数组的最后两维来求和
z = np.random.randint(0,10,(3,3,3,3))
z.sum(axis=(-1,-2))
# 交换矩阵中的两行
z = np.arange(9).reshape(3,3)
z[[0,1]] = z[[1,0]]
# 交换两列
z[:,[0,1]] = z[:,[1,0]]
# 找到一个数组中最常出现的数字
z = np.random.randint(0,10,10)
np.bincount(z).argmax()
# 快速查找TOPK
z = np.arange(1000)
np.random.shuffle(z)
n = 5
z[np.argpartition(-z,n)[:n]]
# 去除掉一个数组中,所有元素都相同的数据
z = np.random.randint(0,3,(10,3))
print(z)
print(np.all(z[:, 1:] == z[:, :-1], axis=1))
