ตรวจสอบว่าอาร์เรย์ NumPy มีค่าที่ไม่ใช่ตัวเลขอย่างน้อยหนึ่งค่าหรือไม่?


109

ฉันต้องเขียนฟังก์ชันที่จะตรวจสอบว่าอินพุตมีค่าอย่างน้อยหนึ่งค่าที่ไม่ใช่ตัวเลขหรือไม่ หากพบค่าที่ไม่ใช่ตัวเลขฉันจะเพิ่มข้อผิดพลาด (เนื่องจากการคำนวณควรส่งคืนค่าตัวเลขเท่านั้น) ไม่ทราบจำนวนมิติของอาร์เรย์อินพุตล่วงหน้า - ฟังก์ชันควรให้ค่าที่ถูกต้องโดยไม่คำนึงถึง ndim ในฐานะที่เป็นความซับซ้อนเพิ่มเติมอินพุตอาจเป็นลูกลอยเดียวหรือnumpy.float64หรือแม้แต่บอลคี่เช่นอาร์เรย์ศูนย์มิติ

วิธีที่ชัดเจนในการแก้ปัญหานี้คือการเขียนฟังก์ชันแบบวนซ้ำซึ่งจะวนซ้ำบนทุกออบเจ็กต์ที่ทำซ้ำได้ในอาร์เรย์จนกว่าจะพบสิ่งที่ไม่ใช่อิเทราบี จะใช้numpy.isnan()ฟังก์ชันนี้กับทุกออบเจ็กต์ที่ไม่สามารถทำซ้ำได้ หากพบค่าที่ไม่ใช่ตัวเลขอย่างน้อยหนึ่งค่าฟังก์ชันจะส่งคืน False ทันที มิฉะนั้นหากค่าทั้งหมดในการทำซ้ำเป็นตัวเลขจะส่งกลับ True ในที่สุด

ใช้งานได้ดี แต่ค่อนข้างช้าและฉันคาดหวังว่าNumPyจะมีวิธีที่ดีกว่านี้มาก ทางเลือกอื่นที่เร็วกว่าและมึนงงคืออะไร?

นี่คือต้นแบบของฉัน:

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
คำอธิบายของคุณที่contains_nanดูน่าสงสัย: "ส่งกลับเท็จหากมีค่าที่ไม่ใช่ตัวเลขอย่างน้อยหนึ่งค่า" ฉันคาดว่าcontains_nanจะกลับมาTrueถ้าอาร์เรย์มี NaN
Samuel Tardieu

สิ่งที่เกี่ยวกับปัจจัยการผลิตเช่นarray(['None', 'None'], dtype=object)? ข้อมูลดังกล่าวควรเพิ่มข้อยกเว้นหรือไม่?
Finn Årup Nielsen

float('nan') in xไม่ใช้ มันไม่ทำงาน.
Charlie Parker

คำตอบ:


195

สิ่งนี้ควรเร็วกว่าการทำซ้ำและจะได้ผลโดยไม่คำนึงถึงรูปร่าง

numpy.isnan(myarray).any()

แก้ไข: เร็วขึ้น 30 เท่า:

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

ผล:

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

โบนัส: ใช้งานได้ดีสำหรับประเภท NumPy ที่ไม่ใช่อาร์เรย์:

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

1
ด้วย numpy 1.7 เวอร์ชัน flatten () เร็วกว่ารุ่นแรกเพียงสองเท่า
Christian Geier

ทำไมบางอย่างถึงfloat('nan') in xไม่ได้ผล? ฉันพยายามมันและผลตอบแทนหลามที่False x = [1,2,3,float('nan')]
Charlie Parker

1
@CharlieParker เหตุผลเดียวกันว่าทำไม float ('nan') == float ('nan') จะส่งคืน False NaN ไม่เท่ากับ NaN ข้อมูลเพิ่มเติมที่นี่: stackoverflow.com/questions/10034149/…
Muppet

1
@mab: นั่นเป็นเพราะการเรียกnumpy.anyใช้ genexp เพียงแค่ส่งคืน genexp คุณไม่ได้ทำการคำนวณอย่างที่คุณคิดจริงๆ อย่าโทรหาnumpy.anygenexp
user2357112 รองรับ Monica

1
ไม่สนใจ - นี่เป็นวิธีที่เร็วที่สุดในการทำเช่นนี้จริงๆหรือ i) ไม่numpy.isnan(a).any()เกี่ยวข้องกับการจัดสรรอาร์เรย์ชั่วคราวขนาดใหญ่ (มันเป็นมุมมอง) ii) หากองค์ประกอบแรกเป็น NAN โซลูชันนี้เกี่ยวข้องกับการวนซ้ำบนอาร์เรย์เต็มรูปแบบหรือไม่ ถ้าฉันตั้งค่าองค์ประกอบแรกเป็น NAN สิ่งนี้ยังคงใช้เวลาประมาณ 5 มิลลิวินาทีซึ่งดูเหมือนจะค่อนข้างช้าสำหรับสิ่งที่สามารถทำได้ด้วยการค้นหาอาร์เรย์และการทดสอบ - ควรเป็นนาโนวินาทีไม่ใช่หรือ
user48956

18

ถ้าอินฟินิตี้เป็นค่าที่เป็นไปได้ฉันจะใช้numpy.isfinite

numpy.isfinite(myarray).all()

หากประเมินข้างต้นTrueแล้วmyarrayมีไม่numpy.nan, numpy.infหรือ-numpy.infค่า

numpy.nanจะใช้ได้กับnumpy.infค่าตัวอย่างเช่น:

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)

ทำไมบางอย่างถึงfloat('nan') in xไม่ได้ผล? ฉันพยายามมันและผลตอบแทนหลามที่False x = [1,2,3,float('nan')]
Charlie Parker

1
@CharlieParker เพราะสองnans ไม่ถือว่าเท่ากัน ลองfloat('nan') == float('nan').
Akavall

น่าสนใจ. เหตุใดจึงไม่ถือว่าเท่าเทียมกัน?
Charlie Parker

1
@CharlieParker ฉันไม่คิดว่าฉันจะให้คำตอบที่ดีได้ที่นี่ บางทีนี่อาจเป็นสิ่งที่คุณกำลังมองหา: stackoverflow.com/questions/1565164/…
Akavall

6

พ้อ! ไมโครวินาที! อย่าแก้ปัญหาในหน่วยไมโครวินาทีที่สามารถแก้ไขได้ในหน่วยนาโนวินาที

โปรดทราบว่าคำตอบที่ยอมรับ:

  • วนซ้ำข้อมูลทั้งหมดไม่ว่าจะพบ nan หรือไม่ก็ตาม
  • สร้างอาร์เรย์ชั่วคราวขนาด N ซึ่งซ้ำซ้อน

ทางออกที่ดีกว่าคือส่งคืน True ทันทีเมื่อพบ NAN:

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)

และใช้งานได้กับขนาด n:

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

เปรียบเทียบสิ่งนี้กับโซลูชันดั้งเดิมของ numpy:

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

วิธีการออกก่อนกำหนดคือ 3 คำสั่งหรือการเร่งขนาด (ในบางกรณี) ไม่โทรมเกินไปสำหรับคำอธิบายประกอบง่ายๆ


3

ด้วย numpy 1.3 หรือ svn คุณสามารถทำได้

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

การปฏิบัติต่อแนนในการเปรียบเทียบไม่สอดคล้องกับเวอร์ชันก่อนหน้า


ทำไมบางอย่างถึงfloat('nan') in xไม่ได้ผล? ฉันพยายามมันและผลตอบแทนหลามที่False x = [1,2,3,float('nan')]
Charlie Parker

@CharlieParker ... เพราะการเปรียบเทียบกับแนนไม่ได้ทำในสิ่งที่คุณคาดหวัง NAN ได้รับการปฏิบัติเหมือน NULL เชิงตรรกะ (= ไม่รู้) float("nan")==float("nan")ให้False(แม้ว่าจะเป็นไปได้ที่จะส่งคืน NAN หรือไม่มี) ความแปลกในทำนองเดียวกันกับ NAN และ boolen NULL เป็นจริงในหลายภาษารวมถึง SQL (โดยที่ NULL = NULL ไม่เป็นจริง)
user48956

2

(np.where(np.isnan(A)))[0].shape[0]จะสูงกว่า0ถ้าAมีองค์ประกอบอย่างน้อยหนึ่งnan, Aอาจจะเป็นn x mเมทริกซ์

ตัวอย่าง:

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"
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.