本章介绍矩阵和通用函数(ufuncs)。 矩阵在数学上是众所周知的,在 NumPy 中也具有表示。 通用函数适用于数组,逐元素或标量。 ufuncs 期望一组标量作为输入,并产生一组标量作为输出。 通用函数通常可以映射到它们的数学对应物,例如加,减,除,乘等。 我们还将介绍三角函数,按位和比较通用函数。
在本章中,我们将介绍以下主题:
- 矩阵创建
- 矩阵运算
- 基本函数
- 三角函数
- 按位函数
- 比较函数
NumPy 中的矩阵是ndarray
的子类。 我们可以使用特殊的字符串格式创建矩阵。 就像在数学中一样,它们是二维的。 正如您期望的那样,矩阵乘法不同于正常的 NumPy 乘法。 幂运算符也是如此。 我们可以使用mat()
,matrix()
和bmat()
函数创建矩阵。
如果输入已经是矩阵或ndarray
,则mat()
函数不会复制。 调用此函数等效于调用matrix(data, copy=False)
。 我们还将演示转置和求逆矩阵。
-
行用分号分隔,值用空格分隔。 使用以下字符串调用
mat()
函数以创建矩阵:A = np.mat('1 2 3; 4 5 6; 7 8 9') print("Creation from string", A)
矩阵输出应为以下矩阵:
Creation from string [[1 2 3] [4 5 6] [7 8 9]]
-
如下将矩阵转换为具有
T
属性的矩阵:print("transpose A", A.T)
以下是转置矩阵:
transpose A [[1 4 7] [2 5 8] [3 6 9]]
-
可以使用
I
属性将矩阵反转,如下所示:print("Inverse A", A.I)
逆矩阵打印如下(请注意,这是
O(n<sup class="calibre54">3</sup>)
操作,这意味着需要平均三次时间):Inverse A [[ -4.50359963e+15 9.00719925e+15 -4.50359963e+15] [ 9.00719925e+15 -1.80143985e+16 9.00719925e+15] [ -4.50359963e+15 9.00719925e+15 -4.50359963e+15]]
-
不使用字符串创建矩阵,而是使用数组:
print("Creation from array", np.mat(np.arange(9).reshape(3, 3)))
新创建的数组如下所示:
Creation from array [[0 1 2] [3 4 5] [6 7 8]]
我们使用mat()
函数创建了矩阵。 我们将使用T
属性将矩阵转置,并使用I
属性将其反转(请参见matrixcreation.py
):
from __future__ import print_function
import numpy as np
A = np.mat('1 2 3; 4 5 6; 7 8 9')
print("Creation from string", A)
print("transpose A", A.T)
print("Inverse A", A.I)
print("Check Inverse", A * A.I)
print("Creation from array", np.mat(np.arange(9).reshape(3, 3)))
有时,我们想由其他较小的矩阵创建矩阵。 我们可以通过bmat()
函数来实现。 b
在这里代表块矩阵。
我们将从两个较小的矩阵创建一个矩阵,如下所示:
-
首先,创建一个
2×2
单位矩阵:A = np.eye(2) print("A", A)
单位矩阵如下所示:
A [[ 1\. 0.] [ 0\. 1.]]
-
创建另一个类似于
A
的矩阵,并将其乘以 2:B = 2 * A print("B", B)
第二个矩阵如下:
B [[ 2\. 0.] [ 0\. 2.]]
-
从字符串创建复合矩阵。 字符串使用与
mat()
函数相同的格式-使用矩阵而不是数字:print("Compound matrix\n", np.bmat("A B; A B"))
复合矩阵如下所示:
Compound matrix [[ 1\. 0\. 2\. 0.] [ 0\. 1\. 0\. 2.] [ 1\. 0\. 2\. 0.] [ 0\. 1\. 0\. 2.]]
我们使用bmat()
函数从两个较小的矩阵创建了一个块矩阵。 我们给该函数一个字符串,其中包含矩阵名称,而不是数字(请参见bmatcreation.py
):
from __future__ import print_function
import numpy as np
A = np.eye(2)
print("A", A)
B = 2 * A
print("B", B)
print("Compound matrix\n", np.bmat("A B; A B"))
Q1. mat()
和bmat()
函数接受的字符串中的行分隔符是什么?
- 分号
- 句号
- 逗号
- 空格
通用函数(ufuncs)期望一组标量作为输入并产生一组标量作为输出。 它们实际上是 Python 对象,它们封装了函数的行为。 通常,我们可以将ufunc
映射到它们的数学对应项,例如加,减,除,乘等。 通常,通用函数由于其特殊的优化以及在本机级别上运行而更快。
我们可以使用 NumPy 和frompyfunc()
函数从 Python 函数创建ufunc
,如下所示:
-
定义一个 Python 函数,该函数回答关于宇宙,存在和其他问题的最终问题(来自《银河系漫游指南》 ,道格拉斯·亚当,Pan Books,如果您还没有阅读,可以安全地忽略这一点!):
def ultimate_answer(a):
到目前为止,没有什么特别的。 我们给函数命名为
ultimate_answer()
并定义了一个参数a
。 -
使用
zeros_like()
函数,创建一个形状与a
相同的所有零组成的结果:result = np.zeros_like(a)
-
现在,将初始化数组的元素设置为答案
42
,然后返回结果。 完整的函数应显示在下面的代码片段中。flat
属性使我们可以访问平面迭代器,该迭代器允许我们设置数组的值。def ultimate_answer(a): result = np.zeros_like(a) result.flat = 42 return result
-
用
frompyfunc()
创建一个ufunc
;指定1
作为输入参数的数量,然后指定1
作为输出参数的数量:ufunc = np.frompyfunc(ultimate_answer, 1, 1) print("The answer", ufunc(np.arange(4)))
一维数组的结果如下所示:
The answer [42 42 42 42]
使用以下代码对二维数组执行相同的操作:
print("The answer", ufunc(np.arange(4).reshape(2, 2)))
二维数组的输出如下所示:
The answer [[42 42] [42 42]]
我们定义了一个 Python 函数。 在此函数中,我们使用zeros_like()
函数,根据输入参数的形状将数组的元素初始化为零。 然后,使用ndarray
的flat
属性,将数组元素设置为最终答案42
(请参见answer42.py
):
from __future__ import print_function
import numpy as np
def ultimate_answer(a):
result = np.zeros_like(a)
result.flat = 42
return result
ufunc = np.frompyfunc(ultimate_answer, 1, 1)
print("The answer", ufunc(np.arange(4)))
print("The answer", ufunc(np.arange(4).reshape(2, 2)))
函数如何具有方法? 如前所述,通用函数不是函数,而是表示函数的 Python 对象。 通用函数具有五种重要方法,如下:
ufunc.reduce(a[, axis, dtype, out, keepdims])
ufunc.accumulate(array[, axis, dtype, out])
ufunc.reduceat(a, indices[, axis, dtype, out])
ufunc.outer(A, B)
ufunc.at(a, indices[, b])])])
让我们在add()
函数上调用前四个方法:
-
通用函数沿指定元素的连续轴递归地减少输入数组。 对于
add()
函数,约简的结果类似于计算数组的总和。 调用reduce()
方法:a = np.arange(9) print("Reduce", np.add.reduce(a))
精简数组应如下所示:
Reduce 36
-
accumulate()
方法也递归地遍历输入数组。 但是,与reduce()
方法相反,它将中间结果存储在一个数组中并返回它。 如果使用add()
函数,则结果等同于调用cumsum()
函数。 在add()
函数上调用accumulate()
方法:print("Accumulate", np.add.accumulate(a))
累积的数组如下:
Accumulate [ 0 1 3 6 10 15 21 28 36]
-
reduceat()
方法的解释有点复杂,因此让我们对其进行调用并逐步了解其算法。reduceat()
方法需要输入数组和索引列表作为参数:print("Reduceat", np.add.reduceat(a, [0, 5, 2, 7]))
结果如下所示:
Reduceat [10 5 20 15]
第一步与索引
0
和5
有关。 此步骤可减少索引0
和5
之间的数组元素的运算:print("Reduceat step I", np.add.reduce(a[0:5]))
步骤 1 的输出如下:
Reduceat step I 10
第二步涉及索引
5
和2
。 由于2
小于5
,因此返回索引为5
的数组元素:print("Reduceat step II", a[5])
第二步产生以下输出:
Reduceat step II 5
第三步涉及索引
2
和7
。 此步骤可减少索引2
和7
之间的数组元素的运算:print("Reduceat step III", np.add.reduce(a[2:7]))
第三步的结果如下所示:
Reduceat step III 20
第四步涉及索引
7
。 此步骤导致从索引7
到数组末尾的数组元素减少操作:print("Reduceat step IV", np.add.reduce(a[7:]))
第四步结果如下所示:
Reduceat step IV 15
-
outer()
方法返回一个具有等级的数组,该等级是其两个输入数组的等级的总和。 该方法适用于所有可能的输入数组元素对。 在add()
函数上调用outer()
方法:print("Outer", 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]]
我们将通用函数的前四种方法reduce()
,accumulate()
,reduceat()
和outer()
应用于add()
函数(请参见ufuncmethods.py
):
from __future__ import print_function
import numpy as np
a = np.arange(9)
print("Reduce", np.add.reduce(a))
print("Accumulate", np.add.accumulate(a))
print("Reduceat", np.add.reduceat(a, [0, 5, 2, 7]))
print("Reduceat step I", np.add.reduce(a[0:5]))
print("Reduceat step II", a[5])
print("Reduceat step III", np.add.reduce(a[2:7]))
print("Reduceat step IV", np.add.reduce(a[7:]))
print("Outer", np.add.outer(np.arange(3), a))
通用算术运算符+
,-
和*
分别隐式链接到通用函数的加,减和乘。 这意味着在 NumPy 数组上使用这些运算符之一时,将调用相应的通用函数。 除法涉及一个稍微复杂的过程。 与数组分割有关的三个通用函数是divide()
,true_divide()
和floor_division()
。 两个运算符对应于除法:/
和//
。
让我们来看一下数组分割的作用:
-
divide()
函数将截断整数除法和普通浮点除法:a = np.array([2, 6, 5]) b = np.array([1, 2, 3]) print("Divide", np.divide(a, b), np.divide(b, a))
divide()
函数的结果如下所示:Divide [2 3 1] [0 0 0]
如您所见,截断发生了。
-
函数
true_divide()
更接近于除法的数学定义。 整数除法返回浮点结果,并且不会发生截断:print("True Divide", np.true_divide(a, b), np.true_divide(b, a))
true_divide()
函数的结果如下:True Divide [ 2\. 3\. 1.66666667] [ 0.5 0.33333333 0.6 ]
-
floor_divide()
函数总是返回整数结果。 等效于调用divide()
函数之后调用floor()
函数。floor()
函数丢弃浮点数的小数部分并返回一个整数:print("Floor Divide", np.floor_divide(a, b), np.floor_divide(b, a)) c = 3.14 * b print("Floor Divide 2", np.floor_divide(c, b), np.floor_divide(b, c))
floor_divide()
函数调用导致:Floor Divide [2 3 1] [0 0 0] Floor Divide 2 [ 3\. 3\. 3.] [ 0\. 0\. 0.]
-
默认情况下,
/
运算符等效于调用divide()
函数:from __future__ import division
但是,如果在 Python 程序的开头找到此行,则将调用
true_divide()
函数。 因此,此代码将如下所示:print("/ operator", a/b, b/a)
The result is shown as follows:
/ operator [ 2\. 3\. 1.66666667] [ 0.5 0.33333333 0.6 ]
-
//
运算符等效于调用floor_divide()
函数。 例如,查看以下代码片段:print("// operator", a//b, b//a) print("// operator 2", c//b, b//c)
//
运算符结果如下所示:// operator [2 3 1] [0 0 0] // operator 2 [ 3\. 3\. 3.] [ 0\. 0\. 0.]
divide()
函数会执行截断整数除法和常规浮点除法。 true_divide()
函数始终返回浮点结果而没有任何截断。 floor_divide()
函数始终返回整数结果; 结果与通过连续调用divide()
和floor()
函数(请参见dividing.py
)获得的相同:
from __future__ import print_function
from __future__ import division
import numpy as np
a = np.array([2, 6, 5])
b = np.array([1, 2, 3])
print("Divide", np.divide(a, b), np.divide(b, a))
print("True Divide", np.true_divide(a, b), np.true_divide(b, a))
print("Floor Divide", np.floor_divide(a, b), np.floor_divide(b, a))
c = 3.14 * b
print("Floor Divide 2", np.floor_divide(c, b), np.floor_divide(b, c))
print("/ operator", a/b, b/a)
print("// operator", a//b, b//a)
print("// operator 2", c//b, b//c)
通过实验确认导入__future__.division
的影响。
我们可以使用 NumPy mod()
,remainder()
和fmod()
函数来计算模或余数。 同样,我们可以使用%
运算符。 这些函数之间的主要区别在于它们如何处理负数。 该组中的奇数是fmod()
函数。
让我们调用前面提到的函数:
-
remainder()
函数以元素为单位返回两个数组的其余部分。 如果第二个数字为 0,则返回 0:a = np.arange(-4, 4) print("Remainder", np.remainder(a, 2))
remainder()
函数的结果如下所示:Remainder [0 1 0 1 0 1 0 1]
-
mod()
函数的功能与remainder()
函数的功能完全相同:print("Mod", np.mod(a, 2))
mod()
函数的结果如下所示:Mod [0 1 0 1 0 1 0 1]
-
%
运算符只是remainder()
函数的简写:print("% operator", a % 2)
%
运算符的结果如下所示:% operator [0 1 0 1 0 1 0 1]
-
fmod()
函数处理负数的方式与mod()
和%
的处理方式不同。 余数的符号是被除数的符号,除数的符号对结果没有影响:print("Fmod", np.fmod(a, 2))
fmod()
结果打印如下:Fmod [ 0 -1 0 -1 0 1 0 1]
我们向 NumPy 演示了mod()
,remainder()
和fmod()
函数,它们计算模或余数(请参见modulo.py
):
from __future__ import print_function
import numpy as np
a = np.arange(-4, 4)
print("Remainder", np.remainder(a, 2))
print("Mod", np.mod(a, 2))
print("% operator", a % 2)
print("Fmod", np.fmod(a, 2))
斐波那契数 基于递归关系:
用 NumPy 代码直接表达这种关系是困难的。 但是,我们可以用矩阵形式表示这种关系,也可以按照黄金比例公式:
与
这将介绍matrix()
和rint()
函数。 matrix()
函数创建矩阵, 数字四舍五入到最接近的整数,但结果不是整数。
矩阵可以表示斐波那契递归关系。 我们可以将斐波纳契数的计算表示为重复的矩阵乘法:
-
如下创建斐波那契矩阵:
F = np.matrix([[1, 1], [1, 0]]) print("F", F)
斐波那契矩阵如下所示:
F [[1 1] [1 0]]
-
通过从 8 减去 1 并取矩阵的幂,计算出第 8 个斐波那契数(忽略 0)。 斐波那契数然后出现在对角线上:
print("8th Fibonacci", (F ** 7)[0, 0])
斐波那契数如下:
8th Fibonacci 21
-
“黄金比例”公式(又称为“Binet”公式)使我们能够计算斐波纳契数,并在最后进行四舍五入。 计算前八个斐波那契数:
n = np.arange(1, 9) sqrt5 = np.sqrt(5) phi = (1 + sqrt5)/2 fibonacci = np.rint((phi**n - (-1/phi)**n)/sqrt5) print("Fibonacci", fibonacci)
前八个斐波那契数如下:
Fibonacci [ 1\. 1\. 2\. 3\. 5\. 8\. 13\. 21.]
我们用两种方法计算了斐波那契数。 在此过程中,我们了解了用于创建矩阵的matrix()
函数。 我们还了解了rint()
函数,该函数将数字四舍五入到最接近的整数,但不将类型更改为整数(请参见fibonacci.py
):
from __future__ import print_function
import numpy as np
F = np.matrix([[1, 1], [1, 0]])
print("F", F)
print("8th Fibonacci", (F ** 7)[0, 0])
n = np.arange(1, 9)
sqrt5 = np.sqrt(5)
phi = (1 + sqrt5)/2
fibonacci = np.rint((phi**n - (-1/phi)**n)/sqrt5)
print("Fibonacci", fibonacci)
您可能想知道哪种方法更快,因此请继续并确定时间。 用frompyfunc()
创建通用的斐波那契函数,并对其计时。
所有标准的三角函数,例如sin
,cos
,tan
等,都由 NumPy 中的通用函数表示)。利萨如曲线是使用三角函数的一种有趣方式。 我记得在物理实验室的示波器上制作了李沙育的数字。 两个参数方程式描述了这些图形:
x = A sin(at + π/2)
y = B sin(bt)
利萨如的数字是由A
,B
,a
和b
四个参数确定的 。 为了简单起见,我们将A
和B
设置为1
:
-
将具有
linspace()
函数的t
从-pi
初始化为具有201
点的pi
:a = 9 b = 8 t = np.linspace(-np.pi, np.pi, 201)
-
使用
sin()
函数和np.pi
计算x
:x = np.sin(a * t + np.pi/2)
-
使用
sin()
函数计算y
:y = np.sin(b * t)
-
如下图所示:
plt.plot(x, y) plt.title('Lissajous curves') plt.grid() plt.show()
a = 9
和b = 8
的结果如下:
我们用上述参数方程式绘制了利萨如曲线,其中A=B=1
,a=9
和b=8
。 我们使用了sin()
和linspace()
函数,以及 NumPy pi
常量(请参见lissajous.py
):
import numpy as np
import matplotlib.pyplot as plt
a = 9
b = 8
t = np.linspace(-np.pi, np.pi, 201)
x = np.sin(a * t + np.pi/2)
y = np.sin(b * t)
plt.plot(x, y)
plt.title('Lissajous curves')
plt.grid()
plt.show()
方波也是您可以在示波器上查看的那些整洁的东西之一。 正弦波可以很好地将其近似为 。 毕竟,方波是可以用无限傅立叶级数表示的信号。
傅立叶级数是以著名数学家让·巴蒂斯特·傅立叶(Jean-Baptiste Fourier)命名的,一系列正弦和余弦项之和。
代表方波的该特定系列的公式如下:
就像上一节一样,我们将初始化t
。 我们需要总结一些术语。 术语数量越多,结果越准确; k = 99
应该足够。 为了绘制方波,请按照下列步骤操作:
-
我们将从初始化
t
和k
开始。 将该函数的初始值设置为0
:t = np.linspace(-np.pi, np.pi, 201) k = np.arange(1, 99) k = 2 * k - 1 f = np.zeros_like(t)
-
使用
sin()
和sum()
函数计算函数值:for i, ti in enumerate(t): f[i] = np.sum(np.sin(k * ti)/k) f = (4 / np.pi) * f
-
要绘制的代码与上一节中的代码几乎相同:
plt.plot(t, f) plt.title('Square wave') plt.grid() plt.show()
用
k = 99
生成的所得方波如下:
我们使用 sin()
函数生成了方波,或者至少是它的近似值。 输入值通过 linspace()
函数进行组装,而k
值通过arange()
函数进行组装(请参见squarewave.py
):
import numpy as np
import matplotlib.pyplot as plt
t = np.linspace(-np.pi, np.pi, 201)
k = np.arange(1, 99)
k = 2 * k - 1
f = np.zeros_like(t)
for i, ti in enumerate(t):
f[i] = np.sum(np.sin(k * ti)/k)
f = (4 / np.pi) * f
plt.plot(t, f)
plt.title('Square wave')
plt.grid()
plt.show()
您可能已经注意到代码中存在一个循环。 使用 NumPy 函数摆脱它,并确保性能也得到改善。
锯齿波和三角波也是在示波器上容易看到的现象。 就像方波一样,我们可以定义无限傅立叶级数。 三角波可以通过获取锯齿波的绝对值来找到。 表示一系列锯齿波的公式如下:
就像上一节一样,我们初始化t
。 同样,k = 99
应该足够。 为了绘制锯齿波和三角波,请按照下列步骤操作:
-
将该函数的初始值设置为
zero
:t = np.linspace(-np.pi, np.pi, 201) k = np.arange(1, 99) f = np.zeros_like(t)
-
使用
sin()
和sum()
函数计算函数值:for i, ti in enumerate(t): f[i] = np.sum(np.sin(2 * np.pi * k * ti)/k) f = (-2 / np.pi) * f
-
绘制锯齿波和三角波很容易,因为三角波的值应等于锯齿波的绝对值。 绘制波形,如下所示:
plt.plot(t, f, lw=1.0, label='Sawtooth') plt.plot(t, np.abs(f), '--', lw=2.0, label='Triangle') plt.title('Triangle and sawtooth waves') plt.grid() plt.legend(loc='best') plt.show()
在下图中,三角形波是带有虚线的波:
我们使用sin()
函数绘制了锯齿波 。 我们将输入值与linspace()
函数组合在一起,并将k
值与arange()
函数组合在一起。 通过取绝对值从锯齿波中产生一个三角波(请参见sawtooth.py
):
import numpy as np
import matplotlib.pyplot as plt
t = np.linspace(-np.pi, np.pi, 201)
k = np.arange(1, 99)
f = np.zeros_like(t)
for i, ti in enumerate(t):
f[i] = np.sum(np.sin(2 * np.pi * k * ti)/k)
f = (-2 / np.pi) * f
plt.plot(t, f, lw=1.0, label='Sawtooth')
plt.plot(t, np.abs(f), '--', lw=2.0, label='Triangle')
plt.title('Triangle and sawtooth waves')
plt.grid()
plt.legend(loc='best')
plt.show()
如果您选择接受 ,那么您面临的挑战是摆脱程序中的循环。 它应该可以与 NumPy 函数一起使用,并且性能应该得到改善。
按位函数是整数或整数数组的位,因为它们是通用函数。 运算符^
,&
,|
,<<
,>>
等具有其 NumPy 对应物。 比较运算符,例如<
,>
和==
等也是如此。 这些运算符使您可以做一些巧妙的技巧,从而提高性能; 但是,它们会使您的代码难以理解,因此请谨慎使用。
现在,我们将介绍三个技巧:检查整数的符号是否不同,检查数字是否为2
的幂,以及计算作为2
的幂的数字的模数。 我们将展示一个仅用于运算符的符号,以及一个使用相应的 NumPy 函数的符号:
-
第一个技巧取决于
XOR
或^
运算符。XOR
运算符也称为不等式运算符; 因此,如果两个操作数的符号位不同,则XOR
运算将导致负数。下面的真值表说明了
XOR
运算符:输入 1 输入 2 异或 True
True
False
False
True
True
True
False
True
False
False
False
^
运算符对应于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]
正如预期的那样,除零以外,所有符号均不同。
-
2 的幂由 1 表示,后跟一系列二进制表示的尾随零。 例如,
10
,100
或1000
。 比 2 的幂小 1 的数字将由一排二进制 1 表示。 例如,11
,111
或1111
(或十进制中的3
,7
和15
)。 现在,如果我们对 2 的幂,和比它小 1 的整数进行“与”运算,则应该得到 0。AND
运算符的真值表如下所示:输入 1 输入 2 AND True True True False True False True False False False False False &
的 NumPy 对应项是bitwise_and()
,==
的对应项是equal()
通用函数:print("Power of 2?\n", x, "\n", (x & (x - 1)) == 0) print("Power of 2?\n", x, "\n", np.equal(np.bitwise_and(x, (x - 1)), 0))
The result is shown as follows:
Power of 2? **[-9 -8 -7 -6 -5 -4 -3 -2 -1 0 1 2 3 4 5 6 7 8]** [False False False False False False False False False True True True False True False False False True] Power of 2? **[-9 -8 -7 -6 -5 -4 -3 -2 -1 0 1 2 3 4 5 6 7 8]** [False False False False False False False False False True True True False True False False False True]
-
当计算整数的 2 的幂的模数时,例如 4、8、16 等,计算 4 的模数的技巧实际上起作用。 左移导致值加倍。我们在上一步中看到,从 2 的幂中减去 1 会导致二进制表示形式的数字带有一行诸如 11、111 或 1111 之类的数字。 这基本上给了我们一个掩码。 用这样的数字按位与,得到的余数为 2。 NumPy 的
<<
的等价物是left_shift()
通用函数:print("Modulus 4\n", x, "\n", x & ((1 << 2) - 1)) print("Modulus 4\n", x, "\n", np.bitwise_and(x, np.left_shift(1, 2) - 1))
The result is shown as follows:
Modulus 4 **[-9 -8 -7 -6 -5 -4 -3 -2 -1 0 1 2 3 4 5 6 7 8]** [3 0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3 0] Modulus 4 **[-9 -8 -7 -6 -5 -4 -3 -2 -1 0 1 2 3 4 5 6 7 8]** [3 0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3 0]
我们介绍了三点技巧:检查整数的符号是否不同,检查数字是否为2
的幂,并计算数字的模数为2
的幂。 我们看到了运算符^
,&
,<<
和<
的 NumPy 对应项(请参见bittwidling.py
):
from __future__ import print_function
import numpy as np
x = np.arange(-9, 9)
y = -x
print("Sign different?", (x ^ y) < 0)
print("Sign different?", np.less(np.bitwise_xor(x, y), 0))
print("Power of 2?\n", x, "\n", (x & (x - 1)) == 0)
print("Power of 2?\n", x, "\n", np.equal(np.bitwise_and(x, (x - 1)), 0))
print("Modulus 4\n", x, "\n", x & ((1 << 2) - 1))
print("Modulus 4\n", x, "\n", np.bitwise_and(x, np.left_shift(1, 2) - 1))
at()
方法是在 NumPy 1.8 中添加的 。 此方法允许原地建立花式索引。 花式索引是不涉及整数或切片的索引 ,这是正常的索引。 原地意味着将对我们操作的数组进行修改。
at()
方法的签名为ufunc.at(a, indices[, b])
。 indices
数组指定要操作的元素。 我们仅需要b
数组用于具有两个操作数的通用函数。 以下“实战时间”部分给出了at()
方法的示例 。
要演示方法的工作方式,请启动 Python 或 IPython shell 并导入 NumPy。 您现在应该知道如何执行此操作。
-
创建一个由七个随机整数组成的数组,该整数从
-3
到3
,种子为42
:>>> a = np.random.random_integers(-3, 3, 7) >>> a array([ 1, 0, -1, 2, 1, -2, 0])
当我们在编程中谈论随机数字时,我们通常会谈论伪随机数。 这些数字看起来是随机的,但实际上是使用种子来计算的。
-
将
sign()
通用函数的at()
方法应用于第四和第六个数组元素:>>> np.sign.at(a, [3, 5]) >>> a array([ 1, 0, -1, 1, 1, -1, 0])
我们使用at()
方法来选择数组元素,并执行原地操作-确定符号。 我们还学习了如何创建随机整数。
在本章中,您学习了关于矩阵和通用函数的知识。 我们介绍了如何创建矩阵,并研究了通用函数如何工作。 您简要介绍了算术,三角函数,按位和比较通用函数。
在下一章中,您将介绍 NumPy 模块。