สร้างเมทริกซ์ที่เต็มไปด้วย NaN


195

ฉันมีรหัสต่อไปนี้:

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

มันสร้างwidth x height x 9เมทริกซ์ที่เต็มไปด้วยศูนย์ แต่ฉันต้องการทราบว่ามีฟังก์ชั่นหรือวิธีการเริ่มต้นพวกเขาแทนที่จะNaNเป็นในวิธีที่ง่าย


2
ข้อแม้หนึ่งคือ NumPy ไม่มีค่า NA จำนวนเต็ม (ไม่เหมือนกับ R) ดูรายชื่อหมีแพนด้าของ gotchas ดังนั้นnp.nanจะผิดพลาดเมื่อเปลี่ยนเป็น int
smci

smci ถูกต้อง สำหรับ NumPy ไม่มีค่า NaN ดังกล่าว ดังนั้นขึ้นอยู่กับชนิดและบน NumPy ค่าใดที่จะมีสำหรับ NaN หากคุณไม่ทราบว่าสิ่งนี้จะทำให้เกิดปัญหา
MasterControlProgram

คำตอบ:


271

คุณไม่ค่อยต้องการลูปสำหรับการดำเนินการเวกเตอร์ในจำนวนมาก คุณสามารถสร้างอาร์เรย์ที่ไม่ได้กำหนดค่าเริ่มต้นและกำหนดให้กับรายการทั้งหมดได้ในครั้งเดียว:

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

ฉันหมดเวลาทางเลือกa[:] = numpy.nanที่นี่และa.fill(numpy.nan)โพสต์โดย 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

การกำหนดเวลาแสดงการตั้งค่าสำหรับndarray.fill(..)เป็นทางเลือกที่เร็วขึ้น OTOH ฉันชอบความสะดวกของผู้ใช้งานที่คุณสามารถกำหนดค่าให้กับส่วนทั้งหมดในเวลานั้นความตั้งใจของรหัสนั้นชัดเจนมาก

โปรดทราบว่าการndarray.fillดำเนินการดำเนินงานในสถานที่เพื่อจะกลับมาแทนnumpy.empty((3,3,)).fill(numpy.nan)None


8
ฉันยอมรับว่าความตั้งใจของรหัสของคุณชัดเจนขึ้น แต่ขอบคุณสำหรับการกำหนดเวลาที่เป็นกลาง (หรือมากกว่าความจริงที่ว่าคุณยังคงโพสต์พวกเขา) ผมขอบคุณมัน :)
เฆอิสราเอลPeña

2
a = numpy.empty((3, 3,)) * numpy.nanฉันเช่นนี้: มันจับเวลาเร็วกว่าfillแต่ช้ากว่าวิธีการมอบหมาย แต่มันเป็นแบบออนไลน์ !!
heltonbiker

2
โปรดดูคำตอบนี้: stackoverflow.com/questions/10871220/…
Ivan

3
ฉันชอบ.fill()วิธีนี้มากกว่า แต่ความแตกต่างของความเร็วจะลดลงจนแทบไม่มีอะไรเลยเมื่ออาร์เรย์มีขนาดใหญ่ขึ้น
naught101

4
... เพราะnp.empty([2, 5])สร้างอาเรย์แล้วfill()แก้ไขอาเรย์นั้นแทน แต่จะไม่ส่งคืนสำเนาหรือการอ้างอิง หากคุณต้องการโทรnp.empty(2, 5)ด้วยชื่อ ("มอบหมายให้กับตัวแปร") คุณต้องทำก่อนที่จะทำการดำเนินการในที่ [1, 2, 3].insert(1, 4)เดียวกันสิ่งที่เกิดขึ้นครับถ้าคุณทำ รายการถูกสร้างขึ้นและแทรก 4 แต่มันเป็นไปไม่ได้ที่จะได้รับการอ้างอิงไปยังรายการ (และมันสามารถสันนิษฐานได้ว่ามีการเก็บขยะ) บนข้อมูลที่ไม่เปลี่ยนรูปเช่นสตริงข้อความจะถูกส่งคืนเนื่องจากคุณไม่สามารถใช้งานได้ นุ่นสามารถทำทั้งสองอย่าง
flutefreak7

164

อีกตัวเลือกหนึ่งคือการใช้numpy.fullตัวเลือกที่มีอยู่ใน NumPy 1.8+

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

มันมีความยืดหยุ่นและคุณสามารถใส่หมายเลขอื่น ๆ ที่คุณต้องการได้


19
ฉันคิดว่านี่เป็นคำตอบที่ถูกต้องที่สุดเนื่องจากเป็นสิ่งที่fullมีไว้สำหรับ np.empy((x,y))*np.nanเป็นนักวิ่งที่ดี (และใช้งานร่วมกันได้สำหรับเวอร์ชันเก่าของ numpy)
travc

สิ่งนี้ช้ากว่านั้นfill 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 หากคุณใส่รหัสที่เทียบเท่ากับการวนรอบเวลาพวกเขาจะเหมือนกัน ทั้งสองวิธีมีความเท่าเทียมกันโดยทั่วไปคุณเพิ่งได้ "np.empty" นอกตัวจับเวลาในวิธีแรก 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

49

ฉันเปรียบเทียบทางเลือกที่แนะนำสำหรับความเร็วและพบว่าสำหรับเวกเตอร์ / เมทริกซ์ที่มีขนาดใหญ่พอที่จะเติมเต็มทางเลือกทั้งหมดยกเว้นval * onesและarray(n * [val])เร็วพอ ๆ กัน

ป้อนคำอธิบายรูปภาพที่นี่


รหัสในการทำซ้ำพล็อต:

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)",
)

แปลกที่numpy.full(n, val)ช้ากว่าa = numpy.empty(n) .. a.fill(val)เพราะมันทำสิ่งเดียวกันภายใน
endolith

26

คุณคุ้นเคยnumpy.nanหรือไม่

คุณสามารถสร้างวิธีการของคุณเองเช่น:

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

แล้วก็

nans([3,4])

จะส่งออก

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

ผมพบว่ารหัสนี้ในหัวข้อรายชื่อผู้รับจดหมาย


1
ดูเหมือนว่า overkill
นักฟิสิกส์บ้า

@MadPhysicist ที่ขึ้นอยู่กับสถานการณ์ของคุณทั้งหมด หากคุณต้องเริ่มต้นเพียงหนึ่ง NaN อาเรย์เดียวแล้วใช่ฟังก์ชั่นที่กำหนดเองน่าจะเป็น overkill อย่างไรก็ตามหากคุณต้องเริ่มต้นอาร์เรย์ NaN ที่หลาย ๆ แห่งในรหัสของคุณการมีฟังก์ชั่นนี้จะค่อนข้างสะดวก
Xukrao

1
@Xukaro ไม่จริงเนื่องจากมีฟังก์ชันที่มีความยืดหยุ่นและมีประสิทธิภาพมากกว่าอยู่แล้วและถูกกล่าวถึงในคำตอบอื่น ๆ
นักฟิสิกส์บ้า

10

คุณสามารถใช้การคูณได้เสมอถ้าคุณจำไม่ได้ทันที.emptyหรือ.fullวิธีการ:

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

แน่นอนมันทำงานได้กับค่าตัวเลขอื่น ๆ เช่นกัน:

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

แต่คำตอบที่ได้รับการยอมรับของ @ u0b34a0f6ae นั้นเร็วกว่า 3 เท่า (รอบการทำงานของ CPU ไม่ใช่รอบการทำงานของสมองที่จะจดจำไวยากรณ์ที่มีอยู่):

$ 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

อีกทางเลือกหนึ่งคือnumpy.broadcast_to(val,n)ผลตอบแทนในเวลาคงที่โดยไม่คำนึงถึงขนาดและยังเป็นหน่วยความจำที่มีประสิทธิภาพมากที่สุด (มันจะคืนค่ามุมมองขององค์ประกอบที่ทำซ้ำ) ข้อแม้คือค่าที่ส่งคืนเป็นแบบอ่านอย่างเดียว

ด้านล่างนี้คือการเปรียบเทียบของการแสดงของทุกวิธีการอื่น ๆ ที่ได้รับการเสนอให้ใช้มาตรฐานเช่นเดียวกับในคำตอบของนิโก้Schlömer

ป้อนคำอธิบายรูปภาพที่นี่


5

อย่างที่กล่าวไว้ว่า numpy.empty () เป็นวิธีที่จะไป อย่างไรก็ตามสำหรับวัตถุให้เติม () อาจไม่ทำสิ่งที่คุณคิดว่า:

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)

วิธีการหนึ่งสามารถเป็นเช่น:

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)

นอกเหนือจากการไม่มีคำถามเกี่ยวกับคำถามต้นฉบับเรียบร้อยแล้ว
นักฟิสิกส์บ้า

1
มันเกี่ยวกับ "การเริ่มต้นเมทริกซ์ numpy ให้เป็นอย่างอื่นที่ไม่ใช่ศูนย์หรืออย่างใดอย่างหนึ่ง" ในกรณีที่ "อย่างอื่น" เป็นวัตถุ :) (ยิ่งกว่านั้น google นำฉันมาที่นี่เพื่อเริ่มต้นด้วยรายการที่ว่างเปล่า)
ntg

3

ความเป็นไปได้อื่นที่ยังไม่ได้กล่าวถึงที่นี่คือการใช้แผ่นกระเบื้อง NumPy:

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

ยังให้

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

ฉันไม่รู้เกี่ยวกับการเปรียบเทียบความเร็ว

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