创建用 NaN 填充的 numpy 矩阵

Posted

技术标签:

【中文标题】创建用 NaN 填充的 numpy 矩阵【英文标题】:Create numpy matrix filled with NaNs 【发布时间】:2010-12-14 20:36:45 【问题描述】:

我有以下代码:

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

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

【问题讨论】:

一个警告是 NumPy 没有整数 NA 值(与 R 不同)。见pandas list of gotchas。因此,np.nan 在转换为 int 时会出错。 smci 是对的。对于 NumPy,没有这样的 NaN 值。因此,这取决于类型和 NumPy,NaN 将存在哪个值。如果你不知道这一点,就会造成麻烦 看起来 np.nans 函数实际上有模仿 np.zeros 和 np.ones 的空间,但我认为 np.full 是一种概括,不需要所有专门的职能。好问题。 【参考方案1】:

在 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

【讨论】:

我同意您的代码意图更清晰。但是感谢您提供公正的时间安排(或者更确切地说,您仍然发布它们的事实),我很感激:) 我喜欢这个:a = numpy.empty((3, 3,)) * numpy.nan。它的计时比fill 快,但比赋值方法慢,但它是一个单行器!! 请看这个答案:***.com/questions/10871220/… 我更喜欢 .fill() 方法,但随着阵列变大,速度差异几乎没有。 ... 因为np.empty([2, 5]) 创建了一个数组,然后fill() 就地修改了该数组,但不返回副本或引用。如果您想通过名称调用np.empty(2, 5)(“分配给变量”),则必须在对其进行就地操作之前这样做。如果你这样做[1, 2, 3].insert(1, 4),也会发生同样的事情。创建列表并插入 4,但无法获得对列表的引用(因此可以假定它已被垃圾收集)。在字符串等不可变数据上,会返回一个副本,因为您无法就地操作。 Pandas 两者都可以。【参考方案2】:

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

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

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

【讨论】:

我认为这是最正确的答案,因为这正是full 的意思。 np.empy((x,y))*np.nan 是一个很好的亚军(并且兼容旧版本的 numpy)。 这比 fill python -mtimeit "import numpy as np; a = np.empty((100,100));" "a.fill(np.nan)" 100000 loops, best of 3: 13.3 usec per loop python -mtimeit "import numpy as np; a = np.full((100,100), np.nan);" 100000 loops, best of 3: 18.5 usec per loop @Farnabaz 如果将等效代码放在时序循环中,它们大致相同。这两种方法基本上是相等的,你刚刚在第一个定时器之外得到了“np.empty”。 python -mtimeit "import numpy as np; a = np.empty((1000,1000)); a.fill(np.nan)" 1000 loops, best of 3: 381 usec per loop $ python -mtimeit "import numpy as np; a = np.full((1000,1000), np.nan);" 1000 loops, best of 3: 383 usec per loop【参考方案3】:

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


重现情节的代码:

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.full(n, val)a = numpy.empty(n) .. a.fill(val) 慢,因为它在内部做同样的事情【参考方案4】:

你熟悉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]])

我在mailing list thread 中找到了此代码。

【讨论】:

看起来有点矫枉过正。 @MadPhysicist 这完全取决于您的情况。如果您只需要初始化一个 NaN 数组,那么是的,自定义函数可能是矫枉过正。但是,如果您必须在代码中的几十个地方初始化一个 NaN 数组,那么拥有这个函数就变得非常方便了。 @Xukaro。并非如此,因为这种功能的更灵活和更有效的版本已经存在并且在多个其他答案中被提及。【参考方案5】:

如果您没有立即调用 .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 的 accepted answer 快 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

【讨论】:

【参考方案6】:

如前所述,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)

【讨论】:

除了与原始问题几乎没有任何关系之外,整洁。 嗯,这是关于“将 numpy 矩阵初始化为除零或一以外的东西”,如果“其他东西”是一个对象:)列表)【参考方案7】:

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

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

也给

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

我不知道速度比较。

【讨论】:

【参考方案8】:

另一种选择是numpy.broadcast_to(val,n),无论大小如何,它都会以恒定时间返回,而且内存效率最高(它返回重复元素的视图)。需要注意的是返回的值是只读的。

以下是使用与Nico Schlömer's answer 相同的基准提出的所有其他方法的性能比较。

【讨论】:

【参考方案9】:

只是一个警告,使用 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]

【讨论】:

以上是关于创建用 NaN 填充的 numpy 矩阵的主要内容,如果未能解决你的问题,请参考以下文章

NumPy矩阵

Numpy

numpy,用其他矩阵的行填充稀疏矩阵

Numpy - 用 NaN 替换数字

Numpy - 用向量行创建矩阵

用列表中的值填充 NaN