Đếm số phần tử không phải NaN trong một ndarray numpy bằng Python


87

Tôi cần tính số phần tử không phải NaN trong ma trận ndarray không có cấu trúc. Làm cách nào để thực hiện điều này một cách hiệu quả trong Python? Đây là mã đơn giản của tôi để đạt được điều này:

import numpy as np

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

Có một chức năng tích hợp cho việc này trong numpy không? Hiệu quả rất quan trọng vì tôi đang thực hiện phân tích Dữ liệu lớn.

Thnx cho bất kỳ sự giúp đỡ!


2
Câu hỏi này dường như là off-topic vì nó thuộc về codereview.stackexchange.com
jonrsharpe

1
Ý bạn là hiệu quả về bộ nhớ?
Ashwini Chaudhary

+1 Tôi đã suy nghĩ về thời gian CPU, nhưng tại sao không phải là bộ nhớ. Các nhanh hơn và rẻ hơn thì càng tốt =)
jjepsuomi

3
@jjepsuomi Sẽ có một phiên bản hiệu quả về bộ nhớ sum(not np.isnan(x) for x in a), nhưng về tốc độ thì nó chậm hơn so với phiên bản @ M4rtini numpy.
Ashwini Chaudhary

@AshwiniChaudhary Cảm ơn bạn rất nhiều! Tôi cần phải xem cái nào là quan trọng hơn trong ứng dụng của tôi =)
jjepsuomi

Câu trả lời:


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

~đảo ngược ma trận boolean được trả về từ đó np.isnan.

np.count_nonzerođếm các giá trị không phải là 0 \ false. .sumnên cho kết quả tương tự. Nhưng có thể rõ ràng hơn để sử dụngcount_nonzero

Tốc độ kiểm tra:

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))dường như hầu như không phải là nhanh nhất ở đây. dữ liệu khác có thể cho kết quả tốc độ tương đối khác nhau.


+1 @ M4rtini cảm ơn bạn một lần nữa! Bạn tuyệt vời! ; DI sẽ chấp nhận câu trả lời của bạn ngay khi tôi có thể :)
jjepsuomi

3
Thậm chí có thể numpy.isnan(array).sum()? Tôi không thành thạo lắm với numpy.
msvalkon

2
@msvalkon, Nó sẽ đếm số lượng NaN, trong khi OP muốn số phần tử không phải NaN.
falsetru


5
Phần mở rộng của câu trả lời @msvalkon: data.size - np.isnan(data).sum()sẽ hiệu quả hơn một chút.
Daniel

10

Viết nhanh thay đổi

Mặc dù không phải là lựa chọn nhanh nhất, nhưng nếu hiệu suất không phải là vấn đề, bạn có thể sử dụng:

sum(~np.isnan(data)).

Hiệu suất:

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

Câu trả lời này cung cấp tổng không giống như đếm số phần tử ... Bạn nên sử dụng lenthay thế.
BenT

@BenT tổng các phần tử của mảng bool đáp ứng một điều kiện nhất định giống như cung cấp len của một mảng tập hợp con với các phần tử đáp ứng một điều kiện nhất định. Bạn có thể vui lòng làm rõ điều này là sai ở đâu?
GM

1
Sai lầm của tôi, tôi đã quên một Boolean được trả lại.
BenT

3

Để xác định xem mảng có thưa thớt hay không, có thể giúp lấy một tỷ lệ các giá trị nan

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

Nếu tỷ lệ đó vượt quá một ngưỡng, thì hãy sử dụng một mảng thưa thớt, ví dụ - https://sparse.pydata.org/en/latest/


2

Một giải pháp thay thế, nhưng chậm hơn một chút là thực hiện nó qua việc lập chỉ mục.

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 

Việc sử dụng kép np.isnan(data)==toán tử có thể hơi quá mức cần thiết và vì vậy tôi chỉ đăng câu trả lời cho đầy đủ.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.