Tạo ma trận numpy chứa đầy NaN


195

Tôi có đoạn mã sau:

r = numpy.zeros(shape = (width, height, 9))

Nó tạo ra một width x height x 9ma trận chứa đầy số không. Thay vào đó, tôi muốn biết liệu có một chức năng hoặc cách để khởi tạo chúng thay vào NaNđó một cách dễ dàng.


2
Một điều lưu ý là NumPy không có giá trị NA nguyên (không giống R). Xem danh sách gấu trúc của gotchas . Do đó np.nanđi sai khi chuyển đổi sang int.
smci

smci là đúng Đối với NumPy không có giá trị NaN như vậy. Vì vậy, nó phụ thuộc vào loại và NumPy sẽ có giá trị nào cho NaN. Nếu bạn không biết điều này, nó sẽ gây rắc rối
MasterControlProgram

Câu trả lời:


271

Bạn hiếm khi cần các vòng lặp cho các hoạt động vector trong numpy. Bạn có thể tạo một mảng chưa được khởi tạo và gán cho tất cả các mục cùng một lúc:

>>> a = numpy.empty((3,3,))
>>> a[:] = numpy.nan
>>> a
array([[ NaN,  NaN,  NaN],
       [ NaN,  NaN,  NaN],
       [ NaN,  NaN,  NaN]])

Tôi đã hẹn giờ thay thế a[:] = numpy.nanở đây và a.fill(numpy.nan)như được đăng bởi Blaenk:

$ python -mtimeit "import numpy as np; a = np.empty((100,100));" "a.fill(np.nan)"
10000 loops, best of 3: 54.3 usec per loop
$ python -mtimeit "import numpy as np; a = np.empty((100,100));" "a[:] = np.nan" 
10000 loops, best of 3: 88.8 usec per loop

Thời gian hiển thị một ưu tiên cho ndarray.fill(..) sự thay thế nhanh hơn. OTOH, tôi thích triển khai tiện lợi của numpy khi bạn có thể gán giá trị cho toàn bộ lát cắt tại thời điểm đó, ý định của mã rất rõ ràng.

Lưu ý rằng ndarray.fillthực hiện hoạt động tại chỗ của nó, numpy.empty((3,3,)).fill(numpy.nan)thay vào đó sẽ trở lại None.


8
Tôi đồng ý rằng ý định mã của bạn rõ ràng hơn. Nhưng cảm ơn vì thời gian không thiên vị (hay đúng hơn, thực tế là bạn vẫn đăng chúng), tôi đánh giá cao nó :)
Jorge Israel Peña

2
Tôi thích cái này : a = numpy.empty((3, 3,)) * numpy.nan. Nó hẹn giờ nhanh hơn fillnhưng chậm hơn phương thức gán, nhưng nó là một oneliner !!
heltonbiker

2
Vui lòng xem câu trả lời này: stackoverflow.com/questions/10871220/ Kẻ
Ivan

3
Tôi thích .fill()phương pháp này, nhưng sự khác biệt về tốc độ giảm xuống thực tế không có gì khi các mảng trở nên lớn hơn.
ness101

4
... bởi vì np.empty([2, 5])tạo một mảng, sau đó fill()sửa đổi mảng đó tại chỗ, nhưng không trả về một bản sao hoặc một tham chiếu. Nếu bạn muốn gọi np.empty(2, 5)bằng một tên ("gán cho một biến"), bạn phải làm như vậy trước khi bạn thực hiện các thao tác tại chỗ trên nó. Điều tương tự sẽ xảy ra nếu bạn làm [1, 2, 3].insert(1, 4). Danh sách được tạo và 4 được chèn, nhưng không thể có được một tham chiếu đến danh sách (và do đó nó có thể được coi là đã được thu gom rác). Trên dữ liệu không thay đổi như chuỗi, một bản sao được trả về, vì bạn không thể vận hành tại chỗ. Gấu trúc có thể làm cả hai.
flutefreak7

163

Một tùy chọn khác là sử dụng numpy.full, một tùy chọn có sẵn trong NumPy 1.8+

a = np.full([height, width, 9], np.nan)

Điều này khá linh hoạt và bạn có thể điền nó với bất kỳ số nào khác mà bạn muốn.


19
Tôi coi đây là câu trả lời đúng nhất vì nó hoàn toàn fullcó nghĩa là gì. np.empy((x,y))*np.nanlà một người chạy tốt (và khả năng tương thích cho các phiên bản cũ của numpy).
travc

cái này chậm hơnfill python -mtimeit "import numpy as np; a = np.empty((100,100));" "a.fill(np.nan)" 100000 loops, best of 3: 13.3 usec per loop python -mtimeit "import numpy as np; a = np.full((100,100), np.nan);" 100000 loops, best of 3: 18.5 usec per loop
Farnabaz

5
@Farnabaz Nếu bạn đặt mã tương đương bên trong vòng lặp thời gian thì chúng giống nhau. Hai phương thức cơ bản là bằng nhau, bạn vừa có "np.empty" bên ngoài bộ đếm thời gian trong phương thức đầu tiên. python -mtimeit "import numpy as np; a = np.empty((1000,1000)); a.fill(np.nan)" 1000 loops, best of 3: 381 usec per loop $ python -mtimeit "import numpy as np; a = np.full((1000,1000), np.nan);" 1000 loops, best of 3: 383 usec per loop
Scott Staniewicz

47

Tôi đã so sánh các phương án được đề xuất cho tốc độ và thấy rằng, đối với các vectơ / ma trận đủ lớn để điền vào, tất cả các phương án ngoại trừ val * onesarray(n * [val])đều nhanh như nhau.

nhập mô tả hình ảnh ở đây


Mã để tái tạo cốt truyện:

import numpy
import perfplot

val = 42.0


def fill(n):
    a = numpy.empty(n)
    a.fill(val)
    return a


def colon(n):
    a = numpy.empty(n)
    a[:] = val
    return a


def full(n):
    return numpy.full(n, val)


def ones_times(n):
    return val * numpy.ones(n)


def list(n):
    return numpy.array(n * [val])


perfplot.show(
    setup=lambda n: n,
    kernels=[fill, colon, full, ones_times, list],
    n_range=[2 ** k for k in range(20)],
    logx=True,
    logy=True,
    xlabel="len(a)",
)

Lạ mà numpy.full(n, val)là chậm hơn so với a = numpy.empty(n) .. a.fill(val)vì nó làm điều tương tự trong nội bộ
endolith

26

Bạn có quen thuộc với numpy.nan không?

Bạn có thể tạo phương thức của riêng bạn, chẳng hạn như:

def nans(shape, dtype=float):
    a = numpy.empty(shape, dtype)
    a.fill(numpy.nan)
    return a

Sau đó

nans([3,4])

sẽ xuất

array([[ NaN,  NaN,  NaN,  NaN],
       [ NaN,  NaN,  NaN,  NaN],
       [ NaN,  NaN,  NaN,  NaN]])

Tôi tìm thấy mã này trong một chủ đề danh sách gửi thư .


1
Có vẻ như quá mức cần thiết.
Nhà vật lý điên

@MadPhysicist Điều đó phụ thuộc hoàn toàn vào tình huống của bạn. Nếu bạn phải khởi tạo chỉ một mảng NaN duy nhất, thì có, một chức năng tùy chỉnh có thể là quá mức cần thiết. Tuy nhiên, nếu bạn phải khởi tạo một mảng NaN tại hàng chục vị trí trong mã của mình, thì việc có chức năng này trở nên khá thuận tiện.
Xukrao

1
@Xukaro. Không thực sự, cho rằng một phiên bản linh hoạt và hiệu quả hơn của một chức năng như vậy đã tồn tại và được đề cập trong nhiều câu trả lời khác.
Nhà vật lý điên

10

Bạn luôn có thể sử dụng phép nhân nếu bạn không nhớ lại ngay lập tức .emptyhoặc .fullcác phương thức:

>>> np.nan * np.ones(shape=(3,2))
array([[ nan,  nan],
       [ nan,  nan],
       [ nan,  nan]])

Tất nhiên nó cũng hoạt động với bất kỳ giá trị số nào khác:

>>> 42 * np.ones(shape=(3,2))
array([[ 42,  42],
       [ 42,  42],
       [ 42, 42]])

Nhưng câu trả lời được chấp nhận của @ u0b34a0f6ae nhanh hơn gấp 3 lần (chu kỳ CPU, không phải chu kỳ não để ghi nhớ cú pháp numpy;):

$ python -mtimeit "import numpy as np; X = np.empty((100,100));" "X[:] = np.nan;"
100000 loops, best of 3: 8.9 usec per loop
(predict)laneh@predict:~/src/predict/predict/webapp$ master
$ python -mtimeit "import numpy as np; X = np.ones((100,100));" "X *= np.nan;"
10000 loops, best of 3: 24.9 usec per loop

6

Một cách khác là numpy.broadcast_to(val,n) trả về trong thời gian không đổi bất kể kích thước và cũng là bộ nhớ hiệu quả nhất (nó trả về một khung nhìn của phần tử lặp lại). Thông báo trước là giá trị trả về là chỉ đọc.

Dưới đây là so sánh hiệu suất của tất cả các phương pháp khác đã được đề xuất bằng cách sử dụng cùng một tiêu chuẩn như trong câu trả lời của Nico Schlömer .

nhập mô tả hình ảnh ở đây


5

Như đã nói, numpy.empty () là con đường để đi. Tuy nhiên, đối với các đối tượng, fill () có thể không thực hiện chính xác những gì bạn nghĩ:

In[36]: a = numpy.empty(5,dtype=object)
In[37]: a.fill([])
In[38]: a
Out[38]: array([[], [], [], [], []], dtype=object)
In[39]: a[0].append(4)
In[40]: a
Out[40]: array([[4], [4], [4], [4], [4]], dtype=object)

Một cách xung quanh có thể là:

In[41]: a = numpy.empty(5,dtype=object)
In[42]: a[:]= [ [] for x in range(5)]
In[43]: a[0].append(4)
In[44]: a
Out[44]: array([[4], [], [], [], []], dtype=object)

Ngoài việc hầu như không có gì để làm với câu hỏi ban đầu, gọn gàng.
Nhà vật lý điên

1
Chà, đó là về "Khởi tạo ma trận numpy thành một cái gì đó khác không hoặc một", trong trường hợp "cái gì đó khác" là một đối tượng :) (Thực tế hơn, google đã dẫn tôi đến đây để khởi tạo với một danh sách trống)
ntg

3

Một khả năng khác chưa được đề cập ở đây là sử dụng lát NumPy:

a = numpy.tile(numpy.nan, (3, 3))

Cũng cho

array([[ NaN,  NaN,  NaN],
       [ NaN,  NaN,  NaN],
       [ NaN,  NaN,  NaN]])

Tôi không biết về so sánh tốc độ.

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.