การต่อเชื่อม NumPy อาร์เรย์หนึ่งมิติสองมิติ


266

ฉันมีสองอาร์เรย์ง่ายหนึ่งมิติในNumPy ฉันควรจะสามารถที่จะเชื่อมพวกเขาโดยใช้numpy.concatenate แต่ฉันได้รับข้อผิดพลาดสำหรับรหัสด้านล่างนี้:

TypeError: เฉพาะอาร์เรย์ความยาว 1 เท่านั้นที่สามารถแปลงเป็นสเกลาร์ Python

รหัส

import numpy
a = numpy.array([1, 2, 3])
b = numpy.array([5, 6])
numpy.concatenate(a, b)

ทำไม?


หากคุณต้องการที่จะเชื่อมพวกเขา (เป็นอาร์เรย์เดี่ยว) พร้อมnp.concatenat(..., axis)แกนใช้ np.vstackหากคุณต้องการเรียงซ้อนในแนวตั้งการใช้งาน หากคุณต้องการที่จะสแต็คพวกเขา (ลงในอาร์เรย์หลาย) np.hstackแนวนอนใช้ (หากคุณต้องการสแต็กข้อมูลเชิงลึกอย่างเช่นมิติที่สามใช้np.dstack) โปรดทราบว่าหลังมีความคล้ายคลึงกับหมีแพนด้าpd.concat
smci

คำตอบ:


372

บรรทัดควรเป็น:

numpy.concatenate([a,b])

อาร์เรย์ที่คุณต้องการเชื่อมต่อจำเป็นต้องผ่านเป็นลำดับไม่ใช่อาร์กิวเมนต์แยกต่างหาก

จากเอกสาร NumPy :

numpy.concatenate((a1, a2, ...), axis=0)

เข้าร่วมลำดับของอาร์เรย์ด้วยกัน

มันพยายามตีความคุณbว่าเป็นพารามิเตอร์แกนซึ่งเป็นเหตุผลว่าทำไมมันบ่นว่ามันไม่สามารถแปลงมันให้เป็นสเกลาร์ได้


1
ขอบคุณ! แค่อยากรู้อยากเห็น - ตรรกะที่อยู่เบื้องหลังสิ่งนี้คืออะไร?
user391339

8
@ user391339 จะเกิดอะไรขึ้นถ้าคุณต้องการเชื่อมสามอาร์เรย์เข้าด้วยกัน ฟังก์ชั่นนี้มีประโยชน์มากกว่าในการถ่ายภาพต่อเนื่องถ้ามันใช้สองอาร์เรย์
Winston Ewert

@ WinstonEwert สมมติว่าปัญหาไม่ใช่ว่าฮาร์ดโค้ดที่มีสองข้อโต้แย้งคุณสามารถใช้มันเหมือนnumpy.concatenate(a1, a2, a3)หรือnumpy.concatenate(*[a1, a2, a3])ถ้าคุณต้องการ Python มีความคล่องแคล่วพอที่จะทำให้ความแตกต่างเกิดความรู้สึกมากกว่าความงาม แต่มันก็ดีเมื่อ API นั้นสอดคล้องกัน (เช่นถ้าฟังก์ชั่น numpy ทั้งหมดที่รับรายการอาร์กิวเมนต์ความยาวผันแปรต้องมีลำดับที่ชัดเจน)
Jim K.

@JimK จะเกิดอะไรขึ้นกับพารามิเตอร์แกน?
Winston Ewert

1
สมมติว่าสิ่งที่จะเชื่อมต่อกันเป็นพารามิเตอร์ตำแหน่งทั้งหมดคุณสามารถรักษาแกนเป็นอาร์กิวเมนต์คำหลักเช่นdef concatx(*sequences, **kwargs)) ไม่เหมาะเนื่องจากคุณไม่สามารถตั้งชื่อคำหลักให้ชัดเจนในลายเซ็นด้วยวิธีนี้ แต่มีวิธีแก้ไขปัญหา
Jim K.

37

มีความเป็นไปได้หลายอย่างในการต่อเชื่อม 1D อาร์เรย์เช่น

numpy.r_[a, a],
numpy.stack([a, a]).reshape(-1),
numpy.hstack([a, a]),
numpy.concatenate([a, a])

ตัวเลือกทั้งหมดนั้นเร็วพอ ๆ กันสำหรับอาร์เรย์ขนาดใหญ่ สำหรับตัวเล็กconcatenateมีขอบเล็กน้อย:

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

พล็อตถูกสร้างขึ้นด้วยperfplot :

import numpy
import perfplot

perfplot.show(
    setup=lambda n: numpy.random.rand(n),
    kernels=[
        lambda a: numpy.r_[a, a],
        lambda a: numpy.stack([a, a]).reshape(-1),
        lambda a: numpy.hstack([a, a]),
        lambda a: numpy.concatenate([a, a]),
    ],
    labels=["r_", "stack+reshape", "hstack", "concatenate"],
    n_range=[2 ** k for k in range(19)],
    xlabel="len(a)",
)

9
np.concatenateทางเลือกการใช้งานทั้งหมด พวกเขานวดรายการอินพุตด้วยวิธีต่างๆก่อนถึงมือ np.stackตัวอย่างเช่นเพิ่มมิติพิเศษให้กับอาร์เรย์อินพุตทั้งหมด ดูซอร์สโค้ดของพวกเขา เพียง แต่concatenateจะรวบรวม
hpaulj

1
เพียงเพื่อเพิ่มความคิดเห็นของ @hpaulj - เวลาทั้งหมดมาบรรจบกันเมื่อขนาดของอาร์เรย์เพิ่มขึ้นเพราะnp.concatenateทำสำเนาของอินพุต หน่วยความจำและค่าใช้จ่ายเวลานี้จะมีค่ามากกว่าเวลาที่ใช้ในการ 'นวด' อินพุต
n1k31t4

31

พารามิเตอร์แรกที่concatenateตัวเองควรเป็นลำดับของอาร์เรย์ที่จะต่อกัน:

numpy.concatenate((a,b)) # Note the extra parentheses.

10

ทางเลือกอื่นคือใช้รูปแบบย่อของ "concatenate" ซึ่งเป็น "r _ [... ]" หรือ "c _ [... ]" ตามที่แสดงในตัวอย่างโค้ดด้านล่าง (ดูhttp://wiki.scipy.org / NumPy_for_Matlab_Usersสำหรับข้อมูลเพิ่มเติม):

%pylab
vector_a = r_[0.:10.] #short form of "arange"
vector_b = array([1,1,1,1])
vector_c = r_[vector_a,vector_b]
print vector_a
print vector_b
print vector_c, '\n\n'

a = ones((3,4))*4
print a, '\n'
c = array([1,1,1])
b = c_[a,c]
print b, '\n\n'

a = ones((4,3))*4
print a, '\n'
c = array([[1,1,1]])
b = r_[a,c]
print b

print type(vector_b)

ซึ่งผลลัพธ์ใน:

[ 0.  1.  2.  3.  4.  5.  6.  7.  8.  9.]
[1 1 1 1]
[ 0.  1.  2.  3.  4.  5.  6.  7.  8.  9.  1.  1.  1.  1.] 


[[ 4.  4.  4.  4.]
 [ 4.  4.  4.  4.]
 [ 4.  4.  4.  4.]] 

[[ 4.  4.  4.  4.  1.]
 [ 4.  4.  4.  4.  1.]
 [ 4.  4.  4.  4.  1.]] 


[[ 4.  4.  4.]
 [ 4.  4.  4.]
 [ 4.  4.  4.]
 [ 4.  4.  4.]] 

[[ 4.  4.  4.]
 [ 4.  4.  4.]
 [ 4.  4.  4.]
 [ 4.  4.  4.]
 [ 1.  1.  1.]]

2
vector_b = [1,1,1,1] #short form of "array", นี้เป็นเพียงไม่เป็นความจริง. vector_b จะเป็นประเภทรายการ Python มาตรฐาน Numpy นั้นค่อนข้างดีในการรับลำดับแทนที่จะบังคับให้อินพุตทั้งหมดเป็นประเภท numpy.array
Hannes Ovrén

2
คุณพูดถูก - ฉันผิด ฉันแก้ไขรหัสต้นฉบับและผลลัพธ์
Semjon Mössinger

0

นี่คือวิธีการอื่น ๆ อีกมากมายสำหรับการทำเช่นนี้โดยใช้numpy.ravel(), numpy.array()ใช้ความจริงที่ว่าอาร์เรย์ 1D สามารถแตกเป็นองค์ประกอบธรรมดา:

# we'll utilize the concept of unpacking
In [15]: (*a, *b)
Out[15]: (1, 2, 3, 5, 6)

# using `numpy.ravel()`
In [14]: np.ravel((*a, *b))
Out[14]: array([1, 2, 3, 5, 6])

# wrap the unpacked elements in `numpy.array()`
In [16]: np.array((*a, *b))
Out[16]: array([1, 2, 3, 5, 6])

0

ข้อเท็จจริงบางอย่างเพิ่มเติมจากเอกสาร numpy :

ด้วยไวยากรณ์เช่น numpy.concatenate((a1, a2, ...), axis=0, out=None)

Axis = 0 สำหรับการต่อข้อมูลแถวที่ชาญฉลาด row = 1 สำหรับการต่อข้อมูลแบบคอลัมน์ที่ชาญฉลาด

>>> a = np.array([[1, 2], [3, 4]])
>>> b = np.array([[5, 6]])

# Appending below last row
>>> np.concatenate((a, b), axis=0)
array([[1, 2],
       [3, 4],
       [5, 6]])

# Appending after last column
>>> np.concatenate((a, b.T), axis=1)    # Notice the transpose
array([[1, 2, 5],
       [3, 4, 6]])

# Flattening the final array
>>> np.concatenate((a, b), axis=None)
array([1, 2, 3, 4, 5, 6])

ฉันหวังว่ามันจะช่วย!

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