NumPy 2.x 完全指南【三十四】通用函数(ufunc)之比较、逻辑运算、极值、位操作、浮点函数

发布于:2025-09-06 ⋅ 阅读:(19) ⋅ 点赞:(0)

1. 比较函数

函数名 基本功能 运算符等价形式
greater(x1, x2) 逐元素判断 x1 > x2 x1 > x2
greater_equal(x1, x2) 逐元素判断 x1 >= x2 x1 >= x2
less(x1, x2) 逐元素判断 x1 < x2 x1 < x2
less_equal(x1, x2) 逐元素判断 x1 <= x2 x1 <= x2
equal(x1, x2) 逐元素判断 x1 == x2 x1 == x2
not_equal(x1, x2) 逐元素判断 x1 != x2 x1 != x2

示例 :

# 创建两个示例数组
arr1 = np.array([3, 5, 2, 8])
arr2 = np.array([4, 5, 0, 8])

# 使用函数和运算符进行逐元素比较
print("greater (arr1 > arr2):", np.greater(arr1, arr2))        # 等价于 arr1 > arr2
print("greater_equal (arr1 >= arr2):", np.greater_equal(arr1, arr2)) # 等价于 arr1 >= arr2
print("less (arr1 < arr2):", np.less(arr1, arr2))              # 等价于 arr1 < arr2
print("less_equal (arr1 <= arr2):", np.less_equal(arr1, arr2))     # 等价于 arr1 <= arr2
print("equal (arr1 == arr2):", np.equal(arr1, arr2))           # 等价于 arr1 == arr2
print("not_equal (arr1 != arr2):", np.not_equal(arr1, arr2))     # 等价于 arr1 != arr2

2. 逻辑运算函数

| 函数名 | 基本功能 | 运算符等价形式 |
| logical_and(x1, x2) | 逐元素逻辑与操作 | x1 & x2 |
| logical_or(x1, x2) | 逐元素逻辑或操作 | x1 \| x2 |
| logical_xor(x1, x2) | 逐元素逻辑异或操作 | x1 ^ x2 |
| logical_not(x) | 逐元素逻辑非操作 | ~x |

示例 :

# 创建两个示例布尔数组
a = np.array([True, False, True, False])
b = np.array([True, True, False, False])

# 逻辑与:只有两个输入值都为 True 时,结果才为 True
result_and = np.logical_and(a, b)
print("np.logical_and(a, b):", result_and) # 输出: [ True False False False]

# 逻辑或:只要有一个输入值为 True,结果就为 True
result_or = np.logical_or(a, b)
print("np.logical_or(a, b):", result_or)   # 输出: [ True True True False]

# 逻辑异或:两个输入值不同时结果为 True,相同时为 False
result_xor = np.logical_xor(a, b)
print("np.logical_xor(a, b):", result_xor) # 输出: [False True True False]

# 逻辑非:对单个输入值取反
result_not_a = np.logical_not(a)
print("np.logical_not(a):", result_not_a)    # 输出: [False True False True]

不要使用 Python 关键字 andor 来组合逻辑数组表达式,这些关键字将测试整个数组的真值(而不是您可能期望的逐元素):

A = np.array([True, False, True, False])
B = np.array([True, True, False, False])
result = A and B # 这会引发 ValueError,因为 Python 试图判断整个数组 A 的真值
# 输出:The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

可以改用按位运算符 &|

# 逐元素逻辑与
logical_and_result = A & B  # 输出:array([ True, False, False, False])

# 逐元素逻辑或
logical_or_result = A | B   # 输出:array([ True, True, True, False])

3. 极值函数

函数名 基本功能 处理 NaN
fmax(x1, x2) 逐元素比较两个数组,返回最大值 忽略 NaN
fmin(x1, x2) 逐元素比较两个数组,返回最小值 忽略 NaN
maximum(x1, x2) 逐元素比较两个数组,返回最大值 传播 NaN
minimum(x1, x2) 逐元素比较两个数组,返回最小值 传播 NaN

处理 NaN 方式说明:

  • 忽略 NaN :如果比较的元素中有一个是 NaN,则返回非 NaN 元素;如果两个都是 NaN,则返回第一个 NaN
  • 传播 NaN :如果比较的元素中有任意一个是 NaN,则返回 NaN

注意事项

  • np.maxnp.min 不是通用函数,是聚合函数,即对输入数组的所有元素或沿指定轴进行聚合操作,返回一个或多个标量值。

Python 中的 max() 函数会在一维数组上查找最大值,但它使用较慢的序列接口,对于维度大于一的数组, max() 可能不会给出您期望的答案:

list=[1,2,3,4,5]
print(max(list)) # 5

np.maximum()reduce 方法要快得多:

# 创建一个2维数组
arr_2d = np.random.randint(0, 100, size=(4, 5))
print(arr_2d)
#  [[99 61 27 54 45]
#  [49 67 52  3 33]
#  [38 18  1  0 22]
#  [39 30 60 61 19]]

# 查找整个数组的最大值
global_max = np.max(arr_2d)
print(global_max) # 99

# 沿 axis=0(列方向)求最大值 -> 结果为每列的最大值 (形状: (5,))
max_per_column = np.max(arr_2d, axis=0)
print(max_per_column) # [99 67 60 61 45]

# 沿axis=1(行方向)求最大值 -> 结果为每行的最大值 (形状: (4,))
max_per_row = np.max(arr_2d, axis=1)
print(max_per_row) # [99 67 38 61]

# 使用 reduce 方法实现同样效果
max_per_column_reduce = np.maximum.reduce(arr_2d, axis=0)
print(max_per_column_reduce) # [99 67 60 61 45]

max(a, b)ab 视为两个整体,比较它们并返回较大的那个整体。np.maximum(a, b) 则对 ab (支持广播机制)进行逐元素比较,返回一个由每个位置较大元素组成的新数组:

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

print("max(a, b):", max(a, b)) # 比较两个数组整体,返回整个数组a或b
print("np.maximum(a, b):", np.maximum(a, b)) # 逐元素比较,返回新数组

# 输出:
# max(a, b): [4 2 8] # 整体比较,b数组“大于”a数组?这通常不是我们想要的结果
# np.maximum(a, b): [4 7 8] # 逐元素比较:max(3,4)=4; max(7,2)=7; max(1,8)=8

np.fmax()np.fmin() 在处理 NaN 值时非常有用,它们会忽略 NaN 并返回另一个非 NaN 的值。这与 np.maximum()np.minimum() 的行为不同,后者在遇到 NaN 时通常也会返回 NaN

a = np.array([1.0, np.nan, 3.0])
b = np.array([2.0, 4.0, np.nan])

print(np.fmax(a, b))  # 输出: [2. 4. 3.] (忽略NaN)
print(np.maximum(a, b)) # 输出: [ 2. nan nan] (NaN会被传播)

4. 位操作函数

函数名 基本功能 运算符等价形式
bitwise_and(x1, x2) 逐元素计算按位与 x1 & x2
bitwise_or(x1, x2) 逐元素计算按位或 x1 | x2
bitwise_xor(x1, x2) 逐元素计算按位异或 x1 ^ x2
invert(x) 逐元素计算按位取反 (非) ~x
left_shift(x1, x2) 将整数的位向左移位 x1 << x2
right_shift(x1, x2) 将整数的位向右移位 x1 >> x2

注意事项

  • 位操作函数要求参数是整数类型,因为这些函数直接操作数据的底层二进制表示,直接对整数在内存中的二进制位(bit)进行逻辑运算,而不是对数值本身进行数学运算。
  • 使用按位运算符 &| 时需要确保理解运算符优先级,如 (a > 2) & (a < 5) 是正确语法,因为 a > 2 & a < 5 会由于先计算 2 & a 而导致错误。

示例 1 ,逐位进行逻辑与操作,只有两个数的对应位都为 1 时,结果位才为 1

# 使用函数
a = np.array([5, 10, 15, 20], dtype=np.int32)
b = np.array([12, 12, 12, 12], dtype=np.int32)
result_func = np.bitwise_and(a, b) #  输出: [ 4  8 12  4]
print("bitwise_and 函数结果:", result_func)

# 使用运算符
result_operator = a & b
print(result_operator)  #  输出: [ 4  8 12  4]

示例 2 ,逐位进行逻辑或操作,只要两个数的对应位有一个为 1,结果位就为 1

# 使用函数
a = np.array([1, 2, 3, 4], dtype=np.int32)
b = np.array([4, 3, 2, 1], dtype=np.int32)
result_func = np.bitwise_or(a, b)
print( result_func)   # 输出: [5 3 3 5]

# 使用运算符
result_operator = a | b
print( result_operator)  # 输出: [5 3 3 5]

示例 3 ,逐位进行比较,如果两个数的对应位不相同,结果位为 1 ,相同则为 0

# 使用函数
a = np.array([5, 10, 15, 20], dtype=np.int32)
scalar = 12
result_func = np.bitwise_xor(a, scalar)
print(result_func)  # 输出: [ 9  6  3 24]

# 使用运算符
result_operator = a ^ scalar
print(result_operator)  # 输出: [ 9  6  3 24]

示例 4 ,将数值的二进制表示中的每一位进行取反操作(0110):

# 无符号整数类型
arr_unsigned = np.array([13], dtype=np.uint8)
result_unsigned = np.invert(arr_unsigned)
print("无符号整数取反:", result_unsigned)  # 输出: [242]
print("二进制表示:", np.binary_repr(result_unsigned[0], width=8))  # 输出: 11110010

# 有符号整数类型
arr_signed = np.array([13], dtype=np.int8)
result_signed = np.invert(arr_signed)
print("有符号整数取反:", result_signed)  # 输出: [-14]
print("二进制表示:", np.binary_repr(result_signed[0], width=8))  # 输出: 11110010

# 使用运算符
result_operator = ~arr_unsigned
print("使用 ~ 运算符结果:", result_operator)  # 输出: [242]

示例 5 ,将整数的二进制位向左移动指定的位数,右侧空位补 0 。左移 n 位相当于乘以 2 n 2^n 2n

# 使用函数
result_func = np.left_shift(10, 2)
print("left_shift 函数结果:", result_func)  # 输出: 40

# 使用运算符
result_operator = 10 << 2
print("使用 << 运算符结果:", result_operator)  # 输出: 40

# 查看二进制表示变化
print("10 的二进制:", np.binary_repr(10, width=8))  # 输出: 00001010
print("40 的二进制:", np.binary_repr(40, width=8))  # 输出: 00101000

示例 6 ,将整数的二进制位向右移动指定的位数,左侧空位补 0 (对于无符号整数)。右移 n 位相当于除以 2 n 并向下取整:

# 使用函数
result_func = np.right_shift(40, 2)
print("right_shift 函数结果:", result_func)  # 输出: 10

# 使用运算符
result_operator = 40 >> 2
print("使用 >> 运算符结果:", result_operator)  # 输出: 10

# 查看二进制表示变化
print("40 的二进制:", np.binary_repr(40, width=8))  # 输出: 00101000
print("10 的二进制:", np.binary_repr(10, width=8))  # 输出: 00001010

5. 浮点函数

浮点函数专门设计用来高效、正确地处理浮点数数组及其特有的运算问题。

函数名 主要功能 返回值/输出说明
isfinite 检测数组中的每个元素是否是有限数(即既不是无穷大,也不是 NaN 布尔数组(True 表示对应元素是有限数)
isinf 检测数组中的每个元素是否是无穷大(包括正无穷和负无穷) 布尔数组(True 表示对应元素是无穷大)
isnan 检测数组中的每个元素是否是 NaN 布尔数组(True 表示对应元素是 NaN
isnat 检测 datetime64 类型数组中的每个元素是否是 NaTNot a Time 布尔数组(True 表示对应元素是 NaT
fabs 计算数组每个元素的绝对值(对于复数是模长) 浮点数或复数数组
signbit 检测数组每个元素的符号位是否设置(即是否为负数) 布尔数组(True 表示对应元素是负数)
copysign 将第一个数组的符号逐元素更改为第二个数组对应元素的符号 浮点数数组
nextafter 返回第一个数组朝向第二个数组的下一个可表示的浮点数(逐元素) 浮点数数组
spacing 返回数组中每个元素与最近邻可表示浮点数之间的距离(ULP) 浮点数数组
modf 将数组的每个元素分离为小数部分和整数部分(逐元素) 两个浮点数数组(一个包含小数部分,一个包含整数部分)
ldexp 计算第一个数组乘以 2 的第二个数组次方(x1 * 2x2,逐元素) 浮点数数组
frexp 将数组的每个元素分解为尾数(mantissa)和二进制指数(exponent)(逐元素) 两个数组(一个包含尾数,一个包含指数)
fmod 计算除法的余数(逐元素) 浮点数数组
floor 对数组每个元素进行向下取整 浮点数数组
ceil 对数组每个元素进行向上取整 浮点数数组
trunc 对数组每个元素进行截断取整(向零取整) 浮点数数组

示例:

# 创建一个包含多种特殊值的示例数组
arr = np.array([1.0, np.inf, -np.inf, np.nan, 0.0, -2.5, 3.14])

# 使用 isfinite, isinf, isnan 进行检测
print("原始数组:", arr)
print("isfinite (是否有限):", np.isfinite(arr))  # [ True False False False  True  True  True]
print("isinf (是否无穷):", np.isinf(arr))      # [False  True  True False False False False]
print("isnan (是否NaN):", np.isnan(arr))      # [False False False  True False False False]

# 使用 fabs 计算绝对值
print("fabs (绝对值):", np.fabs(arr))          # [1.  inf inf nan 0.  2.5 3.14]

# 使用 signbit 检查符号位(是否为负)
print("signbit (是否为负):", np.signbit(arr))  # [False False  True False  True False False]

# 使用 copysign 更改符号
positive_arr = np.array([1.0, 2.0, 3.0])
negative_sign = np.array([-1.0, -1.0, -1.0])
print("copysign (更改符号):", np.copysign(positive_arr, negative_sign))  # [-1. -2. -3.]

# 使用 floor, ceil, trunc 进行取整
arr_to_round = np.array([-1.7, 1.2, 3.8])
print("floor (向下取整):", np.floor(arr_to_round))  # [-2.  1.  3.]
print("ceil (向上取整):", np.ceil(arr_to_round))   # [-1.  2.  4.]
print("trunc (向零取整):", np.trunc(arr_to_round))  # [-1.  1.  3.]

# 使用 modf 分离整数和小数部分
fractional_part, integral_part = np.modf(np.array([3.14, -2.718]))
print("modf (小数部分):", fractional_part)    # [ 0.14 -0.718]
print("modf (整数部分):", integral_part)      # [ 3. -2.]

# 使用 fmod 计算余数
print("fmod (余数):", np.fmod(np.array([7.0, -7.0]), np.array([3.0, 3.0])))  # [ 1. -1.]

网站公告

今日签到

点亮在社区的每一天
去签到