import numpy as np
使用NumPy中的frompyfunc函数,通过一个Python函数来创建通用函数。
# 定义一个Python函数
def pyFunc(a):
result = np.zeros_like(a)
# 这里可以看出来对逐个元素的操作
result = 42
return result
使用zeros_like函数创建一个和a形状相同的、元素全部为0的数组result。flat属性提供了一个扁平迭代器,可以逐个设置数组元素的值。
使用frompyfunc创建通用函数,制定输入参数为1,输出参数为1。
ufunc1 = np.frompyfunc(pyFunc, 1, 1)
ret = ufunc1(np.arange(4))
print "The answer:\n", ret
The answer: [42 42 42 42]
ret = ufunc1(np.arange(4).reshape(2,2))
print "The answer:\n", ret
The answer: [[42 42] [42 42]]
使用在第五节介绍的vectorize函数
func2 = np.vectorize(pyFunc)
ret = func2(np.arange(4))
print "The answer:\n", ret
The answer: [42 42 42 42]
通用函数并不是真正的函数,而是能够表示函数的numpy.ufunc的对象。frompyfunc是一个构造ufunc类对象的工厂函数。
通用函数类有4个方法:reduce、accumulate、reduceat、outer。这些方法只对输入两个参数、输出一个参数的ufunc对象有效。
a = np.arange(9)
print "a:\n", a
print "Reduce:\n", np.add.reduce(a)
a: [0 1 2 3 4 5 6 7 8] Reduce: 36
print "Accumulate:\n", np.add.accumulate(a)
Accumulate: [ 0 1 3 6 10 15 21 28 36]
print "cumsum:\n", np.cumsum(a)
cumsum: [ 0 1 3 6 10 15 21 28 36]
print "Reduceat:\n", np.add.reduceat(a, [0,5,2,7])
Reduceat: [10 5 20 15]
print "Reduceat step 1:", np.add.reduce(a[0:5])
print "Reduceat step 2:", a[5]
print "Reduceat step 3:", np.add.reduce(a[2:7])
print "Reduceat step 4:", np.add.reduce(a[7:])
Reduceat step 1: 10 Reduceat step 2: 5 Reduceat step 3: 20 Reduceat step 4: 15
print "Outer:\n", np.add.outer(np.arange(3), a)
Outer: [[ 0 1 2 3 4 5 6 7 8] [ 1 2 3 4 5 6 7 8 9] [ 2 3 4 5 6 7 8 9 10]]
在NumPy中,计算算术运算符+、-、* 隐式关联着通用函数add、subtrack和multiply。也就是说,当你对NumPy数组使用这些运算符时,对应的通用函数将自动被调用。
除法包含的过程比较复杂,在数组的除法运算中射击三个通用函数divide、true_divide和floor_division,以及两个对应的运算符/和//。
a = np.array([2, 6, 5])
b = np.array([1, 2, 3])
print "Divide:\n", np.divide(a, b), np.divide(b, a)
Divide: [2 3 1] [0 0 0]
运算结果的小数部分被截断了
c = np.array([2.1, 6.2, 5.0])
d = np.array([1, 2, 1.9])
print "Divide:\n", np.divide(c, d), np.divide(d, c)
Divide: [ 2.1 3.1 2.63157895] [ 0.47619048 0.32258065 0.38 ]
divide函数如果有一方是浮点数,那么结果也是浮点数结果
print "True Divide:\n", np.true_divide(a, b), np.true_divide(b, a)
True Divide: [ 2. 3. 1.66666667] [ 0.5 0.33333333 0.6 ]
floor函数对浮点数进行向下取整并返回整数。
print "Floor Divide:\n", np.floor_divide(a, b), np.floor_divide(b, a)
Floor Divide: [2 3 1] [0 0 0]
默认情况下,使用/运算符相当于调用divide函数,使用//运算符对应于floor_divide函数
计算模数或者余数,可以使用NumPy中的mod、remainder和fmod函数。也可以用%运算符。
a = np.arange(-4,4)
print "a:\n", a
print "Remainder:\n", np.remainder(a, 2)
a: [-4 -3 -2 -1 0 1 2 3] Remainder: [0 1 0 1 0 1 0 1]
mod函数与remainder函数的功能完全一致,%操作符仅仅是remainder函数的简写
print "Fmod:\n", np.fmod(a, 2)
Fmod: [ 0 -1 0 -1 0 1 0 1]
print np.fmod(a, -2)
[ 0 -1 0 -1 0 1 0 1]
这里要用到XOR或者^操作符。XOR操作符又称为不等运算符,因此当两个操作数的符号不一致时,XOR操作的结果为负数。
在NumPy中,^操作符对应于bitwise_xor函数,<操作符对应于less函数。
x = np.arange(-9, 9)
y = -x
print "Sign different? ", (x^y) < 0
print "Sign different? ", np.less(np.bitwise_xor(x, y), 0)
Sign different? [ True True True True True True True True True False True True True True True True True True] Sign different? [ True True True True True True True True True False True True True True True True True True]
除了等于0的情况,所有整数对的符号都不一样。
在二进制数中,2的幂数表示为一个1后面跟着一串0的形式。如果在2的幂数以及比它小1的数之间进行位与操作AND,那么应该等于0。
在NumPy中,&操作符对应于bitwise_and函数,==操作符对应于equal函数。
b = np.arange(20)
print b
print "Power of 2 ?\n", (b & (b-1)) == 0
print "Power of 2 ?\n", np.equal(np.bitwise_and(b, (b-1)), 0)
[ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19] Power of 2 ? [ True True True False True False False False True False False False False False False False True False False False] Power of 2 ? [ True True True False True False False False True False False False False False False False True False False False]
计算余数的技巧只在模为2的幂数时有效。二进制的位左移一位,数值翻倍。
上一个例子看到,将2的幂数减去1,得到一串1组成的二进制数,这为我们提供了掩码,与这样的掩码做位与操作,即可得到以2的幂数作为模的余数。
在NumPy中,<<操作符对应于left_shift函数。
print "Modulus 4:\n", x & ((1<<2) - 1)
Modulus 4: [3 0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3 0]
def mod_2_pow(x, n):
mod = x & ((1<<n) - 1)
return mod
mod_2_pow(x,2)
array([3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0])
mod_2_pow(x, 3)
array([7, 0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7, 0])