创建充满nan的numpy矩阵

我有以下代码:

r = numpy.zeros(shape = (width, height, 9))

它创建一个充满0的width x height x 9矩阵。相反,我想知道是否有一个函数或方法可以简单地将它们初始化为__abc1。

332110 次浏览

你熟悉numpy.nan吗?

你可以创建你自己的方法,比如:

def nans(shape, dtype=float):
a = numpy.empty(shape, dtype)
a.fill(numpy.nan)
return a

然后

nans([3,4])

将输出

array([[ NaN,  NaN,  NaN,  NaN],
[ NaN,  NaN,  NaN,  NaN],
[ NaN,  NaN,  NaN,  NaN]])

我在邮件列表线程中找到了这段代码。

在numpy中,向量操作很少需要循环。 您可以创建一个未初始化的数组,并一次分配给所有条目:

>>> a = numpy.empty((3,3,))
>>> a[:] = numpy.nan
>>> a
array([[ NaN,  NaN,  NaN],
[ NaN,  NaN,  NaN],
[ NaN,  NaN,  NaN]])

我已经计算了Blaenk发布的替代品a[:] = numpy.nana.fill(numpy.nan)的时间:

$ python -mtimeit "import numpy as np; a = np.empty((100,100));" "a.fill(np.nan)"
10000 loops, best of 3: 54.3 usec per loop
$ python -mtimeit "import numpy as np; a = np.empty((100,100));" "a[:] = np.nan"
10000 loops, best of 3: 88.8 usec per loop

计时显示偏好ndarray.fill(..)作为更快的替代方案。OTOH,我喜欢numpy的方便实现,在这里你可以同时为整个切片赋值,代码的意图非常明确。

注意,ndarray.fill在原地执行操作,因此numpy.empty((3,3,)).fill(numpy.nan)将返回None

另一个选项是使用numpy.full, NumPy 1.8+中提供的一个选项

a = np.full([height, width, 9], np.nan)

这是非常灵活的,你可以用任何你想要的数字来填充它。

如果你不能立即回忆起.empty.full方法,你总是可以使用乘法:

>>> np.nan * np.ones(shape=(3,2))
array([[ nan,  nan],
[ nan,  nan],
[ nan,  nan]])

当然,它也适用于任何其他数值:

>>> 42 * np.ones(shape=(3,2))
array([[ 42,  42],
[ 42,  42],
[ 42, 42]])

但是@u0b34a0f6ae的接受的答案快3倍(CPU周期,而不是大脑周期来记住numpy语法;):

$ python -mtimeit "import numpy as np; X = np.empty((100,100));" "X[:] = np.nan;"
100000 loops, best of 3: 8.9 usec per loop
(predict)laneh@predict:~/src/predict/predict/webapp$ master
$ python -mtimeit "import numpy as np; X = np.ones((100,100));" "X *= np.nan;"
10000 loops, best of 3: 24.9 usec per loop

如前所述,numpy.empty()是可行的方法。然而,对于对象,fill()可能并不完全像你想象的那样:

In[36]: a = numpy.empty(5,dtype=object)
In[37]: a.fill([])
In[38]: a
Out[38]: array([[], [], [], [], []], dtype=object)
In[39]: a[0].append(4)
In[40]: a
Out[40]: array([[4], [4], [4], [4], [4]], dtype=object)

一种方法可以是:

In[41]: a = numpy.empty(5,dtype=object)
In[42]: a[:]= [ [] for x in range(5)]
In[43]: a[0].append(4)
In[44]: a
Out[44]: array([[4], [], [], [], []], dtype=object)

我比较了建议的替代方案的速度,发现,对于足够大的向量/矩阵来填充,除了val * onesarray(n * [val])之外的所有替代方案都同样快。

enter image description here


代码重现情节:

import numpy
import perfplot


val = 42.0




def fill(n):
a = numpy.empty(n)
a.fill(val)
return a




def colon(n):
a = numpy.empty(n)
a[:] = val
return a




def full(n):
return numpy.full(n, val)




def ones_times(n):
return val * numpy.ones(n)




def list(n):
return numpy.array(n * [val])




b = perfplot.bench(
setup=lambda n: n,
kernels=[fill, colon, full, ones_times, list],
n_range=[2 ** k for k in range(20)],
xlabel="len(a)",
)
b.save("out.png")

这里还没有提到的另一种可能性是使用NumPy平铺:

a = numpy.tile(numpy.nan, (3, 3))

也给了

array([[ NaN,  NaN,  NaN],
[ NaN,  NaN,  NaN],
[ NaN,  NaN,  NaN]])

我不知道速度比较。

另一种替代方法是numpy.broadcast_to(val,n),无论大小如何,它都在常数时间内返回,也是内存效率最高的(它返回重复元素的视图)。需要注意的是返回值是只读的。

下面是使用与Nico Schlömer的答案相同的基准测试提出的所有其他方法的性能比较。

enter image description here

只是一个警告,使用np.empty()初始化而不随后编辑值可能会导致(内存分配?)问题:

arr1 = np.empty(96)
arr2 = np.empty(96)
print(arr1)
print(arr2)


# [nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan  1.  1.
#   1.  1.  2.  2.  2.  2. nan nan nan nan nan nan nan nan  0.  0.  0.  0.
#   0.  0.  0.  0. nan nan nan nan nan nan nan nan nan nan nan nan nan nan
#  nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan
#  nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan
#  nan nan nan nan nan nan]
#
# [nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan  1.  1.
#   1.  1.  2.  2.  2.  2. nan nan nan nan nan nan nan nan nan nan nan nan
#  nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan
#  nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan
#  nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan
#  nan nan nan nan nan nan]

在数组中初始化的浮点数在我的脚本中的其他地方使用,但与变量arr1arr2根本没有关联。令人毛骨悚然的。

来自用户@JHBonarius的回答解决了这个问题:

arr = np.tile(np.nan, 96)
print(arr)


# [nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan
#  nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan
#  nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan
#  nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan
#  nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan
#  nan nan nan nan nan nan]
>>> width = 2
>>> height = 3


>>> r = np.full((width, height, 9), np.nan)


>>> print(r)


array([[[nan, nan, nan, nan, nan, nan, nan, nan, nan],
[nan, nan, nan, nan, nan, nan, nan, nan, nan],
[nan, nan, nan, nan, nan, nan, nan, nan, nan]],


[[nan, nan, nan, nan, nan, nan, nan, nan, nan],
[nan, nan, nan, nan, nan, nan, nan, nan, nan],
[nan, nan, nan, nan, nan, nan, nan, nan, nan]]])


>>> r.shape
(2, 3, 9)