Bir NumPy dizisinin en az bir sayısal olmayan değer içerip içermediğini tespit et?


103

Girdinin sayısal olmayan en az bir değer içerip içermediğini algılayacak bir işlev yazmam gerekiyor. Sayısal olmayan bir değer bulunursa, bir hata oluştururum (çünkü hesaplama yalnızca sayısal bir değer döndürmelidir). Giriş dizisinin boyutlarının sayısı önceden bilinmemektedir - fonksiyon, ndim'den bağımsız olarak doğru değeri vermelidir. Ekstra bir komplikasyon olarak, girdi tek bir kayan nokta olabilir veyanumpy.float64 veya hatta sıfır boyutlu bir dizi gibi garip bir şey olabilir.

Bunu çözmenin açık yolu, yinelemeli olmayan bir bulana kadar dizideki her yinelenebilir nesneyi yineleyen yinelemeli bir işlev yazmaktır. numpy.isnan()İşlevi yinelenemeyen her nesneye uygulayacaktır . En az bir sayısal olmayan değer bulunursa, işlev hemen False döndürür. Aksi takdirde yinelenebilirdeki tüm değerler sayısal ise, sonunda True döndürür.

Bu gayet iyi çalışıyor, ancak oldukça yavaş ve NumPy'nin bunu yapmak için çok daha iyi bir yolu olmasını bekliyorum. Daha hızlı ve daha uyuşmuş bir alternatif nedir?

İşte mockup'ım:

def contains_nan( myarray ):
    """
    @param myarray : An n-dimensional array or a single float
    @type myarray : numpy.ndarray, numpy.array, float
    @returns: bool
    Returns true if myarray is numeric or only contains numeric values.
    Returns false if at least one non-numeric value exists
    Not-A-Number is given by the numpy.isnan() function.
    """
    return True

3
Açıklamanız contains_nanşüpheli görünüyor: "En az bir sayısal olmayan değer varsa yanlış döndürür". Ben umuyordum contains_nandönmek için Truedizi NaN içeriyorsa.
Samuel Tardieu

Peki ya gibi girdiler array(['None', 'None'], dtype=object)? Böyle bir girdi sadece bir istisna oluşturmalı mı?
Finn Årup Nielsen

KULLANMAYIN float('nan') in x. İşe yaramıyor.
Charlie Parker

Yanıtlar:


183

Bu, yinelemeden daha hızlı olmalı ve şekli ne olursa olsun işe yarayacaktır.

numpy.isnan(myarray).any()

Düzenleme: 30 kat daha hızlı:

import timeit
s = 'import numpy;a = numpy.arange(10000.).reshape((100,100));a[10,10]=numpy.nan'
ms = [
    'numpy.isnan(a).any()',
    'any(numpy.isnan(x) for x in a.flatten())']
for m in ms:
    print "  %.2f s" % timeit.Timer(m, s).timeit(1000), m

Sonuçlar:

  0.11 s numpy.isnan(a).any()
  3.75 s any(numpy.isnan(x) for x in a.flatten())

Bonus: dizi olmayan NumPy türleri için iyi çalışır:

>>> a = numpy.float64(42.)
>>> numpy.isnan(a).any()
False
>>> a = numpy.float64(numpy.nan)
>>> numpy.isnan(a).any()
True

1
numpy 1.7 ile flatten () versiyonu ilk versiyondan sadece iki kat daha hızlı
Christian Geier

Neden gibi bir float('nan') in xşey çalışmıyor? Ben denedim ve python Falsenereye geri döndü x = [1,2,3,float('nan')].
Charlie Parker

1
@CharlieParker aynı neden float ('nan') == float ('nan') False döndürür. NaN, NaN'ye eşit değildir. Burada daha fazla bilgi: stackoverflow.com/questions/10034149/…
Muppet

1
@mab: Bunun nedeni numpy.any, bir genexp'i çağırmanın genexp'i döndürmesidir; aslında düşündüğünüz hesaplamayı yapmıyorsunuz. Asla numpy.anybir genexp çağırmayın.
user2357112, Monica'yı

Gerçek hata ayıklama senaryosunda, sayısal taşmaları, istikrarsızlıkları vb. Tespit etmek np.isfiniteyerine bakmanızı da öneririm np.isnan.
Ben Usman

18

Sonsuzluk olası bir değerse , numpy.isfinite kullanırdım

numpy.isfinite(myarray).all()

Yukarıda değerlendirilirse True, o zaman myarrayhiçbir içerir numpy.nan, numpy.infya da -numpy.infdeğerleri.

numpy.nannumpy.infdeğerler için uygun olacaktır , örneğin:

In [11]: import numpy as np

In [12]: b = np.array([[4, np.inf],[np.nan, -np.inf]])

In [13]: np.isnan(b)
Out[13]: 
array([[False, False],
       [ True, False]], dtype=bool)

In [14]: np.isfinite(b)
Out[14]: 
array([[ True, False],
       [False, False]], dtype=bool)

Neden gibi bir float('nan') in xşey çalışmıyor? Ben denedim ve python Falsenereye geri döndü x = [1,2,3,float('nan')].
Charlie Parker

1
@CharlieParker çünkü iki nans birbirine eşit kabul edilmez. Deneyin float('nan') == float('nan').
Akavall

ilginç. Neden eşit kabul edilmiyorlar?
Charlie Parker

1
@CharlieParker, burada çok iyi bir cevap verebileceğimi sanmıyorum. Belki de aradığınız şey budur: stackoverflow.com/questions/1565164/…
Akavall

4

Pfft! Mikrosaniye! Nanosaniyeler içinde çözülebilecek bir sorunu asla mikrosaniyeler içinde çözmeyin.

Kabul edilen cevabın:

  • Bir nan bulunup bulunmadığına bakılmaksızın tüm verileri yineler
  • Gereksiz olan N boyutunda geçici bir dizi oluşturur.

Daha iyi bir çözüm, NAN bulunduğunda hemen True döndürmektir:

import numba
import numpy as np

NAN = float("nan")

@numba.njit(nogil=True)
def _any_nans(a):
    for x in a:
        if np.isnan(x): return True
    return False

@numba.jit
def any_nans(a):
    if not a.dtype.kind=='f': return False
    return _any_nans(a.flat)

array1M = np.random.rand(1000000)
assert any_nans(array1M)==False
%timeit any_nans(array1M)  # 573us

array1M[0] = NAN
assert any_nans(array1M)==True
%timeit any_nans(array1M)  # 774ns  (!nanoseconds)

ve n boyutları için çalışır:

array1M_nd = array1M.reshape((len(array1M)/2, 2))
assert any_nans(array1M_nd)==True
%timeit any_nans(array1M_nd)  # 774ns

Bunu numpy yerel çözümle karşılaştırın:

def any_nans(a):
    if not a.dtype.kind=='f': return False
    return np.isnan(a).any()

array1M = np.random.rand(1000000)
assert any_nans(array1M)==False
%timeit any_nans(array1M)  # 456us

array1M[0] = NAN
assert any_nans(array1M)==True
%timeit any_nans(array1M)  # 470us

%timeit np.isnan(array1M).any()  # 532us

Erken çıkış yöntemi 3 emir veya büyüklük hızlandırmasıdır (bazı durumlarda). Basit bir açıklama için çok perişan değil.


3

Numpy 1.3 veya svn ile bunu yapabilirsiniz

In [1]: a = arange(10000.).reshape(100,100)

In [3]: isnan(a.max())
Out[3]: False

In [4]: a[50,50] = nan

In [5]: isnan(a.max())
Out[5]: True

In [6]: timeit isnan(a.max())
10000 loops, best of 3: 66.3 µs per loop

Nans'ın karşılaştırmalarda ele alınması önceki versiyonlarda tutarlı değildi.


Neden gibi bir float('nan') in xşey çalışmıyor? Ben denedim ve python Falsenereye geri döndü x = [1,2,3,float('nan')].
Charlie Parker

@CharlieParker ... çünkü NAN ile karşılaştırma beklediğinizi yapmıyor. NAN, mantıksal bir BOŞ (= bilmiyorum) gibi ele alınır. float("nan")==float("nan")vermek False(mümkün olsa da muhtemelen NAN veya Hiçbiri döndürmelidir). Benzer şekilde NAN ve boolen NULL ile ilgili tuhaflık, SQL dahil (burada NULL = NULL hiçbir zaman doğru değildir) birçok dilde doğrudur.
user48956

2

(np.where(np.isnan(A)))[0].shape[0] daha büyük olacak 0 , eğer Aen az bir element arasında içerir nan, Abir olabilirn x m matrisi.

Misal:

import numpy as np

A = np.array([1,2,4,np.nan])

if (np.where(np.isnan(A)))[0].shape[0]: 
    print "A contains nan"
else:
    print "A does not contain nan"
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.