我经常发现自己必须在2D数组中创建一条线(或某种其他形状)。换句话说,除了y = mx + c之外,数组的值都是零。 (旁白 - 这种方法的动机,而不是在一维数组中存储一条线,是我的工作经常需要2D傅里叶变换,所以除了线/形状/等等之外我还需要零点)。
我这样做的常用方法如下:
array = numpy.zeros((height, width))
for i, line in enumerate(array):
for j, pixel in enumerate(line):
if j == m*i + c:
array[i,j] = 1
这样可以正常工作,但它并没有让我觉得特别是pythonic,而且当阵列变大时它往往变得相当慢。所以,我的问题是一个相当普遍的问题 - 是否有人知道更好的方法呢?
提前致谢!
答案 0 :(得分:3)
您可以在这里使用broadcasting
来摆脱那些嵌套循环 -
import numpy as np
out = (np.arange(height) == m*np.arange(width)[:,None]+c)+0.0
作为验证正确性的示例,使用这些参数 -
height = 10
width = 10
m = 0.5;
c = 6;
你会 -
In [306]: array
Out[306]:
array([[ 0., 0., 0., 0., 0., 0., 1., 0., 0., 0.],
[ 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
[ 0., 0., 0., 0., 0., 0., 0., 1., 0., 0.],
[ 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
[ 0., 0., 0., 0., 0., 0., 0., 0., 1., 0.],
[ 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
[ 0., 0., 0., 0., 0., 0., 0., 0., 0., 1.],
[ 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
[ 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
[ 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]])
In [307]: out
Out[307]:
array([[ 0., 0., 0., 0., 0., 0., 1., 0., 0., 0.],
[ 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
[ 0., 0., 0., 0., 0., 0., 0., 1., 0., 0.],
[ 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
[ 0., 0., 0., 0., 0., 0., 0., 0., 1., 0.],
[ 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
[ 0., 0., 0., 0., 0., 0., 0., 0., 0., 1.],
[ 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
[ 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
[ 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]])
答案 1 :(得分:2)
函数np.fromfunction
是为可以从索引构建数组的情况设计的,例如这种情况。
在你的情况下,
np.fromfunction(lambda i, j: j == m*i+c, (height, width), dtype=np.float)
将等同于您的方法,但使用numpy的例程而不是Python for循环。
简短演示:
import numpy as np
height, width = 10,10
m, c = 2, 4
a = np.zeros((height, width))
for i, line in enumerate(a):
for j, pixel in enumerate(a):
if j == m*i + c:
a[i,j] = 1
b = np.fromfunction(lambda i, j: j == m*i+c, (height, width), dtype=np.float)
np.all(a==b)
# True
b.astype(np.int) # as type added to reduce output (no need for all the periods)
#array([[0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
# [0, 0, 0, 0, 0, 0, 1, 0, 0, 0],
# [0, 0, 0, 0, 0, 0, 0, 0, 1, 0],
# [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
# [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
# [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
# [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
# [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
# [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
# [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]])
编辑:即使这个答案被接受,我想指出@Divakar's answer在我的机器上快了大约10倍。如果您正在寻找速度:使用该答案如果您的问题很容易让自己适应矢量化,就像Divakar所示(并非每个fromfunction
调用都可以轻松地进行矢量化)。我赞成它,因为它是解决这个问题的好方法。
答案 2 :(得分:1)
使用np.put
,但您需要创建特定索引的列表,您可以使用列表解析来执行此操作:
>>> np.put(arr,[j for j in range(arr.shape[1]) for i in range(arr.shape[0]) if j == m*i + c],1)
演示:
>>> np.put(arr,[j for j in range(arr.shape[1]) for i in range(arr.shape[0]) if j == 3*i + 1],1)
>>> arr
array([[ 0., 1., 0.],
[ 0., 0., 0.],
[ 0., 0., 0.],
[ 0., 0., 0.],
[ 0., 0., 0.]])
>>> np.put(arr,[j for j in range(arr.shape[1]) for i in range(arr.shape[0]) if j == 0.5*i + 2],1)
>>> arr
array([[ 0., 1., 1.],
[ 0., 0., 0.],
[ 0., 0., 0.],
[ 0., 0., 0.],
[ 0., 0., 0.]])