Python科学计算模块NumPy学习笔记

23次阅读
没有评论

共计 6019 个字符,预计需要花费 16 分钟才能阅读完成。

基本介绍

NumPy:Numerical Python 的缩写,提供了底层基于 C 语言实现的数值计算库,与 Python 内置的 list 数据结构相比,其支持更加规范的数据类型和极其丰富的操作接口,速度也更快。

安装 NumPy

NumPy 是第三方库,所以在使用前必须先安装 NumPy。可以使用 pip 命令安装:pip install numpy

安装完就可以写 NumPy 代码了。一般流程是先import numpy,为了后续调用方便,通常在 import 完之后,还给它一个缩写形式as np

创建 NumPy 数组 ndarray

NumPy 默认 ndarray 所有元素的类型是相同的。如果传进来的列表中包含不同的类型,则统一为同一类型,优先级:str > float > int。

使用 np.array()

import numpy as np

n = np.array([1, 2, 3])
print(n.shape)  # 形状:(3,)

使用 np.ones()

创建一个所有元素都为 1 的多维数组。

n = np.ones((3, 2), dtype=np.int8)  # 默认是 float 类型
print(n.shape)  # 形状:(3, 2)

创建一个所有元素都为 0 的多维数组,使用 np.zeros()。

创建一个所有元素都为指定元素的多维数组,使用 np.full():

n = np.full((3, 2), fill_value=6)
print(n)
# 输出:# [[6 6]
#  [6 6]
#  [6 6]]

使用 np.eye()

创建一个单位矩阵:主对角线都是 1,其他都是 0 的二维数组。

n = np.eye(5, 5, dtype=np.int8)
print(n)
# 输出:# [[1 0 0 0 0]
#  [0 1 0 0 0]
#  [0 0 1 0 0]
#  [0 0 0 1 0]
#  [0 0 0 0 1]]

# k= 1 向右偏移 1 个位置,k=- 1 向左偏移 1 个位置
n = np.eye(5, 5, k=1, dtype=np.int8)
print(n)
# [[0 1 0 0 0]
#  [0 0 1 0 0]
#  [0 0 0 1 0]
#  [0 0 0 0 1]
#  [0 0 0 0 0]]

使用 np.linspace()

创建一个等差数列。参数说明:

  • start: 开始值
  • stop: 结束值
  • num=50: 等差数列中默认有 50 个数
  • endpoint=True: 是否包含结束值
  • retstep=False: 是否返回等差值(步长)
  • dtype=None: 元素类型
n = np.linspace(0, 10, num=6, dtype=np.int8)
print(n)  # [0  2  4  6  8 10]

使用 np.arange()

创建一个数值范围的数组,和 Python 中的 range 功能类似。

n = np.arange(10)
print(n)  # [0 1 2 3 4 5 6 7 8 9]
n = np.arange(2, 10)
print(n)  # [2 3 4 5 6 7 8 9]
n = np.arange(2, 10, 2)
print(n)  # [2 4 6 8]

使用 np.random.randint()

创建一个随机整数的多维数组。

import numpy as np
import matplotlib.pyplot as plt

n = np.random.randint(3)
print(n)  # 随机范围:[0, 3)
n = np.random.randint(3, 10)
print(n)  # 随机范围:[3, 10)
n = np.random.randint(3, 10, size=5)
print(n)  # 一维
n = np.random.randint(3, 10, size=(2, 3))
print(n)  # 二维

n = np.random.randint(0, 256, size=(20, 40, 3))
plt.imshow(n)  # 图像处理
plt.show()  # 图像显示

使用 np.random.randn()创建一个服从标准正态分布的多维数组:

n = np.random.randn()
print(n)
n = np.random.randn(5)
print(n)
n = np.random.randn(3, 4)
print(n)

使用 np.random.normal()创建一个服从正态分布的多维数组:

n = np.random.normal(loc=10, scale=1, size=(2, 3))
print(n)  # 均值:10,标准差:1,数组形状:2 行 3 列

使用 np.random.random()创建一个元素为 [0, 1) 随机数的多维数组:

n = np.random.random(size=(2, 3))
print(n)

使用 np.random.rand()也是创建一个元素为 [0, 1) 随机数的多维数组,只是参数传递方式不同,random.rand()接收分开的参数。

两个函数功能完全一样,NumPy 这么做可能是为了使 MATLAB 用户更容易学习 Python+NumPy 的组合。把其中一个函数去掉,所带来的麻烦远大于好处,因为有很多现存的代码使用了函数的不同版本。

数组属性

n = np.ones((3, 2), dtype=np.int8)
print(n.shape)  # 形状:(3, 2)
print(n.ndim)  # 维度:2
print(n.size)  # 总数据量:6
print(n.dtype)  # 元素类型:int8

基本操作

索引

n = np.array([1, 2, 3])
print(n[0], n[-1])  # 1 3
n = np.array([[1, 2, 3], [4, 5, 6]])
print(n[-1][-1], n[-1, -1])  # 6 6

切片

行切片:

n = np.array([1, 2, 3])
print(n[0:2])  # [1 2]
print(n[::-1])  # [3 2 1]

n = np.array([[1, 2], [3, 4], [5, 6]])
print(n[0])  # 取一行:[1 2]
print(n[0:2])
# 取连续行:# [[1 2]
#  [3 4]]

print(n[[0, 2]])
# 取不连续行:# [[1 2]
#  [5 6]]

列切片:

n = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
print(n[:, 0])  # 取一列,取所有行,第 0 列:[1 4 7]
print(n[:, 0:2])
# 取连续列:# [[1 2]
#  [4 5]
#  [7 8]]

print(n[:, [0, 2]])
# 取不连续列:# [[1 3]
#  [4 6]
#  [7 9]]

行翻转(上下翻转)和列翻转(左右翻转):

n = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
print(n[::-1])
# 行翻转
# [[7 8 9]
#  [4 5 6]
#  [1 2 3]]

print(n[:, ::-1])
# 列翻转
# [[3 2 1]
#  [6 5 4]
#  [9 8 7]]

数组变形

n = np.array([1, 2, 3, 4, 5, 6])
n2 = np.reshape(n, (2, 3))  # 2 行 3 列
n3 = n.reshape((2, 3))  # 2 行 3 列
n4 = n3.reshape(6)  # 变成一维,也可以写成 reshape(-1)
n5 = n.reshape(2, -1)  # - 1 表示任意剩余维度长度

数组合并

n1 = np.array([[1, 2, 3], [4, 5, 6]])
n2 = np.array([[7, 8, 9], [10, 11, 12]])
n3 = np.concatenate((n1, n2), axis=1)  # 默认上下合并,axis= 1 左右合并
n4 = np.hstack((n1, n2))  # 水平合并,即左右合并
n5 = np.vstack((n1, n2))  # 垂直合并,即上下合并

数组拆分

n = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
n2 = np.vsplit(n, 3)  # 垂直拆分,平均拆成 3 份,水平拆分 hsplit()
n3 = np.vsplit(n, (1,))  # 按照指定位置拆成
n4 = np.split(n, 3, axis=1)  # 默认垂直拆分,axis= 1 水平合并

数组排序

  • np.sort():不改变原数组,占内存空间
  • ndarray.sort():改变原数组,不多占内存空间
n = np.array([2, 44, 5, 3, 8])
n2 = np.sort(n)  # 默认 axis= 1 按行排序,axis= 0 按列排序
n.sort()
print(n, n2)

拷贝

n = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
n2 = n.copy()  # 深拷贝

聚合函数

n = np.array([[1, 2, 13], [4, 15, 6], [17, 8, 9]])

print(" 求和:", n.sum())
print(" 求和:", n.sum(axis=0))  # 每一列多行求和
n = np.array([1, 2, 3, np.nan])
print(np.nansum(n))  # 有 nan(not a number)值时,sum 无法求出和,要用 nansum,它会排除掉 nan 之后再求和

print(" 最小值:", n.min())
print(" 最大值:", n.max())
print(" 平均值:", n.mean())
print(" 中位数:", np.median(n))
print(" 百分位数:", np.percentile(n, 25))
print(" 极差:", n.ptp())

print(" 第一个最大值下标:", n.argmax())
print(" 按条件找到所有最大值下标:", np.argwhere(n == n.max()))

print("3 次方:", np.power(n, 3))

print(" 方差:", n.var())
print(" 标准差:", n.std())

print(" 对数:", np.log(n))

print(" 减法:", np.diff(n))  # 计算数组中相邻元素之间差值

print(" 符号:", np.sign(n))  # 值 >0,返回 1;值 <0,返回 -1;值 =0,返回 0

n = np.array([1, 2, 13])
weights = np.array([0.1, 0.2, 0.3])
print(" 加权平均:", np.average(n, weights=weights))

矩阵操作

算术运算

n = np.array([[11, 12, 13], [24, 15, 26], [17, 38, 39]])
print(n + 10)  # 加
print(n - 10)  # 减
print(n * 10)  # 乘
print(n / 10)  # 除
print(n // 10)  # 整除
print(n % 2)  # 余数
print(n**2)  # 次方

线性代数

矩阵积:第一个矩阵的列数 = 第二个矩阵的行数。

n1 = np.array([[1, 2, 3], [4, 5, 6]])
n2 = np.array([[1, 2], [3, 4], [5, 6]])
print(np.dot(n1, n2))

其他矩阵操作:

n = np.array([[1, 2], [4, 5]])
print(np.linalg.inv(n))  # 矩阵逆
print(np.round(np.linalg.det(n)))  # 矩阵行列式
print(np.linalg.matrix_rank(n))  # 矩阵的秩(满秩矩阵、奇异矩阵)

广播机制

ndarray 广播机制的两条规则:

  • 规则一:为缺失的维度补维度
  • 规则二:缺失元素用已有值填充
n1 = np.ones((2, 3), dtype=np.int8)
n2 = np.arange(3)
print(n1 + n2)
# 输出
# [[1 2 3]
#  [1 2 3]]

文件 IO 操作

数组保存和读取

NumPy 可以用二进制的格式保存数据。如果不想让别人看到数据,想使用 NumPy 时加载的话,那完全可以用这种方式来保存数据。

使用 save()来保存,保存的是一个以.npy 结尾的二进制文件。加载的时候,用 load()直接加载这个二进制数据文件。

row_string = "1, 10, 5, 2, 11, 22"
data = np.fromstring(row_string, dtype=np.int64, sep=",")
data = data.reshape(2, 3)
np.save("save_data.npy", data)

npy_data = np.load("save_data.npy")
print(npy_data)

NumPy 还可以使用 savez()将多个 array 保存到一个.npz 文件中。

train_data = np.array([1, 2, 3])
test_data = np.array([11, 22, 33])
np.savez("save_data.npz", train=train_data, test=test_data)

npz_data = np.load("save_data.npz")
print("train:", npz_data["train"])
print("test:", npz_data["test"])

用 savez()的时候,还有一个方法可以更节省空间,那就是用 savez_compressed()来做一次数据压缩。

np.savez_compressed("save_data.npz", train=train_data, test=test_data)

文本文件读写操作

data = np.array([1, 10, 5, 2, 11, 22])
np.savetxt("save_data.csv", data, delimiter=",", fmt="%s")

使用 np.loadtxt()就能自定义读取数据:

csv_data = np.loadtxt("save_data.csv", delimiter=",", dtype=np.int8)
print(csv_data)

loadtxt()传入的关键字参数:

  1. fname:文件名,数据类型为字符串
  2. delimiter:分隔符,数据类型为字符串
  3. usecols:读取列数,数据类型为元组, 其中元素个数有多少个,则选出多少列
  4. unpack:是否解包,数据类型为布尔。如果 True,读入属性将分别写入不同变量

高级函数

分段函数

简单分段,可以使用 where(condition, x, y),第一个参数表示条件,当条件成立时 where 方法返回 x,当条件不成立时 where 返回 y。

x = np.array([8, 9, -1, -6])
y = np.where(x > 0, x, np.abs(x))
print(y)  # [8 9 1 6]

分段数较多,可以用 select()。

x = np.array([8, 9, 0, -1, -6])
y = np.select([x < 0, x == 0, x > 0], [-1, 0, 1])
print(y)  # [1  1  0 -1 -1]

where()、select()函数的所有参数都需要在调用它们之前完成计算,在计算时还会产生许多保存中间结果的数组,因此如果输入的数组很大,将会发生大量内存分配和释放。

piecewise()解决了上述问题,它只计算需要计算的值。piecewise()是专门用于计算分段的函数。

x = np.array([8, 9, 5, 0, -1, -6])
y = np.piecewise(x, [x < 0, x == 0, x > 0], [-1, 0, 1])
print(y)  # [1  1  1  0 -1 -1]

正文完
post-qrcode
 0
三毛
版权声明:本站原创文章,由 三毛 于2023-08-16发表,共计6019字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
评论(没有评论)