การกำหนดค่าเริ่มต้นอาร์เรย์ NumPy (เติมด้วยค่าที่เหมือนกัน)


237

ฉันต้องการที่จะสร้างอาร์เรย์ NumPy ของความยาวองค์ประกอบของซึ่งแต่ละnv

มีอะไรที่ดีไปกว่า:

a = empty(n)
for i in range(n):
    a[i] = v

ฉันรู้zerosและonesจะทำงานกับ v = 0, 1 ฉันสามารถใช้งานv * ones(n)ได้ แต่มันจะไม่ทำงานเมื่อvเป็นNoneและจะช้ากว่ามาก


1
บนคอมพิวเตอร์ของฉัน 0 กรณีที่ใช้ในวงจะเร็วกว่าa = np.zeros(n) a.fill(0)นี่เป็นสิ่งที่ตรงกันข้ามกับสิ่งที่ฉันคาดไว้เนื่องจากฉันคิดว่าa=np.zeros(n)จะต้องจัดสรรและเริ่มต้นใช้หน่วยความจำใหม่ หากใครสามารถอธิบายสิ่งนี้ฉันจะขอบคุณมัน
3731622

คุณไม่สามารถใส่ None ในอาเรย์ numpy ได้เนื่องจากเซลล์ถูกสร้างขึ้นด้วยชนิดข้อมูลเฉพาะขณะที่ None มีชนิดของตัวเองและในความเป็นจริงแล้วเป็นตัวชี้
Camion

@Camion ใช่ฉันรู้แล้วตอนนี้ :) แน่นอนว่าv * ones(n)มันยังน่ากลัวเพราะมันใช้การคูณที่มีราคาแพง แทนที่*ด้วย+แม้ว่าและv + zeros(n)กลายเป็นสิ่งที่ดีอย่างน่าประหลาดใจในบางกรณี ( stackoverflow.com/questions/5891410/… )
สูงสุด

สูงสุดแทนที่จะสร้างอาร์เรย์ด้วยค่าศูนย์ก่อนที่จะเพิ่ม v มันยิ่งเร็วกว่าในการสร้างค่าว่างด้วยvar = np.empty(n)แล้วเติมด้วย 'var [:] = v' (btw np.full()เร็วเท่านี้)
Camion

คำตอบ:


308

แนะนำ NumPy 1.8 np.full()ซึ่งเป็นวิธีการโดยตรงมากกว่าempty()ตามด้วยfill()การสร้างอาร์เรย์ที่เต็มไปด้วยค่าที่แน่นอน:

>>> np.full((3, 5), 7)
array([[ 7.,  7.,  7.,  7.,  7.],
       [ 7.,  7.,  7.,  7.,  7.],
       [ 7.,  7.,  7.,  7.,  7.]])

>>> np.full((3, 5), 7, dtype=int)
array([[7, 7, 7, 7, 7],
       [7, 7, 7, 7, 7],
       [7, 7, 7, 7, 7]])

นี่คือเนื้อหาวิธีการสร้างอาร์เรย์ที่เต็มไปด้วยค่าบางอย่างเพราะมันชัดเจนอธิบายถึงสิ่งที่จะประสบความสำเร็จ (และมันสามารถในหลักการจะมีประสิทธิภาพมากตั้งแต่มันดำเนินงานที่เฉพาะเจาะจงมาก)


1
วิธีการแบบเต็ม () นี้ใช้งานได้ดีสำหรับฉัน แต่ฉันไม่สามารถหาเอกสารได้บ้าง ใครช่วยชี้ทางฉันให้ถูกที่ไหม?
James Adams

1
อย่างน้อยคุณสามารถทำได้help(numpy.full)ใน Python shell ฉันยังประหลาดใจที่มันไม่ได้อยู่ในเอกสารทางเว็บ
Eric O Lebigot

ในระบบของฉัน (Python 2.7, Numpy 1.8), np.full () จะช้ากว่า np.empty () เล็กน้อยตามด้วย np.fill ()
John Zwinck

1
สำหรับ 10,000 องค์ประกอบฉันสังเกตสิ่งเดียวกัน (ยกเว้นที่np.fill()ไม่มีอยู่และควรเป็นarr.fill()) โดยมีความแตกต่างประมาณ 10% หากความแตกต่างใหญ่กว่าฉันจะแจ้งปัญหาในเครื่องติดตามบั๊ก NumPy :) ฉันต้องการรหัสที่ชัดเจนและชัดเจนมากขึ้นสำหรับความแตกต่างเล็กน้อยในการใช้งานเวลาดังนั้นฉันไปกับnp.full()ตลอดเวลา
Eric O Lebigot

เมื่อวันที่ np.full เครื่องของฉัน () คือความเร็วเดียวกับ np.array.fill ()
Fnord

92

อัปเดตสำหรับ Numpy 1.7.0: (Hat-tip ถึง @Rolf Bartstra.)

a=np.empty(n); a.fill(5) เร็วที่สุด

ตามลำดับความเร็วจากมากไปน้อย:

%timeit a=np.empty(1e4); a.fill(5)
100000 loops, best of 3: 5.85 us per loop

%timeit a=np.empty(1e4); a[:]=5 
100000 loops, best of 3: 7.15 us per loop

%timeit a=np.ones(1e4)*5
10000 loops, best of 3: 22.9 us per loop

%timeit a=np.repeat(5,(1e4))
10000 loops, best of 3: 81.7 us per loop

%timeit a=np.tile(5,[1e4])
10000 loops, best of 3: 82.9 us per loop

13
การเพิ่มช่วงเวลาสำหรับสิ่งที่ใหม่กว่าและตรงไปตรงมาnp.full()จะมีประโยชน์ บนเครื่องของฉันด้วย NumPy 1.8.1 นั้นช้ากว่าfill()รุ่นโดยตรงน้อยกว่าประมาณ 15% (ซึ่งเป็นสิ่งที่ไม่คาดคิดเนื่องจากfull()มีแนวโน้มว่าจะเร็วขึ้นเล็กน้อย)
Eric O Lebigot

@DavidSanders: ฉันไม่แน่ใจว่าฉันกำลังติดตามคุณ: fill()เป็นทางออกที่เร็วที่สุด วิธีการคูณจะช้ากว่ามาก
Eric O Lebigot

2
หมายเหตุ: หากความเร็วเป็นปัญหาจริง ๆ การใช้ขนาด10000แทนที่จะ1e4สร้างความแตกต่างที่เห็นได้ชัดเจนด้วยเหตุผลบางอย่าง ( full()ช้ากว่าเกือบ 50% เมื่อใช้1e4)
Eric O Lebigot

เพียงเพิ่มผลลัพธ์ของฉันด้วยfull()มันจะทำงานช้าลงอย่างมากเมื่อประเภทข้อมูลนั้นไม่ลอยอย่างชัดเจน มิฉะนั้นจะเทียบได้ (แต่ช้ากว่าเล็กน้อย) ด้วยวิธีการที่ดีที่สุดที่นี่
user2699

@ user2699 ผมไม่ได้สังเกตนี้ 100,000 องค์ประกอบ: full(100000, 5), full(100000, 5, dtype=float), full(100000, 5, dtype=int)และa =np.empty(100000); a.fill(5)ใช้เวลาทั้งหมดในเวลาเดียวกันในเครื่องของฉัน (ไม่มีแคช: %timeit -r1 -n1 …) (NumPy 1.11.2)
Eric O Lebigot

65

ฉันเชื่อว่าfillเป็นวิธีที่เร็วที่สุดในการทำเช่นนี้

a = np.empty(10)
a.fill(7)

คุณควรหลีกเลี่ยงการทำซ้ำเหมือนอย่างที่คุณทำในตัวอย่างของคุณ วิธีง่ายๆที่a[:] = vจะทำให้การวนซ้ำของคุณทำได้โดยใช้การกระจายเสียงแบบไม่ยุ่งยาก


1
ขอบคุณ. เมื่อดูที่fillฉันเห็นว่าrepeatเหมาะสมกับความต้องการของฉันดียิ่งขึ้น
สูงสุด

คุณทราบการปรับปรุงคำตอบของคุณจะบอกว่าข้อเสนอแนะของคุณa[:]=vเป็นจริงได้เร็วขึ้นโดยรวมกว่าfill?
สูงสุด

@max เร็วขึ้นไหม? fillบรอดคาสติ้งเป็นวิธีทั่วไปมากขึ้นเพื่อเติมเต็มอาร์เรย์และฉันเดาจะช้าหรือเท่ากับกรณีการใช้งานที่แคบมาก
Paul

16

เห็นได้ชัดว่าไม่เพียง แต่ความเร็วสัมบูรณ์ แต่ยังสั่งความเร็ว(ตามที่รายงานโดยผู้ใช้ 1579844) ขึ้นอยู่กับเครื่อง นี่คือสิ่งที่ฉันพบ:

a=np.empty(1e4); a.fill(5) เร็วที่สุด;

ตามลำดับความเร็วจากมากไปน้อย:

timeit a=np.empty(1e4); a.fill(5) 
# 100000 loops, best of 3: 10.2 us per loop
timeit a=np.empty(1e4); a[:]=5
# 100000 loops, best of 3: 16.9 us per loop
timeit a=np.ones(1e4)*5
# 100000 loops, best of 3: 32.2 us per loop
timeit a=np.tile(5,[1e4])
# 10000 loops, best of 3: 90.9 us per loop
timeit a=np.repeat(5,(1e4))
# 10000 loops, best of 3: 98.3 us per loop
timeit a=np.array([5]*int(1e4))
# 1000 loops, best of 3: 1.69 ms per loop (slowest BY FAR!)

ดังนั้นลองค้นหาแล้วใช้สิ่งที่เร็วที่สุดบนแพลตฟอร์มของคุณ


14

ฉันมี

numpy.array(n * [value])

ในใจ แต่เห็นได้ชัดว่าจะช้ากว่าข้อเสนอแนะอื่น ๆ nทั้งหมดที่มีขนาดใหญ่พอ

นี่คือการเปรียบเทียบเต็มรูปแบบกับperfplot (โครงการสัตว์เลี้ยงของฉัน)

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

emptyทางเลือกสองทางยังคงเป็นวิธีที่เร็วที่สุด (ด้วย NumPy 1.12.1) fullจับขึ้นสำหรับอาร์เรย์ขนาดใหญ่


รหัสเพื่อสร้างพล็อต:

import numpy as np
import perfplot


def empty_fill(n):
    a = np.empty(n)
    a.fill(3.14)
    return a


def empty_colon(n):
    a = np.empty(n)
    a[:] = 3.14
    return a


def ones_times(n):
    return 3.14 * np.ones(n)


def repeat(n):
    return np.repeat(3.14, (n))


def tile(n):
    return np.repeat(3.14, [n])


def full(n):
    return np.full((n), 3.14)


def list_to_array(n):
    return np.array(n * [3.14])


perfplot.show(
    setup=lambda n: n,
    kernels=[empty_fill, empty_colon, ones_times, repeat, tile, full, list_to_array],
    n_range=[2 ** k for k in range(27)],
    xlabel="len(a)",
    logx=True,
    logy=True,
)

7

คุณสามารถใช้numpy.tileเช่น:

v = 7
rows = 3
cols = 5
a = numpy.tile(v, (rows,cols))
a
Out[1]: 
array([[7, 7, 7, 7, 7],
       [7, 7, 7, 7, 7],
       [7, 7, 7, 7, 7]])

แม้ว่าจะtileมีความหมายว่า 'ไทล์' อาเรย์ (แทนที่จะเป็นสเกลาร์, ในกรณีนี้), มันจะทำงาน, สร้างอาร์เรย์ที่มีขนาดและมิติใด ๆ ไว้ล่วงหน้า


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