跳到主要内容

NumPy 数学函数

本章将详细介绍 NumPy 中的数学函数,包括通用函数(ufunc)、三角函数、指数对数函数、统计函数等。这些函数是数值计算的基础。

通用函数(ufunc)

通用函数(Universal Functions,简称 ufunc)是对数组中每个元素进行操作的函数。NumPy 中的大部分数学运算都是通过 ufunc 实现的。

什么是 ufunc?

ufunc 的核心特性是元素级操作——它对数组中的每个元素独立执行相同的操作:

import numpy as np

arr = np.array([1, 2, 3, 4])

# np.sin 是一个 ufunc,对每个元素分别计算正弦
result = np.sin(arr)
print(f"sin([1,2,3,4]): {result}")

# 加法也是 ufunc
a = np.array([1, 2, 3])
b = np.array([4, 5, 6])
print(f"[1,2,3] + [4,5,6] = {a + b}")

ufunc 的方法

ufunc 对象有一些特殊方法,可以对数组进行更复杂的操作:

import numpy as np

arr = np.array([1, 2, 3, 4, 5])

# reduce: 沿轴累积操作
# 相当于 1+2+3+4+5
print(f"reduce(add): {np.add.reduce(arr)}")

# accumulate: 返回每一步的累积结果
print(f"accumulate(add): {np.add.accumulate(arr)}")
# [1, 3, 6, 10, 15]

# outer: 外积
a = np.array([1, 2, 3])
b = np.array([4, 5, 6])
print(f"outer:\n{np.add.outer(a, b)}")
# [[5, 6, 7],
# [6, 7, 8],
# [7, 8, 9]]

基本数学运算

算术运算

import numpy as np

a = np.array([4, 9, 16])
b = np.array([2, 3, 4])

# 加法
print(f"add: {np.add(a, b)}") # [6, 12, 20]
print(f"a + b: {a + b}") # [6, 12, 20]

# 减法
print(f"subtract: {np.subtract(a, b)}") # [2, 6, 12]
print(f"a - b: {a - b}") # [2, 6, 12]

# 乘法
print(f"multiply: {np.multiply(a, b)}") # [8, 27, 64]
print(f"a * b: {a * b}") # [8, 27, 64]

# 除法
print(f"divide: {np.divide(a, b)}") # [2. 3. 4.]
print(f"a / b: {a / b}") # [2. 3. 4.]

# 整除
print(f"floor_divide: {np.floor_divide(a, b)}") # [2, 3, 4]

# 取模
print(f"mod: {np.mod(a, b)}") # [0, 0, 0]

# 幂运算
print(f"power: {np.power(a, 2)}") # [16, 81, 256]
print(f"a ** 2: {a ** 2}") # [16, 81, 256]
print(f"sqrt: {np.sqrt(a)}") # [2. 3. 4.]

求余数和divmod

import numpy as np

a = np.array([10, 20, 30])
b = np.array([3, 4, 5])

# 求余数
print(f"mod: {np.mod(a, b)}") # [1, 0, 0]
print(f"remainder: {np.remainder(a, b)}") # [1, 0, 0]

# divmod: 同时得到商和余数
quotient, remainder = np.divmod(a, b)
print(f"divmod: 商={quotient}, 余数={remainder}")
# 商=[3, 5, 6], 余数=[1, 0, 0]

# fmod: 考虑符号的取模
a2 = np.array([-5, 5])
b2 = np.array([3, 3])
print(f"fmod: {np.fmod(a2, b2)}") # [-2, 2]
print(f"mod: {np.mod(a2, b2)}") # [1, 2]

倒数和相反数

import numpy as np

arr = np.array([1, 2, 4, 0.5])

# 倒数
print(f"reciprocal: {np.reciprocal(arr)}") # [1. 0.5 0.25 2.]

# 相反数
print(f"negative: {np.negative(arr)}") # [-1. -2. -4. -0.5]

# 绝对值
arr2 = np.array([-1, -2, 3])
print(f"abs: {np.abs(arr2)}") # [1, 2, 3]
print(f"absolute: {np.absolute(arr2)}") # [1, 2, 3]

# 复数的模
arr_complex = np.array([3+4j, 5+12j])
print(f"abs (复数): {np.abs(arr_complex)}") # [5. 13.]

三角函数

NumPy 提供了完整的三角函数,所有函数都使用弧度制:

import numpy as np

# 角度转弧度
angles = np.array([0, 30, 45, 60, 90])
radians = np.deg2rad(angles)
print(f"角度转弧度: {radians}")
# [0. 0.52359878 0.78539816 1.57079633 1.57079633]

# 弧度转角度
print(f"弧度转角度: {np.rad2deg(radians)}")

# 基本三角函数
x = np.array([0, np.pi/2, np.pi, 3*np.pi/2])
print(f"sin: {np.sin(x)}") # [ 0. 1. 0. -1.]
print(f"cos: {np.cos(x)}") # [ 1. 0. -1. 0.]
print(f"tan: {np.tan(x)}") # [ 0. inf 0. nan]

# 反三角函数
arr = np.array([0, 0.5, 1])
print(f"arcsin: {np.arcsin(arr)}") # [0. 0.52359878 1.57079633]
print(f"arccos: {np.arccos(arr)}") # [1.57079633 1.04719755 0. ]
print(f"arctan: {np.arctan(arr)}") # [0. 0.46364761 0.78539816]

三角函数实战

import numpy as np
import matplotlib.pyplot as plt

# 生成周期信号
t = np.linspace(0, 4*np.pi, 1000)

# 正弦波
sin_wave = np.sin(t)
print(f"正弦波范围: [{sin_wave.min():.2f}, {sin_wave.max():.2f}]")

# 余弦波
cos_wave = np.cos(t)

# 复合信号
composite = sin_wave + 0.5 * cos_wave

print("信号生成完成")

双曲函数

import numpy as np

x = np.array([0, 1, 2])

# 双曲正弦
print(f"sinh: {np.sinh(x)}") # [0. 1.17520119 3.6268604]

# 双曲余弦
print(f"cosh: {np.cosh(x)}") # [1. 1.54308063 3.76219569]

# 双曲正切
print(f"tanh: {np.tanh(x)}") # [0. 0.76159416 0.96402758]

# 反双曲函数
y = np.array([0.5, 0.9, 1.0])
print(f"arcsinh: {np.arcsinh(y)}")
print(f"arctanh: {np.arctanh(y)}")

指数和对数函数

import numpy as np

arr = np.array([1, 2, 3])

# 指数函数
print(f"exp: {np.exp(arr)}") # [ 2.71828183 7.3890561 20.0855369]
print(f"exp2: {np.exp2(arr)}") # [2. 4. 8.]
print(f"expm1: {np.expm1(arr)}") # [1.71828183 6.3890561 19.0855369]
# expm1(x) = exp(x) - 1,对小数值更精确

# 对数函数
print(f"log: {np.log(arr)}") # [0. 0.69314718 1.09861229]
print(f"log2: {np.log2(arr)}") # [0. 1. 1.5849625 ]
print(f"log10: {np.log10(arr)}") # [0. 0.30103 0.47712125]
print(f"log1p: {np.log1p(arr)}") # [0.69314718 1.09861229 1.38629436]
# log1p(x) = log(1 + x),对小数值更精确

实战:数值稳定性

import numpy as np

# 问题:对于很小的值,直接计算可能不准确
x = 1e-10
print(f"exp(x) - 1: {np.exp(x) - 1}") # 可能丢失精度
print(f"expm1(x): {np.expm1(x)}") # 更精确

# log(1 + x) 的问题
x = 1e-10
print(f"log(1 + x): {np.log(1 + x)}") # 可能丢失精度
print(f"log1p(x): {np.log1p(x)}") # 更精确

统计函数

求和与累积

import numpy as np

arr = np.array([[1, 2, 3], [4, 5, 6]])

# 求和
print(f"sum: {np.sum(arr)}") # 21
print(f"sum axis=0: {np.sum(arr, axis=0)}") # [5 7 9]
print(f"sum axis=1: {np.sum(arr, axis=1)}") # [ 6 15]

# 累积和
print(f"cumsum: {np.cumsum(arr)}")
# [1 3 6 10 15 21]
print(f"cumsum axis=1:\n{np.cumsum(arr, axis=1)}")
# [[ 1 3 6]
# [ 4 9 15]]

# 乘积
print(f"prod: {np.prod(arr)}") # 720
print(f"cumprod: {np.cumprod(arr)}") # [ 1 2 6 24 120 720]

均值和标准差

import numpy as np

arr = np.array([1, 2, 3, 4, 5])

# 均值
print(f"mean: {np.mean(arr)}") # 3.0

# 加权平均
weights = np.array([1, 2, 3, 2, 1])
print(f"average: {np.average(arr, weights=weights)}") # 3.0

# 中位数
arr2 = np.array([1, 3, 5, 7, 9])
print(f"median: {np.median(arr2)}") # 5.0

# 标准差和方差
print(f"std: {np.std(arr)}") # 1.41421356
print(f"var: {np.var(arr)}") # 2.0

# ddof 参数:自由度调整
# ddof=0: 总体标准差(除以 N)
# ddof=1: 样本标准差(除以 N-1)
arr3 = np.array([2, 4, 4, 4, 5, 5, 7, 9])
print(f"std (ddof=0): {np.std(arr3)}") # 2.0
print(f"std (ddof=1): {np.std(arr3, ddof=1)}") # 2.138...

最值函数

import numpy as np

arr = np.array([[3, 1, 5], [2, 8, 4]])

# 最大最小值
print(f"max: {np.max(arr)}") # 8
print(f"min: {np.min(arr)}") # 1
print(f"amax: {np.amax(arr)}") # 8 (别名)

# 沿轴最值
print(f"max axis=0: {np.max(arr, axis=0)}") # [3, 8, 5]
print(f"max axis=1: {np.max(arr, axis=1)}") # [5, 8]

# 返回索引
print(f"argmax: {np.argmax(arr)}") # 4 (展平后的索引)
print(f"argmax axis=0: {np.argmax(arr, axis=0)}") # [0, 1, 0]

# 范围(最大值 - 最小值)
print(f"ptp: {np.ptp(arr)}") # 7
print(f"ptp axis=1: {np.ptp(arr, axis=1)}") # [4, 6]

百分位数

import numpy as np

data = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])

# 百分位数
print(f"percentile 50: {np.percentile(data, 50)}") # 5.5 (中位数)
print(f"percentile 25: {np.percentile(data, 25)}") # 3.25
print(f"percentile 75: {np.percentile(data, 75)}") # 7.75

# 多个百分位数
print(f"percentile [25, 50, 75]: {np.percentile(data, [25, 50, 75])}")

# 分位数(更通用的表达)
print(f"quantile 0.5: {np.quantile(data, 0.5)}") # 5.5

NaN 安全的函数

处理包含缺失值的数据时,使用 NaN 安全的函数:

import numpy as np

arr = np.array([1, 2, np.nan, 4, 5])

# 常规函数遇到 NaN 会返回 NaN
print(f"sum: {np.sum(arr)}") # nan
print(f"mean: {np.mean(arr)}") # nan

# NaN 安全版本
print(f"nansum: {np.nansum(arr)}") # 12.0
print(f"nanmean: {np.nanmean(arr)}") # 3.0
print(f"nanmax: {np.nanmax(arr)}") # 5.0
print(f"nanmin: {np.nanmin(arr)}") # 1.0

# 统计函数列表
print(f"nanstd: {np.nanstd(arr)}") # 1.5811...
print(f"nanvar: {np.nanvar(arr)}") # 2.5

舍入函数

import numpy as np

arr = np.array([1.5, 2.5, 3.7, 4.3, 5.8])

# 四舍五入
print(f"round: {np.round(arr)}") # [2. 2. 4. 4. 6.]
print(f"around: {np.around(arr)}") # [2. 2. 4. 4. 6.]

# 指定小数位数
arr2 = np.array([1.2345, 2.5678, 3.9012])
print(f"round 2 decimals: {np.round(arr2, 2)}") # [1.23 2.57 3.9 ]

# 向上取整
print(f"ceil: {np.ceil(arr)}") # [2. 3. 4. 5. 6.]

# 向下取整
print(f"floor: {np.floor(arr)}") # [1. 2. 3. 4. 5.]

# 截断(向零取整)
arr3 = np.array([-1.5, -0.5, 0.5, 1.5])
print(f"trunc: {np.trunc(arr3)}") # [-1. -0. 0. 1.]
print(f"fix: {np.fix(arr3)}") # [-1. -0. 0. 1.]

逻辑函数

import numpy as np

a = np.array([1, 2, 3, 4])
b = np.array([2, 2, 2, 2])

# 元素比较
print(f"a > b: {a > b}") # [False False True True]
print(f"a == b: {a == b}") # [False True False False]

# 逻辑运算
x = np.array([True, True, False, False])
y = np.array([True, False, True, False])

print(f"logical_and: {np.logical_and(x, y)}") # [True False False False]
print(f"logical_or: {np.logical_or(x, y)}") # [True True True False]
print(f"logical_xor: {np.logical_xor(x, y)}") # [False True True False]
print(f"logical_not: {np.logical_not(x)}") # [False False True True]

# 判断数组
arr = np.array([1, 0, -1, 2])
print(f"isclose: {np.isclose(arr, 0)}") # [False True False False]

# 检查 NaN
arr_nan = np.array([1, np.nan, 3])
print(f"isnan: {np.isnan(arr_nan)}") # [False True False]

# 有限性和无穷性
print(f"isfinite: {np.isfinite(arr)}") # [True False True True]
print(f"isinf: {np.isinf(arr)}") # [False False False False]

实战:数据统计

import numpy as np

# 模拟考试成绩
scores = np.array([78, 85, 92, 67, 88, 75, 95, 82, 70, 90,
80, 85, 78, 92, 88, 73, 86, 79, 91, 84])

print("=== 成绩统计 ===")
print(f"总人数: {len(scores)}")
print(f"平均分: {np.mean(scores):.2f}")
print(f"中位数: {np.median(scores)}")
print(f"最高分: {np.max(scores)}")
print(f"最低分: {np.min(scores)}")
print(f"标准差: {np.std(scores):.2f}")

# 分位数分析
q1 = np.percentile(scores, 25)
q3 = np.percentile(scores, 75)
print(f"Q1 (25%): {q1}")
print(f"Q3 (75%): {q3}")
print(f"IQR: {q3 - q1}")

# 成绩分布
print(f"\n及格人数: {np.sum(scores >= 60)}")
print(f"优秀人数: {np.sum(scores >= 90)}")
print(f"不及格人数: {np.sum(scores < 60)}")

小结

本章介绍了 NumPy 中的数学函数:

  1. 通用函数(ufunc):元素级操作的函数
  2. 基本算术运算:加、减、乘、除、幂等
  3. 三角函数:sin、cos、tan 及其反函数
  4. 指数对数:exp、log 系列函数
  5. 统计函数:sum、mean、std、var、percentile 等
  6. 舍入函数:round、ceil、floor 等
  7. 逻辑函数:比较、布尔运算等

这些函数是数据分析、科学计算的基础,熟练掌握能够高效处理各种数值计算任务。

练习

  1. 计算自然数 1-100 的阶乘(使用 prod)
  2. 计算 0 到 2π 区间内 sin 函数的积分
  3. 给定数组,找出大于均值且小于中位数的元素
  4. 处理包含 NaN 值的数组,计算有效值的统计信息
  5. 实现滑动窗口平均(移动平均)