Numpy: مدخلات فريدة و NaN (Trac # 1514)

تم إنشاؤها على ١٩ أكتوبر ٢٠١٢  ·  14تعليقات  ·  مصدر: numpy/numpy

_Original تذكرة http://projects.scipy.org/numpy/ticket/1514 في 2010-06-18 بواسطة trac user rspringuel ، المخصصة لـ unknown.

عندما يعمل الفريد على مصفوفة ذات إدخالات NaN متعددة ، فإن عودته تتضمن NaN لكل إدخال كان NaN في المصفوفة الأصلية.

أمثلة:
a = random.randint (5، size = 100) .astype (عائم)

a [12] = nan # قم بإضافة إدخال nan واحد
فريد (أ)
صفيف ([0.، 1.، 2.، 3.، 4.، NaN])
a [20] = nan # add ثانية
فريد (أ)
مجموعة ([0.، 1.، 2.، 3.، 4.، NaN، NaN])
أ [13] = نان
فريد (أ) # وثالث
مجموعة ([0.، 1.، 2.، 3.، 4.، NaN، NaN، NaN])

ربما يرجع هذا إلى حقيقة أن x == y تُقدر بـ False إذا كان كل من x و y هما NaN. يحتاج الفريد إلى إضافة "أو (isnan (x) و isnan (y))" إلى الشرط الذي يتحقق من وجود قيمة في القيم المحددة بالفعل. لا أعرف كانت حياة فريدة من نوعها في numpy ولم أتمكن من العثور عليها عندما ذهبت للبحث ، لذلك لا يمكنني إجراء التغيير بنفسي (أو حتى التأكد مما يجب أن يكون عليه بناء الجملة الدقيق)

أيضًا ، يمكن استخدام الوظيفة التالية لتصحيح السلوك.

def nanunique (x):
أ = numpy.unique (x)
ص = []
بالنسبة لي في:
إذا كنت في 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]

يمكن استبدال هذا بشيء مشابه لما يلي ، والذي يتماشى إلى حد كبير مع تعليق جايمفريو منذ حوالي 5 سنوات ، ولكنه يتجنب استدعاء الأرجمين:

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]

بعد إجراء التجارب بنسبة قليلة من الوقت ، لاحظت وجود عقوبة تشغيل أقل بنسبة 10٪ على الأكثر إذا كانت المصفوفة كبيرة وهناك عدد قليل جدًا من NaN (لنقل 10 NaN من أصل 1 مليون) ، وفي مثل هذه المصفوفات الكبيرة يتم تشغيلها بشكل أسرع إذا كان هناك الكثير من NaN.

من ناحية أخرى ، إذا كانت المصفوفات صغيرة (على سبيل المثال ، 10 إدخالات) ، فهناك نتيجة أداء ملحوظة لأن التحقق من تعويم و NaN مكلف نسبيًا ، ويمكن أن يصل وقت التشغيل إلى عدة مرات. ينطبق هذا حتى إذا لم يكن هناك NaN حيث أن الفحص بطيء.

إذا كانت المصفوفة تحتوي على NaNs ، فإنها تنتج نتيجة مختلفة ، تجمع بين NaNs ، وهي نقطة كل شيء. لذلك في هذه الحالة ، فإن الأمر يتعلق حقًا بالحصول على النتيجة المرجوة (كل NaN مدمجة في مجموعة ذات قيمة واحدة) أبطأ قليلاً مقابل الحصول على نتيجة غير مرغوب فيها (كل NaN في مجموعة القيم الخاصة به) بشكل أسرع قليلاً.

أخيرًا ، لاحظ أن هذا التصحيح لن يصلح العثور على قيم فريدة تتضمن كائنات مركبة تحتوي على NaNs ، كما في هذا المثال:

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 user rspringuel كتب في 18-06-2010_

تبادل لاطلاق النار ، للحصول على استخدام كتل التعليمات البرمجية أعلاه. يؤثر هذا فقط في شفرة التصحيح ، لذا سأعيد نشر ما يلي:

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)

ثابت.

ما زلت أرى هذه المشكلة مع أحدث سيد. أي التزام يجب أن يكون قد أصلحه؟ ما لم أفقد شيئًا ، أقترح إعادة فتح هذه المشكلة.

من السهل إصلاح هذا من أجل العوامات ، لكنني لا أرى طريقة سهلة للخروج من أنواع معقدة أو منظمة. سنضع علاقات عامة سريعة معًا ويمكننا مناقشة الخيارات هناك.

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 ، أو ربما شيء ما في nanfuntions.

Sortsearching aux لنفسه هو خدعة ذكية! على الرغم من أن البحث عن _جميع _ مضيعة إلى حد ما ، إلا أننا نرغب بشكل مثالي في تحديد الإدخال الأول باستخدام nan ، ربما شيء على غرار ، بعد إنشاء صندوق aux و flag كما هو الحال الآن ، :

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

أو شيء من هذا القبيل بعد تصحيح كل الأخطاء من خلال خطأ واحد من المحتمل أن أكون قد أدخلته هناك.

ستعمل هذه الطريقة الأخيرة الخاصة بي مع الأنواع العائمة والمعقدة ، ولكنها تفشل في الأنواع الهيكلية ذات حقول النقطة العائمة. لكنني ما زلت أعتقد أن خدعة البحث ، على الرغم من أنها ستعمل مع جميع الأنواع ، إلا أنها مضيعة للغاية. بعض المواعيد:

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 لماذا لا يكون لدينا خيار خطأ افتراضيًا؟

يعني هذا السلوك محير في أحسن الأحوال والأداء ليس عذرا.

@ Demetrio92 بينما أقدر محاولتك لتحريك هذه المشكلة ، فإن السخرية / السخرية على الإنترنت يمكن تفسيرها بشكل مختلف من قبل أشخاص مختلفين ، من فضلك اجعلها لطيفة. بالنسبة للبعض منا ، الأداء مهم جدًا ولا نضيف بشكل عرضي رمزًا يؤدي إلى إبطاء الأمور.

قد يكون PR # 5487 مكانًا أفضل للتعليق أو تقديم اقتراحات حول كيفية المضي قدمًا.

تحرير: إصلاح رقم العلاقات العامة

يبدو أن هذه المشكلة مفتوحة لمدة 8 سنوات ، لكنني أريد فقط أن أتفق مع +1 لجعل السلوك الافتراضي لـ numpy.unique صحيحًا وليس سريعًا. أدى هذا إلى كسر الكود الخاص بي وأنا متأكد من أن الآخرين سيعانون منه / سيعانون منه. يمكن أن يكون لدينا "fast = False" اختياري وسلوك nan للوثائق السريعة و nans. سأندهش إذا كانت 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]

يمكن استبدال هذا بشيء مشابه لما يلي ، والذي يتماشى إلى حد كبير مع تعليق جايمفريو منذ حوالي 5 سنوات ، ولكنه يتجنب استدعاء الأرجمين:

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]

بعد إجراء التجارب بنسبة قليلة من الوقت ، لاحظت وجود عقوبة تشغيل أقل بنسبة 10٪ على الأكثر إذا كانت المصفوفة كبيرة وهناك عدد قليل جدًا من NaN (لنقل 10 NaN من أصل 1 مليون) ، وفي مثل هذه المصفوفات الكبيرة يتم تشغيلها بشكل أسرع إذا كان هناك الكثير من NaN.

من ناحية أخرى ، إذا كانت المصفوفات صغيرة (على سبيل المثال ، 10 إدخالات) ، فهناك نتيجة أداء ملحوظة لأن التحقق من تعويم و NaN مكلف نسبيًا ، ويمكن أن يصل وقت التشغيل إلى عدة مرات. ينطبق هذا حتى إذا لم يكن هناك NaN حيث أن الفحص بطيء.

إذا كانت المصفوفة تحتوي على NaNs ، فإنها تنتج نتيجة مختلفة ، تجمع بين NaNs ، وهي نقطة كل شيء. لذلك في هذه الحالة ، فإن الأمر يتعلق حقًا بالحصول على النتيجة المرجوة (كل NaN مدمجة في مجموعة ذات قيمة واحدة) أبطأ قليلاً مقابل الحصول على نتيجة غير مرغوب فيها (كل NaN في مجموعة القيم الخاصة به) بشكل أسرع قليلاً.

أخيرًا ، لاحظ أن هذا التصحيح لن يصلح العثور على قيم فريدة تتضمن كائنات مركبة تحتوي على NaNs ، كما في هذا المثال:

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

التي لا تزال ستعود

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

"إذا كانت المصفوفة تحتوي على NaNs ، فإنها تنتج نتيجة مختلفة ، تجمع بين NaNs ، وهي نقطة كل شيء."

+1

الدالة التي تعرض قائمة تحتوي على عناصر مكررة ، مثل _g._ قائمة بها أكثر من 1 NaN ، يجب ألا تسمى "فريدة". إذا كانت العناصر المتكررة في حالة NaN مطلوبة ، فيجب أن تكون حالة خاصة فقط يتم تعطيلها افتراضيًا ، على سبيل المثال numpy.unique(..., keep_NaN=False) .

ufmayer أرسل العلاقات العامة!

+1
أود أيضًا أن أؤيد إرجاع NaN مرة واحدة فقط

هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات

القضايا ذات الصلة

MareinK picture MareinK  ·  3تعليقات

Kreol64 picture Kreol64  ·  3تعليقات

kevinzhai80 picture kevinzhai80  ·  4تعليقات

astrofrog picture astrofrog  ·  4تعليقات

marcocaccin picture marcocaccin  ·  4تعليقات