Підрахунок кількості елементів, що не належать до NaN, у numpy ndarray у Python


87

Мені потрібно обчислити кількість елементів, що не містять NaN, у матриці numpy ndarray. Як можна ефективно це робити в Python? Ось мій простий код для досягнення цього:

import numpy as np

def numberOfNonNans(data):
    count = 0
    for i in data:
        if not np.isnan(i):
            count += 1
    return count 

Чи є для цього в numpy вбудована функція? Ефективність важлива, оскільки я роблю аналіз великих даних.

Thnx за будь-яку допомогу!


2
Здається, це питання не стосується теми, оскільки воно належить codereview.stackexchange.com
jonrsharpe

1
Ви маєте на увазі ефективний з точки зору пам’яті?
Ашвіні Чаудхарі

+1 Я думав про час процесора, але так, чому б і не пам’ять. Чим швидше і дешевше, тим краще =)
jjepsuomi

3
@jjepsuomi Ефективна версія пам'яті буде sum(not np.isnan(x) for x in a), але з точки зору швидкості вона повільна порівняно з версією @ M4rtini numpy.
Ашвіні Чаудхарі

@AshwiniChaudhary Велике спасибі! Мені потрібно побачити, який з них важливіший у моїй заявці =)
jjepsuomi

Відповіді:


161
np.count_nonzero(~np.isnan(data))

~інвертує логічну матрицю, повернуту з np.isnan.

np.count_nonzeroпідраховує значення, що не є 0 \ false. .sumповинні дати той самий результат. Але, можливо, більш чітко використовуватиcount_nonzero

Швидкість тестування:

In [23]: data = np.random.random((10000,10000))

In [24]: data[[np.random.random_integers(0,10000, 100)],:][:, [np.random.random_integers(0,99, 100)]] = np.nan

In [25]: %timeit data.size - np.count_nonzero(np.isnan(data))
1 loops, best of 3: 309 ms per loop

In [26]: %timeit np.count_nonzero(~np.isnan(data))
1 loops, best of 3: 345 ms per loop

In [27]: %timeit data.size - np.isnan(data).sum()
1 loops, best of 3: 339 ms per loop

data.size - np.count_nonzero(np.isnan(data))здається, ледве тут найшвидший. інші дані можуть давати різні результати відносної швидкості.


+1 @ M4rtini ще раз спасибі! Ти чудовий! ; DI прийме вашу відповідь, як тільки зможу :)
jjepsuomi

3
Може навіть numpy.isnan(array).sum()? Я не дуже добре володію numpy, хоча.
msvalkon

2
@msvalkon, Він буде рахувати кількість NaN, тоді як OP хоче кількість елементів, що не належать до NaN.
falsetru


5
Розширення відповіді @msvalkon: data.size - np.isnan(data).sum()буде трохи ефективнішим.
Даніель

10

Швидкий для написання альтернативний варіант

Хоча це не найшвидший вибір, якщо продуктивність не є проблемою, ви можете використовувати:

sum(~np.isnan(data)).

Продуктивність:

In [7]: %timeit data.size - np.count_nonzero(np.isnan(data))
10 loops, best of 3: 67.5 ms per loop

In [8]: %timeit sum(~np.isnan(data))
10 loops, best of 3: 154 ms per loop

In [9]: %timeit np.sum(~np.isnan(data))
10 loops, best of 3: 140 ms per loop

Ця відповідь надає суму, яка не є такою, як підрахунок кількості елементів ... lenНатомість слід використовувати .
BenT

@BenT сума елементів bool-масиву, які відповідають певній умові, однакова, забезпечуючи об'єктив масиву підмножин елементами, які відповідають певній умові. Ви можете пояснити, де це неправильно?
ГМ

1
Моя помилка, я забув повернення логічного значення.
BenT

3

Щоб визначити, чи є масив розрідженим, це може допомогти отримати частку значень nan

np.isnan(ndarr).sum() / ndarr.size

Якщо ця частка перевищує порогове значення, використовуйте розріджений масив, наприклад - https://sparse.pydata.org/en/latest/


2

Альтернативою, але дещо повільнішою альтернативою є зробити це за допомогою індексації.

np.isnan(data)[np.isnan(data) == False].size

In [30]: %timeit np.isnan(data)[np.isnan(data) == False].size
1 loops, best of 3: 498 ms per loop 

Подвійне використання оператора np.isnan(data)та ==оператора може бути трохи надмірним, тому я розмістив відповідь лише для повноти.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.