import numpy as np
?np.maximum
np.maximum 是 element-wise 取最大,同时也有broadcasting 机制
np.maximum([1,2,5],[2,3,4])
array([2, 3, 5])
比较下面会发现,列表与numpy 数组是具有一样的效果的
np.maximum(np.eye(2), [0.5,2])
array([[1. , 2. ],
[0.5, 2. ]])
np.maximum(np.eye(2), np.array([0.5,2]))
array([[1. , 2. ],
[0.5, 2. ]])
np.maximum(np.eye(2), np.array([[0.5,2]]))
array([[1. , 2. ],
[0.5, 2. ]])
np.maximum(0, np.array([[1,-1],[-1,2]]))
array([[1, 0],
[0, 2]])
np.array([[1,2],[3,4]]) + 1
array([[2, 3],
[4, 5]])
np.array([[1,2],[3,4]]) + np.array([1,2])
array([[2, 4],
[4, 6]])
a = np.array([[1,2],[3,4]])
a.reshape(-1,1)
array([[1],
[2],
[3],
[4]])
np.nditer
简单的数组迭代
我们可以用nditer 来访问数组的每个元素,每个元素都被提供一个标准python 迭代器接口
a = np.arange(6).reshape(2,3)
a
array([[0, 1, 2],
[3, 4, 5]])
for x in np.nditer(a):
print(x, end = ' ')
0 1 2 3 4 5
b = np.array([[3,2,4],[1,6,7],[9,8,5]])
for x in np.nditer(b):
print(x, end = ' ')
3 2 4 1 6 7 9 8 5
比较下列异同
a.T
array([[0, 3],
[1, 4],
[2, 5]])
for x in np.nditer(a.T):
print(x, end = ' ')
0 1 2 3 4 5
for x in np.nditer(a.T.copy(order='C')):
print(x, end = ' ')
0 3 1 4 2 5
b.T
array([[3, 1, 9],
[2, 6, 8],
[4, 7, 5]])
for x in np.nditer(b.copy(order='C')):
print(x, end = ' ')
3 2 4 1 6 7 9 8 5
for x in np.nditer(b.T):
print(x, end = ' ')
3 2 4 1 6 7 9 8 5
for x in np.nditer(b.T.copy()):
print(x, end = ' ')
3 1 9 2 6 8 4 7 5
for x in np.nditer(b.T.copy(order='C')):
print(x, end = ' ')
3 1 9 2 6 8 4 7 5
for x in np.nditer(b.T.copy(order='F')):
print(x, end = ' ')
3 2 4 1 6 7 9 8 5
由上面可知选择顺序与内存布局相合,order 为 ‘C’ 时,选择顺序为按行, order 为 ‘F’ 时选择顺序为列;copy 过后就是新的列表,有新的布局,而a 和 a.T 仍然是同一个布局。
修改数组值
默认 nditer 是只读的,若要写,需要更改一些参数,然后nditer 会返回可写的缓冲数组
a = np.arange(6).reshape(2,3)
a
array([[0, 1, 2],
[3, 4, 5]])
for x in np.nditer(a, op_flags=['readwrite']):
x[...] = 2 * x
a
array([[ 0, 2, 4],
[ 6, 8, 10]])
追踪索引
在 nditer 中增加 flags (‘f_index’ 或 ‘multi_index’) ,那么当前的 iterator 中的值可以用索引访问,被追踪的索引在方法 index 或者 multi_index 中
a = np.arange(6).reshape(2,3)
a
array([[0, 1, 2],
[3, 4, 5]])
it = np.nditer(a, flags=['f_index'])
while not it.finished:
print('%d <%s>' %(it[0], it.index))
it.iternext()
0 <0>
1 <2>
2 <4>
3 <1>
4 <3>
5 <5>
it = np.nditer(a, flags=['multi_index'])
while not it.finished:
print('%d <%s>' %(it[0], it.multi_index))
it.iternext()
0 <(0, 0)>
1 <(0, 1)>
2 <(0, 2)>
3 <(1, 0)>
4 <(1, 1)>
5 <(1, 2)>
it = np.nditer(a, flags=['multi_index'], op_flags=['readwrite'])
while not it.finished:
it[0] = it.multi_index[1] - it.multi_index[0]
it.iternext()
a
array([[ 0, 1, 2],
[-1, 0, 1]])
对比
a = np.arange(6).reshape(2,3)
it = np.nditer(a, flags=['multi_index'], op_flags=['readwrite'])
while not it.finished:
it[0] *= 2
it.iternext()
a
array([[ 0, 2, 4],
[ 6, 8, 10]])
a = np.arange(6).reshape(2,3)
for x in np.nditer(a, op_flags=['readwrite']):
x[...] = 2 * x
a
array([[ 0, 2, 4],
[ 6, 8, 10]])
特定数据类型
我们有时会想更改我们原本数据的类型,通常来说我们使用copy 或者 buffer 的模式,直接对原始数据操作会报错,而更好的是 buffer 模式,这种模式内存使用量较小
a = np.arange(6).reshape(2,3) - 3
a
array([[-3, -2, -1],
[ 0, 1, 2]])
for x in np.nditer(a, op_flags=['readonly', 'copy'], op_dtypes=['complex128']):
print(np.sqrt(x))
1.7320508075688772j
1.4142135623730951j
1j
0j
(1+0j)
(1.4142135623730951+0j)
for x in np.nditer(a, flags=['buffered'], op_dtypes=['complex128']):
print(np.sqrt(x))
1.7320508075688772j
1.4142135623730951j
1j
0j
(1+0j)
(1.4142135623730951+0j)
广播
np.nditer() 具有广播机制
a = np.arange(3)
b = np.arange(6).reshape(2,3)
for x,y in np.nditer([a,b]):
print('%d:%d' % (x,y))
0:0
1:1
2:2
0:3
1:4
2:5
a = np.arange(2)
b = np.arange(6).reshape(2,3)
for x,y in np.nditer([a,b]):
print('%d:%d' % (x,y))
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-81-b7cbf77d4db0> in <module>()
1 a = np.arange(2)
2 b = np.arange(6).reshape(2,3)
----> 3 for x,y in np.nditer([a,b]):
4 print('%d:%d' % (x,y))
ValueError: operands could not be broadcast together with shapes (2,) (2,3)
迭代器分配的输出数组
在 numpy 数组中,常见基于输入的广播的输出分配
def square(a):
it = np.nditer([a, None])
for x,y in it:
y[...] = x*x
return it.operands[1]
square([1,2,3])
array([1, 4, 9])
def square(a):
it = np.nditer([a, None])
for x, y in it:
y[...] = x*x
return it.operands[0]
square([1,2,3])
array([1, 2, 3])
当operands 传入的为 None 默认 flags 为 ‘allocate’ 和 ‘writeonly’,当增加一个 out 参数,默认flags 为 ‘readonly’,所以如果我们相对它进行操作,需要显式指定一些参数
def square(a, out=None):
it = np.nditer([a, out], flags=['external_loop', 'buffered'], op_flags=[['readonly'],['writeonly'
,'allocate','no_broadcast']] )
for x, y in it:
y[...] = x*x
return it.operands[1]
square([1,2,3])
array([1, 4, 9])
b = np.zeros((3,))
square([1,2,3], out=b)
array([1., 4., 9.])
b
array([1., 4., 9.])