python3之numpy库
Numpy 是一个开源的 Python 科学计算库,用于快速处理任意维度的数组。Numpy 支持常见的数组和矩阵操作,对于同样的数值计算任务,使用 NumPy 不仅代码要简洁的多,而且 NumPy 在性能上也远远优于原生 Python,至少是一到两个数量级的差距,而且数据量越大,NumPy 的优势就越明显。
NumPy 最为核心的数据类型是ndarray,使用ndarray可以处理一维、二维和多维数组,该对象相当于是一个快速而灵活的大数据容器。NumPy 底层代码使用 C 语言编写,解决了 GIL 的限制,ndarray在存取数据的时候,数据与数据的地址都是连续的,这确保了可以进行高效率的批量操作,性能上远远优于 Python 中的list;另一方面ndarray对象提供了更多的方法来处理数据,尤其获取数据统计特征的方法,这些方法也是 Python 原生的list没有的。
创建数组对象
import numpy as np
# 使用array函数,通过list创建数组对象
print(np.array((2, 3, 4))) # 类型为int32 的一维数组
print(np.array([2.0, 3.0, 4.0])) # 类型为flloat64 的一维数组
print(np.array([[2, 3, 4, 5], [4, 5, 6, 7]])) # 类型为int32 的多维数组
print(np.array([[1, 2], [3, 4]], dtype="float64")) # 指定多为数组类型
# 使用arange函数,指定取值范围和跨度创建数组对象
print(np.arange(10, 30, 5)) # 第三个参数为步长
print(np.arange(0, 2, 0.3))
# 使用linspace函数,用指定范围和元素个数创建数组对象,生成等差数列
print(np.linspace(0.2, 0.3, 9)) # 第三个参数为元素个数
# 使用logspace函数,生成等比数列
print(np.logspace(1, 10, num=10, base=2)) # 生成以2为底数的等比数列
# 通过fromstring函数从字符串提取数据创建数组对象
print(np.fromstring("1, 2, 3, 4, 5", sep=",", dtype="i8")) # [1 2 3 4 5]
# 通过fromiter函数从生成器(迭代器)中获取数据创建数组对象
def fib(how_many):
a, b = 0, 1
for _ in range(how_many):
a, b = b, a + b
yield a
gen = fib(20)
print(np.fromiter(gen, dtype="i8"))
# 使用numpy.random模块的函数生成随机数创建数组对象
print(np.random.rand(10)) # 产生 10 个[0,1)范围的随机小数
print(np.random.randint(1, 100, 10)) # 产生 10 个[1,100)范围的随机整数
print(np.random.normal(50, 10, 10)) # 产生 20 个μ=50 σ=10 的正态分布随机数
print(np.random.rand(3, 4)) # 产生[0,1)范围的随机小数构成的 3 行 4 列的二维数组
print(np.random.randint(1, 100, (3, 4, 5))) # 产生[1,100)范围的随机整数构成的三维数组
# 创建全0、全1或指定元素的数组
print(np.zeros((3, 4))) # 全为 0 的多维数组,默认类型flloat64
print(np.ones((3, 4))) # 全为 1 的多维数组,默认类型flloat64
print(np.empty((3, 4))) # 随机初始值 的多维数组,默认类型flloat64
print(np.full((3, 3), 2)) # 填充为某个值
# 使用eye函数创建单位矩阵
print(np.eye(4))
数组的属性
import numpy as np
# 数组的属性
arr = np.array([2, 3, 4, 5])
print(arr.ndim) # 获取数组的维度 1
print(arr.shape) # 获取数组的形状 (4,)
print(arr.size) # 获取数组元素个数 4
print(arr.dtype) # 获取数组元素的数据类型 int32
print(arr.itemsize) # 获取数组单个元素占用内存空间的字节数 4
print(arr.nbytes) # 获取数组所有元素占用内存空间的字节数 16
arr = np.array([(2, 3, 4, 5), (4, 5, 6, 7)])
print(arr.ndim) # 获取数组的维度 2
print(arr.shape) # 获取数组的形状 (2, 4)
print(arr.size) # 获取数组元素个数 8
print(arr.dtype) # 获取数组元素的数据类型 int32
print(arr.itemsize) # 获取数组单个元素占用内存空间的字节数 4
print(arr.nbytes) # 获取数组所有元素占用内存空间的字节数 32
数组索引
# 普通索引、切片索引
arr = np.arange(9)
print(arr) # [0 1 2 3 4 5 6 7 8]
print(arr[2]) # 2
print(arr[-2]) # 7
print(arr[2:5]) # [2 3 4]
print(arr[1:7:2]) # [1 3 5]
print(arr[::-1]) # 逆序
print(arr[np.array((2, 4, 6))]) # [2 4 6] 使用数组来索引
arr.shape = (3, 3) # 等同于 arr = arr.reshape(3,3)
print(arr[1, 2]) # 5 推荐使用
print(arr[1, -1]) # 5 推荐使用
print(arr[0][1]) # 1 不推荐使用,效率较低
print(arr[0]) # [0 1 2] 返回数组的第1行
print(arr[:2]) # [[0 1 2] [3 4 5]] 返回数组的前2行
print(arr[[0, 2]]) # [[0 1 2] [6 7 8]] 返回指定的第1行和第3行
print(arr[:, 0]) # [0 3 6] 返回数组的第1列
print(arr[:, [0, 2]]) # [[0 2] [3 5] [6 8]] 返回数组的第1列和第3列
print(arr[np.array([0, 1]), np.array([0, 2])]) # [0 5]
# 布尔索引:布尔索引就是通过保存布尔值的数组充当一个数组的索引,布尔值为True的元素保留,布尔值为False的元素不会被选中。
b = arr % 2 == 0
print(b) # [[ True False True] [False True False] [ True False True]]
print(arr[b]) # [0 2 4 6 8]
print(arr[np.array([True, False, True])]) # [[0 1 2] [6 7 8]] 返回所有为True的对应行
c = np.array(["A", "B", "C"])
print(arr[c == "A"]) # [[0 1 2]]
print(arr[(c == "A") | (c == "C")][:, [0, 2]]) # [[0 2] [6 8]]
# 花式索引:花式索引是用保存整数的数组充当一个数组的索引,这里所说的数组可以是 NumPy 的ndarray,也可以是 Python 中list、tuple等可迭代类型,可以使用正向或负向索引。
print(arr[[2, 0, 1]]) # [[6 7 8] [0 1 2] [3 4 5]] 按照指定顺序返回指定行
print(arr[[2, 0, 1]][:, [0, 2, 1]]) # [[6 8 7] [0 2 1] [3 5 4]]返回指定的行与列
print(arr[np.ix_([2, 1], [0, 2])]) # [[6 8] [3 5]] 返回指定的行与列
数组运算
# 数组跟标量的运算
arr = np.arange(1, 10)
print(arr + 10) # [11 12 13 14 15 16 17 18 19]
print(arr * 10) # [10 20 30 40 50 60 70 80 90]
print(arr > 5) # [False False False False False True True True True]
# 数组跟数组的运算 要求两个数组的形状(shape属性)要相同
arr2 = np.array([1, 1, 1, 2, 2, 2, 3, 3, 3])
print(arr1 + arr2) # [ 2 3 4 6 7 8 10 11 12]
print(arr1 ** arr2) # [ 1 2 3 16 25 36 343 512 729]
print(arr1 % arr2 == 0) # [ True True True True False True False False True]
NumPy 中的广播机制
NumPy 中,各种运算默认都是“逐元素”进行的。
在 NumPy 的广播机制中,有一个很重要的概念叫做“相容的形状”。只有当两个数组具有“相容的形状”时,“广播”才能起作用;
所谓“相容的形状”,指的是参与运算的这两个数组各个维度要么相等;要么其中一个数组的对应维度为 1(不存在的维度也是 1)。
而 NumPy 比较各个维度的顺序是从后往前,一次比较,就相当于把参与运算的数组形状右对齐,然后若相等就再往前看,若其中一个为 1 就将其在这个维度上扩展到更高的维度,直到第一个维度。
简单的说,只有两个数组后缘维度相同或者后缘维度不同但其中一个数组后缘维度为1时,广播机制才会被触发。通过广播机制,NumPy 将两个原本形状不相同的数组变成形状相同,才能进行二元运算。
所谓后缘维度,指的是数组形状(shape属性)从后往前看对应的部分
# 两个数组形状不同时的运算
a = np.array([[2, 3, 4, 5], [6, 7, 8, 9]])
b = np.array([1, 2, 3, 5])
print(a + b) # [[ 3 5 7 10] [ 7 9 11 14]] 后缘维度相同
c = np.array([[2], [3]])
print(a + c) # [[ 4 5 6 7] [ 9 10 11 12]]
print(b + c) # [[3 4 5 7] [4 5 6 8]]
常用函数
import numpy as np
# 数学函数
a = np.array([0, 30, 45, 60, 90])
sin = np.sin(a * np.pi / 180)
cos = np.cos(a * np.pi / 180)
tan = np.tan(a * np.pi / 180)
print(sin, cos, tan)
arcsin = np.arcsin(sin)
arccos = np.arccos(cos)
arctan = np.arctan(tan)
print(np.degrees(arcsin), np.degrees(arccos), np.degrees(arctan))
a = np.array([1, 2.0, 30.12, 129.567])
print(np.around(a)) # 四舍五入
print(np.around(a, decimals=1)) # 指定一位小数四舍五入
print(np.round(a)) # 四舍五入
print(np.round(a, decimals=1)) # 指定一位小数四舍五入
print(np.floor(a)) # 向下取整
print(np.ceil(a)) # 向上取整
a = np.arange(6, dtype=np.float_).reshape(2, 3)
b = np.array([2, 2, 2])
print(np.add(a, b)) # 加
print(np.subtract(a, b)) # 减
print(np.multiply(a, b)) # 乘
print(np.divide(a, b)) # 除
print(np.power(a, b)) # 幂
print(np.floor_divide(a, b)) # 整除
print(np.mod(a, b)) # 模
print(np.maximum(a, b)) # 两两比较元素获取最大值
print(np.minimum(a, b)) # 两两比较元素获取最小值
print(np.fmax(a, b)) # 获取最大值(忽略NaN)
print(np.fmin(a, b)) # 获取最小值(忽略NaN)
print(np.add.reduce(a)) # 每列的合计值
print(np.add.reduce(a, axis=1)) # 每行的合计值
print(np.multiply.reduce(a)) # 每列的乘积
print(np.add.accumulate(a)) # 每列的合计值,并存储计算中每步计算结果
a = np.array([1, 4, 9])
print(a**2) # 计算每个元素的平方
print(np.sqrt(a)) # 计算每个元素的平方根
print(np.exp(a)) # 计算每个元素的指数值
print(np.log(a)) # 计算每个元素的自然对数值
print(np.abs(a)) # 计算每个元素的绝对值
# 统计函数
a = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
print(np.sum(a)) # 45 计算所有元素的和
print(np.sum(a, axis=0)) # [12 15 18] 对每一列求和
print(np.sum(a, axis=1)) # [ 6 15 24] 对每一行求和
print(np.prod(a)) # 计算所有元素的积
print(np.cumsum(a)) # [ 1 3 6 10 15 21 28 36 45] 对每一个元素求累积和
print(np.cumsum(a, axis=0)) # [[ 1 2 3] [ 5 7 9] [12 15 18]] 计算每一列的累积和,并返回二维数组
print(np.cumsum(a, axis=1)) # [[ 1 3 6] [ 4 9 15] [ 7 15 24]] 计算每一行的累积和,并返回二维数组
print(np.cumprod(a)) # 对每一个元素求累积积
print(np.max(a)) # 计算所有元素的最大值
print(np.min(a)) # 计算所有元素的最小值
print(np.amin(a)) # 1
print(np.amin(a, axis=0)) # [1 2 3] 0轴最小值
print(np.amax(a, axis=1)) # [3 6 9] 1轴最大值
print(np.ptp(a)) # 8 计算数组中元素最大值与最小值的差
print(np.ptp(a, axis=1)) # [2 2 2]
print(np.percentile(a, 50)) # 5.0 百分位数
print(np.percentile(a, 50, axis=1)) # [2. 5. 8.] 百分位数
print(np.quantile(a, 0.5)) # 5.0 分位数
print(np.quantile(a, 0.5, axis=1)) # [2. 5. 8.] 分位数
print(np.median(a)) # 5.0 中位数
print(np.median(a, axis=1)) # [2. 5. 8.] 中位数
print(np.mean(a)) # 5.0 算术平均值
print(np.mean(a, axis=1)) # 5.0 算术平均值
print(np.average(a)) # [2. 5. 8.] 加权平均值
print(np.average(a, weights=a)) # 6.333333333333333 加权平均值
print(np.average(a, weights=a, returned=True)) # (6.333333333333333, 45.0) 加权平均值
print(np.var(a)) # 6.666666666666667 方差
print(np.std(a)) # 2.581988897471611 标准差
字符串函数
import numpy as np
# NumPy 字符串函数
print(np.char.add(["hello"], [" world"])) # ['hello world']
print(np.char.add(["hello", "hi"], [" world", " lily"])) # ['hello world' 'hi lily']
print(np.char.multiply("hello ", 3)) # hello hello hello
print(np.char.multiply(["hello", "hi"], 3)) # ['hellohellohello' 'hihihi']
print(np.char.center("hello", 7, fillchar="*")) # *hello*
print(np.char.center(["hello", "hi"], 6, fillchar="*")) # ['hello*' '**hi**']
print(np.char.ljust([2023, 2024], 5, "年")) # ['2023年' '2024年']
print(np.char.capitalize("hello")) # Hello
print(np.char.title("i love china")) # I Love China
print(np.char.lower("GOOGLE")) # google
print(np.char.upper("google")) # GOOGLE
print(np.char.split("do you love china?")) # ['do', 'you', 'love', 'china?']
print(np.char.split("yes,i do", sep=",")) # ['yes', 'i do']
print(np.char.splitlines("I\rLove China")) # ['I', 'Love China'] 用换行符作为分隔符来分割字符串
print(np.char.splitlines("I\nLove China")) # ['I', 'Love China']
print(np.char.splitlines("I\r\nLove China")) # ['I', 'Love China']
print(np.char.expandtabs("i\tlove\tchina", 3)) # i love china 将字符串里面的 \t 转换成 N 个 tab
print(np.char.strip("it love china", "i")) # t love china
print(np.char.strip(["it", "love", "china"], "i")) # ['t' 'love' 'china']
print(np.char.lstrip(" china")) # china
print(np.char.rstrip("china ")) # china
print(np.char.join(":", "apple")) # a:p:p:l:e
print(np.char.join([":", "-"], ["apple", "pear"])) # ['a:p:p:l:e' 'p-e-a-r']
print(np.char.partition("apple", "p")) # ['a' 'p' 'ple']
print(np.char.partition(["apple", "pear"], ["p", "p"])) # [['a' 'p' 'ple'] ['' 'p' 'ear']]
print(np.char.replace("i love china", "ov", "ik")) # i like china
print(np.char.encode("中文", "utf-8")) # b'\xe4\xb8\xad\xe6\x96\x87'
a = np.char.encode("中文", "utf-8")
print(np.char.decode(a, "utf-8")) # 中文
功能函数
import numpy as np
arr = np.arange(1, 10)
arr2 = np.array([1, 1, 1, 2, 2, 2, 3, 3, 3])
a = np.array([[2, 3, 4, 5], [6, 7, 8, 9]])
b = np.array([[2], [3]])
c = np.array([[3, 7, 12, 5], [9, 5, 0, 3]])
d = np.array([1, 2])
# 副本
print(arr[3:].copy()) # 避免修改原始数组
# 去重(重复元素只保留一项)
print(np.unique(c)) # [ 0 3 5 7 9 12] 计算唯一元素,并返回有序结果
# 堆叠和拼接
print(np.hstack((a, b))) # [[2 3 4 5 2] [6 7 8 9 3]] 横向拼接两个数组,但必须满足两个数组的行数相同
print(np.vstack((arr, arr2))) # [[1 2 3 4 5 6 7 8 9] [1 1 1 2 2 2 3 3 3]] 纵向拼接两个数组,但必须满足两个数组的列数相同
print(np.concatenate((a, b), axis=1)) # [[2 3 4 5 2] [6 7 8 9 3]]
print(np.concatenate((a, c), axis=0)) # [[ 2 3 4 5] [ 6 7 8 9] [ 3 7 12 5] [ 9 5 0 3]]
# 追加和插入元素
print(np.append(arr, [10])) # [1 2 3 4 5 6 7 8 9 10]
print(np.insert(arr, 0, [0])) # [0 1 2 3 4 5 6 7 8 9]
# 依据条件过滤数据
print(np.extract(arr % 2 != 0, arr)) # [1 3 5 7 9]
print(np.select([arr <= 3, arr >= 7], [arr * 10, arr**2])) # [10 20 30 0 0 0 49 64 81]
print(np.where(arr <= 5, arr * 10, arr**2)) # [10 20 30 40 50 36 49 64 81]
# 重复数组元素创建新数组
print(np.repeat(d, 3)) # [1 1 1 2 2 2]
print(np.tile(d, 2)) # [1 2 1 2]
# 调整数组大小
print(np.resize(arr, (3, 3))) # [[1 2 3] [4 5 6] [7 8 9]]
# 替换数组元素,在原来的数组上直接进行替换
np.put(arr2, [1, 2], [2, 3])
print(arr2) # [1 2 3 2 2 2 3 3 3]
np.place(arr2, arr2 > 2, [1, 2])
print(arr2) # [1 2 1 2 2 2 2 1 2]
# 多维数组降为一维数组 生成的原数组的视图,无需占有内存空间,但视图的改变会影响到原数组的变化。
print(a.ravel()) # [2 3 4 5 4 5 6 7]
# 多维数组降为一维数组 flatten方法返回的是真实值,其值的改变并不会影响原数组的更改
print(a.flatten()) # [2 3 4 5 4 5 6 7]
# 重整多维数组的大小,reshape还允许缺省 1 个参数(用-1占位),它会根据数组元素的总数和提供的其他参数自动求出一个合适的值
print(np.arange(12).reshape(2, 6))
print(np.arange(12).reshape(2, 3, 2))
print(np.arange(12).reshape(2, -1, 2))
# 返回数组的转置结果
print(a.T)
# 沿横轴分割数组
print(np.hsplit(arr, 3)) # [array([1, 2, 3]), array([4, 5, 6]), array([7, 8, 9])]
# 沿纵轴分割数组
print(np.vsplit(a, 2)) # [array([[2, 3, 4, 5]]), array([[6, 7, 8, 9]])]
# 将数组转换为列表
print(arr.tolist())
# 强制转换数组的数据类型
print(arr.astype(float))
# 将数组对象写入文件中
arr.tofile("test.txt", sep=",")
# 保存数组到二进制文件中,通过 NumPy 中的load()函数从保存的文件中加载数据创建数组
arr.dump("data")
print(np.load("data", allow_pickle=True))
# 检查数据元素是否为空
print(np.isnan(a)) # 返回布尔数组,NaN对应True,非NaN对应False
# 排序函数 排序算法:quicksort:快速排序,mergesort:归并排序,heapsort:堆排序,stable:冒泡排序
a = np.array([[3, 7, 12, 45], [9, 1, 0, 34]])
print(np.sort(a)) # 默认快速排序quicksort
print(np.sort(a, axis=0))
print(np.sort(a, kind="heapsort"))
print(np.sort(a, kind="mergesort"))
# 部分排序
print(np.partition(a, 2, axis=1)) # 只针对数组的特定部分排序
# 按照字段排序
dt = np.dtype([("name", "S10"), ("age", int)])
c = np.array([("lily", 21), ("rose", 25), ("daisy", 17), ("jane", 27)], dtype=dt)
print(np.sort(c, order="age"))
# 返回排序的索引数组
a = np.array([3, 4, 2])
b = np.argsort(a)
print(b) # [2 0 1]
print(a[b]) # [2 3 4]
向量和矩阵
import numpy as np
# 向量(vector)也叫矢量,同时具有大小和方向。与向量相对的概念叫标量或数量,标量只有大小,绝大多数情况下没有方向。
# 通常用带箭头的线段来表示向量。向量是表达大小和方向的量,并没有规定起点和终点。
# 可以用 NumPy 的数组来表示向量。机器学习中,我们经常把有n个特征的训练样本称为一个n维向量。
a = np.array([1, 2, 3])
b = np.array([2, 3, 5])
# 向量的大小称为向量的模,它是一个标量。
print(np.linalg.norm(a)) # 3.7416573867739413
# 向量的加法:相同维度的向量可以相加得到一个新的向量
print(a + b) # [3 5 8]
# 向量的点积:将两个向量对应分量的乘积求和,所以点积的结果是一个标量
print(np.dot(a, b)) # 23
# 矩阵: 可以用二维数组表示矩阵
m = np.array([1, 2], [2, 3])
浙公网安备 33010602011771号