Numpy: 唯一和NaN条目(跟踪#1514)

创建于 2012-10-19  ·  14评论  ·  资料来源: numpy/numpy

_trac用户rspringuel于2010-06-18发出的原始工单http://projects.scipy.org/numpy/ticket/1514 ,已分配给未知对象。

当unique对具有多个NaN条目的数组进行操作时,其返回值将为每个条目提供一个NaN,而该数组在原始数组中为NaN。

例子:
一个= random.randint(5,size = 100).astype(float)

a [12] = nan#添加一个nan条目
独特的
array([0.,1.,2.,3.,4.,NaN])
a [20] = nan#添加第二
独特的
array([0.,1.,2.,3.,4.,NaN,NaN])
a [13] = nan
唯一的(a)#和第三个
array([0.,1.,2.,3.,4.,NaN,NaN,NaN])

这可能是由于x和y均为NaN时x == y得出False。 唯一需要将“或(isnan(x)和isnan(y))”添加到检查已标识的值中是否存在值的条件中。 我不知道在numpy中有独特的生活,并且在我寻找时找不到它,因此我无法自己进行更改(甚至无法确定条件的确切语法)。

同样,以下功能可用于修补行为。

def nanunique(x):
一个= numpy.unique(x)
r = []
为我在:
如果我在r或(numpy.isnan(i)和numpy.any(numpy.isnan(r)))中:
继续
其他:
r.append(i)
返回numpy.array(r)

00 - Bug Other

最有用的评论

我今天遇到了同样的问题。 np.unique例程的核心是在numpy / lib / arraysetops.py中的未拆散排序数组上计算掩码,以查找该排序数组中的值何时更改:

mask = np.empty(aux.shape, dtype=np.bool_)
mask[:1] = True
mask[1:] = aux[1:] != aux[:-1]

可以将其替换为以下类似的内容,这与jaimefrio在大约5年前的评论大致相同,但避免了argmin调用:

mask = np.empty(aux.shape, dtype=np.bool_)
mask[:1] = True
if (aux.shape[0] > 0 and isinstance(aux[-1], (float, np.float16,
                                              np.float32, np.float64))
    and np.isnan(aux[-1])):
    aux_firstnan = np.searchsorted(aux, np.nan, side='left')
    mask[1:aux_firstnan] = (aux[1:aux_firstnan] != aux[:aux_firstnan-1])
    mask[aux_firstnan] = True
    mask[aux_firstnan+1:] = False
else:
    mask[1:] = aux[1:] != aux[:-1]

运行一些%timeit实验,如果阵列很大且NaN很少(例如,百万个中的10 NaN),我观察到最多<10%的运行时间损失,而对于这么大的阵列,如果有很多,实际上运行得更快NaN。

另一方面,如果数组较小(例如10个条目),则会对性能造成重大影响,因为对float和NaN的检查相对昂贵,并且运行时可能会增加至多个。 即使没有NaN,这也适用,因为检查很慢。

如果数组确实具有NaN,则结合NaN会产生不同的结果,这就是所有要点。 因此,在这种情况下,这实际上是一个问题,即获得预期结果(将所有NaN合并到一个值组中)的速度略慢,而获得不想要的结果(每个NaN在其自身的值组中)略微更快。

最后,请注意,此修补程序无法解决查找涉及包含NaN的复合对象的唯一值的问题,例如在本示例中:

a = np.array([[0,1],[np.nan, 1], [np.nan, 1]])
np.unique(a, axis=0)

仍然会返回

array([[ 0.,  1.],
       [nan,  1.],
       [nan,  1.]])

所有14条评论

_trac用户rspringuel写于2010-06-18_

射击,因为必须使用上面的代码块。 这只会真正影响补丁代码,因此我将其重新发布:

def nanunique(x):
    a = numpy.unique(x)
    r = []
    for i in a:
        if i in r or (numpy.isnan(i) and numpy.any(numpy.isnan(r))):
            continue
        else:
            r.append(i)
    return numpy.array(r)

固定。

我仍然在最新的master上看到此问题。 哪个提交应该修复它? 除非我缺少任何东西,否则建议重新打开此问题。

这对于浮点数很容易修复,但是对于复杂或结构化的dtypes,我看不到简单的出路。 将进行快速公关,我们可以在那里讨论选项。

@jaimefrio我已将其固定为唯一使用

    if issubclass(aux.dtype.type, np.inexact):
        # nans always compare unequal, so encode as integers
        tmp = aux.searchsorted(aux)
    else:
        tmp = aux
    flag = np.concatenate(([True], tmp[1:] != tmp[:-1]))

但看起来其他所有操作也有问题。 也许我们需要nan_equal, nan_not_equal ufuncs,或者也许需要些什么。

aux本身进行排序搜索是一个聪明的把戏! 尽管对其全部排序进行搜索有点浪费,但理想情况下,我们希望在将auxflag像现在一样装好之后,用nan来查找第一个条目,也许是这样:

if not aux[-1] == aux[-1]:
    nanidx = np.argmin(aux == aux)
    nanaux = aux[nanidx:].searchsorted(aux[nanidx:])
    flag[nanidx+1:] = nanaux[1:] != nanaux[:-1]

或通过我可能在此处引入的所有错误纠正所有偏离之后的类似操作。

我的最后一种方法适用于浮点和复杂类型,但不适用于具有浮点字段的结构化dtype。 但是我仍然认为,即使搜索分类技巧适用于所有类型,也太浪费了。 一些时间:

In [10]: a = np.random.randn(1000)

In [11]: %timeit np.unique(a)
10000 loops, best of 3: 69.5 us per loop

In [12]: b = np.sort(a)

In [13]: %timeit b.searchsorted(b)
10000 loops, best of 3: 28.1 us per loop

这将对性能造成40%的影响,对于nanunique函数可能是可以的,但对于一般情况可能不行。

调用2019,OP问题仍然有效,并且代码可重现。

@jaimefrio为什么我们不能默认将其设置为false?

我的意思是,这种行为充其量是令人困惑的,而性能并不是借口。

@ Demetrio92我感谢您为解决此问题

PR#5487可能是更好的评论或提出建议的地方。

编辑:修复公关号

这个问题似乎已经开放了8年,但我只想通过+1来使numpy.unique的默认行为正确而不是快速。 这破坏了我的代码,我相信其他人会/将会遭受它的困扰。 我们可以有一个可选的“ fast = False”,并为fast和nans记录nan行为。 如果np.unique通常是时间紧迫的应用程序中的性能瓶颈,我会感到惊讶。

我今天遇到了同样的问题。 np.unique例程的核心是在numpy / lib / arraysetops.py中的未拆散排序数组上计算掩码,以查找该排序数组中的值何时更改:

mask = np.empty(aux.shape, dtype=np.bool_)
mask[:1] = True
mask[1:] = aux[1:] != aux[:-1]

可以将其替换为以下类似的内容,这与jaimefrio在大约5年前的评论大致相同,但避免了argmin调用:

mask = np.empty(aux.shape, dtype=np.bool_)
mask[:1] = True
if (aux.shape[0] > 0 and isinstance(aux[-1], (float, np.float16,
                                              np.float32, np.float64))
    and np.isnan(aux[-1])):
    aux_firstnan = np.searchsorted(aux, np.nan, side='left')
    mask[1:aux_firstnan] = (aux[1:aux_firstnan] != aux[:aux_firstnan-1])
    mask[aux_firstnan] = True
    mask[aux_firstnan+1:] = False
else:
    mask[1:] = aux[1:] != aux[:-1]

运行一些%timeit实验,如果阵列很大且NaN很少(例如,百万个中的10 NaN),我观察到最多<10%的运行时间损失,而对于这么大的阵列,如果有很多,实际上运行得更快NaN。

另一方面,如果数组较小(例如10个条目),则会对性能造成重大影响,因为对float和NaN的检查相对昂贵,并且运行时可能会增加至多个。 即使没有NaN,这也适用,因为检查很慢。

如果数组确实具有NaN,则结合NaN会产生不同的结果,这就是所有要点。 因此,在这种情况下,这实际上是一个问题,即获得预期结果(将所有NaN合并到一个值组中)的速度略慢,而获得不想要的结果(每个NaN在其自身的值组中)略微更快。

最后,请注意,此修补程序无法解决查找涉及包含NaN的复合对象的唯一值的问题,例如在本示例中:

a = np.array([[0,1],[np.nan, 1], [np.nan, 1]])
np.unique(a, axis=0)

仍然会返回

array([[ 0.,  1.],
       [nan,  1.],
       [nan,  1.]])

“如果数组确实具有NaN,则结合NaN会产生不同的结果,这就是全部。”

+1

返回包含重复元素的列表(例如,NaN大于1的列表)的函数不应称为“唯一”。 如果需要使用NaN的重复元素,则默认情况下应仅将其作为特殊情况禁用,例如numpy.unique(..., keep_NaN=False)

@ufmayer提交公关!

+1
我也支持只返回一次NaN

此页面是否有帮助?
0 / 5 - 0 等级