ความแตกต่างระหว่างรูปร่างของ numpy.array (R, 1) และ (R,)


319

ในnumpyการดำเนินการ(R, 1)บางอย่างกลับมาเป็นรูปร่างแต่กลับมา(R,)บ้าง สิ่งนี้จะทำให้การคูณเมทริกซ์น่าเบื่อมากขึ้นเนื่องจากreshapeจำเป็นต้องใช้อย่างชัดเจน ตัวอย่างเช่นได้รับเมทริกซ์Mถ้าเราต้องการที่จะทำnumpy.dot(M[:,0], numpy.ones((1, R)))ที่ไหนRจำนวนแถว (แน่นอนปัญหาเดียวกันยังเกิดขึ้นคอลัมน์ฉลาด) เราจะได้รับmatrices are not alignedข้อผิดพลาดตั้งแต่M[:,0]อยู่ในรูปร่าง(R,)แต่อยู่ในรูปnumpy.ones((1, R))(1, R)

ดังนั้นคำถามของฉันคือ:

  1. ความแตกต่างระหว่างรูปร่าง(R, 1)กับ(R,)อะไร ฉันรู้ว่ามันคือรายการของตัวเลขและรายการที่ทุกรายการมีเพียงตัวเลข เพียงแค่สงสัยว่าทำไมไม่ออกแบบnumpyเพื่อให้เหมาะกับรูปร่าง(R, 1)แทน(R,)การคูณเมทริกซ์ที่ง่ายขึ้น

  2. มีวิธีที่ดีกว่าสำหรับตัวอย่างข้างต้นหรือไม่ โดยไม่มีการปรับรูปร่างอย่างชัดเจน:numpy.dot(M[:,0].reshape(R, 1), numpy.ones((1, R)))


3
สิ่งนี้อาจช่วยได้ ไม่ได้กับการหาวิธีแก้ปัญหาในทางปฏิบัติว่า
keyser

1
วิธีแก้ปัญหาที่เหมาะสม: numpy.ravel (M [:, 0]) - แปลงรูปร่างจาก (R, 1) เป็น (R,)
Andi R

คำตอบ:


544

1. ความหมายของรูปร่างใน NumPy

คุณเขียนว่า "ฉันรู้ว่ามันคือรายการของตัวเลขและรายการที่ทุกรายการมีเพียงตัวเลข" แต่นั่นเป็นวิธีที่ไม่มีประโยชน์ที่จะคิดเกี่ยวกับมัน

วิธีที่ดีที่สุดในการคิดเกี่ยวกับอาร์เรย์ NumPy คือประกอบด้วยสองส่วนบัฟเฟอร์ข้อมูลซึ่งเป็นเพียงบล็อกขององค์ประกอบดิบและมุมมองที่อธิบายวิธีตีความบัฟเฟอร์ข้อมูล

ตัวอย่างเช่นถ้าเราสร้างอาร์เรย์จำนวนเต็ม 12 จำนวน:

>>> a = numpy.arange(12)
>>> a
array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11])

จากนั้นaประกอบด้วยบัฟเฟอร์ข้อมูลจัดเรียงดังนี้:

┌────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┐
  0   1   2   3   4   5   6   7   8   9  10  11 
└────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┘

และมุมมองที่อธิบายถึงวิธีการตีความข้อมูล:

>>> a.flags
  C_CONTIGUOUS : True
  F_CONTIGUOUS : True
  OWNDATA : True
  WRITEABLE : True
  ALIGNED : True
  UPDATEIFCOPY : False
>>> a.dtype
dtype('int64')
>>> a.itemsize
8
>>> a.strides
(8,)
>>> a.shape
(12,)

ที่นี่รูปร่าง (12,)หมายความว่าอาร์เรย์ถูกทำดัชนีโดยดัชนีเดี่ยวซึ่งเรียกใช้จาก 0 ถึง 11 ตามแนวคิดแล้วถ้าเราติดป้ายดัชนีเดี่ยวนี้iอาร์เรย์aจะมีลักษณะดังนี้:

i= 0    1    2    3    4    5    6    7    8    9   10   11
┌────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┐
  0   1   2   3   4   5   6   7   8   9  10  11 
└────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┘

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

>>> b = a.reshape((3, 4))

อาร์เรย์bมีบัฟเฟอร์ข้อมูลเหมือนกันaแต่ตอนนี้มันถูกจัดทำดัชนีโดยดัชนีสองตัวที่รันจาก 0 ถึง 2 และ 0 ถึง 3 ตามลำดับ หากเราติดป้ายกำกับดัชนีทั้งสองiและjอาร์เรย์bจะมีลักษณะดังนี้:

i= 0    0    0    0    1    1    1    1    2    2    2    2
j= 0    1    2    3    0    1    2    3    0    1    2    3
┌────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┐
  0   1   2   3   4   5   6   7   8   9  10  11 
└────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┘

ซึ่งหมายความว่า:

>>> b[2,1]
9

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

>>> c = a.reshape((3, 4), order='F')

ซึ่งผลลัพธ์ในอาร์เรย์ทำดัชนีดังนี้:

i= 0    1    2    0    1    2    0    1    2    0    1    2
j= 0    0    0    1    1    1    2    2    2    3    3    3
┌────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┐
  0   1   2   3   4   5   6   7   8   9  10  11 
└────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┘

ซึ่งหมายความว่า:

>>> c[2,1]
5

ตอนนี้มันควรจะชัดเจนว่ามันมีความหมายอย่างไรสำหรับอาเรย์ที่จะมีรูปร่างที่มีขนาดตั้งแต่หนึ่งขนาดขึ้นไปหลังจาก:

>>> d = a.reshape((12, 1))

อาเรย์dถูกทำดัชนีโดยดัชนีสองตัวอันแรกซึ่งรันจาก 0 ถึง 11 และดัชนีที่สองนั้นเป็น 0 เสมอ:

i= 0    1    2    3    4    5    6    7    8    9   10   11
j= 0    0    0    0    0    0    0    0    0    0    0    0
┌────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┐
  0   1   2   3   4   5   6   7   8   9  10  11 
└────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┘

และอื่น ๆ :

>>> d[10,0]
10

มิติของความยาว 1 คือ "ฟรี" (ในบางกรณี) ดังนั้นจึงไม่มีอะไรหยุดคุณจากการไปที่เมือง:

>>> e = a.reshape((1, 2, 1, 6, 1))

ให้อาร์เรย์จัดทำดัชนีเช่นนี้

i= 0    0    0    0    0    0    0    0    0    0    0    0
j= 0    0    0    0    0    0    1    1    1    1    1    1
k= 0    0    0    0    0    0    0    0    0    0    0    0
l= 0    1    2    3    4    5    0    1    2    3    4    5
m= 0    0    0    0    0    0    0    0    0    0    0    0
┌────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┐
  0   1   2   3   4   5   6   7   8   9  10  11 
└────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┘

และอื่น ๆ :

>>> e[0,1,0,0,0]
6

ดูเอกสารภายใน NumPyสำหรับรายละเอียดเพิ่มเติมเกี่ยวกับวิธีการใช้งานอาร์เรย์

2. จะทำอย่างไร?

ตั้งแต่ numpy.reshapeเพิ่งสร้างมุมมองใหม่คุณไม่ควรกลัวที่จะใช้มุมมองนี้เมื่อจำเป็น เป็นเครื่องมือที่เหมาะสมที่จะใช้เมื่อคุณต้องการจัดทำดัชนีอาร์เรย์ในวิธีอื่น

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

ตัวอย่างในคำถามของคุณคือ:

numpy.dot(M[:,0], numpy.ones((1, R)))

แต่นี่ไม่ใช่ความจริง ก่อนอื่นการแสดงออกนี้:

M[:,0].sum()

คำนวณผลลัพธ์ได้ง่ายขึ้น ประการที่สองมีอะไรพิเศษเกี่ยวกับคอลัมน์ 0 หรือไม่? บางทีสิ่งที่คุณต้องการคือ:

M.sum(axis=0)

33
สิ่งนี้มีประโยชน์อย่างมากในการคิดว่าจะจัดเก็บอาร์เรย์อย่างไร ขอบคุณ! การเข้าถึงคอลัมน์ (หรือแถว) ของเมทริกซ์ (2-d) สำหรับการคำนวณเมทริกซ์เพิ่มเติมนั้นไม่สะดวกแม้ว่าฉันจะต้องปรับแต่งคอลัมน์ใหม่อย่างเหมาะสมเสมอ ทุกครั้งที่ฉันต้องเปลี่ยนรูปร่างจาก (n,) เป็น (n, 1)
OfLettersAndNumbers

3
@SammyLee: ใช้newaxisถ้าคุณต้องการแกนอื่นตัวอย่างเช่นa[:, j, np.newaxis]เป็นjคอลัมน์ TH ของaและa[np.newaxis, i]เป็นiแถว TH
Gareth Rees

ฉันพยายามพล็อตดัชนีเพื่อให้เข้าใจกระดาษได้ดีขึ้นโดยแบบจำลองนี้และฉันดูเหมือนจะไม่เข้าใจถ้าฉันมีรูปร่าง 2 x 2 x 4 ฉันเข้าใจ 2 ตัวแรกสามารถเข้าใจได้เป็น 0000000011111111 และ 4 ตัวสุดท้ายสามารถ เข้าใจว่าเป็น 0123012301230123 เกิดอะไรขึ้นกับคนกลาง
PirateApp

3
วิธีง่าย ๆ ในการคิดเกี่ยวกับสิ่งนี้คือการที่ numpy ทำงานตรงตามที่คาดไว้ที่นี่ แต่การพิมพ์สิ่งอันดับของ Python อาจทำให้เข้าใจผิด ใน(R, )กรณีที่รูปร่างของndarraytuple ที่มีองค์ประกอบเดียวจึงถูกพิมพ์โดย Python ด้วยเครื่องหมายจุลภาคต่อท้าย โดยไม่ต้องจุลภาคพิเศษก็จะคลุมเครือกับการแสดงออกในวงเล็บ มีมิติเดียวสามารถแม้ว่าเป็นเวกเตอร์คอลัมน์ของความยาวndarray Rใน(R, 1)กรณี tuple มีสององค์ประกอบดังนั้นอาจจะคิดว่าเป็นเวกเตอร์แถว (หรือเมทริกซ์ที่มี 1 แถวยาวR.
ไมเคิลยาง

1
@ Alex-droidAD: ดูคำถามนี้และคำตอบ
Gareth Rees

16

ความแตกต่างระหว่าง(R,)และ(1,R)คือจำนวนดัชนีที่คุณต้องใช้อย่างแท้จริง ones((1,R))เป็นอาร์เรย์ 2 มิติที่เกิดขึ้นมีแถวเดียวเท่านั้น ones(R)เป็นเวกเตอร์ โดยทั่วไปหากไม่เหมาะสมที่ตัวแปรมีมากกว่าหนึ่งแถว / คอลัมน์คุณควรใช้เวกเตอร์ไม่ใช่เมทริกซ์ที่มีมิติเดียว

สำหรับกรณีเฉพาะของคุณมีสองตัวเลือกดังนี้:

1) เพียงแค่ทำให้อาร์กิวเมนต์ที่สองเป็นเวกเตอร์ งานดังต่อไปนี้ใช้ได้ดี:

    np.dot(M[:,0], np.ones(R))

2) ถ้าคุณต้องการ MATLAB เช่นการดำเนินงานของเมทริกซ์ใช้ในชั้นเรียนแทนmatrix ndarraymatricies ทั้งหมดถูกบังคับให้เป็นอาร์เรย์ 2 มิติและผู้ประกอบการ*ทำการคูณเมทริกซ์แทนองค์ประกอบฉลาด (ดังนั้นคุณไม่จำเป็นต้องจุด) จากประสบการณ์ของฉันนี่เป็นปัญหาที่มีค่ามากกว่า แต่อาจดีถ้าคุณคุ้นเคยกับ matlab


ใช่. ฉันคาดหวังว่าจะมีพฤติกรรมคล้ายกับ matlab มากขึ้น ฉันจะดูที่matrixชั้นเรียน ปัญหาในการmatrixเรียน BTW คืออะไร?
clwen

2
ปัญหากับการmatrixเป็นว่ามันเป็นเพียง 2D และยังว่าเพราะมัน overloads ประกอบการ '*' ฟังก์ชั่นที่เขียนขึ้นสำหรับอาจล้มเหลวหากใช้ในndarray matrix
Evan

11

รูปร่างเป็นสิ่งอันดับ หากมีเพียง 1 มิติรูปร่างจะเป็นตัวเลขหนึ่งและจะว่างเปล่าหลังเครื่องหมายจุลภาค สำหรับ 2 มิติจะมีตัวเลขอยู่หลังเครื่องหมายจุลภาคทั้งหมด

# 1 dimension with 2 elements, shape = (2,). 
# Note there's nothing after the comma.
z=np.array([  # start dimension
    10,       # not a dimension
    20        # not a dimension
])            # end dimension
print(z.shape)

(2)

# 2 dimensions, each with 1 element, shape = (2,1)
w=np.array([  # start outer dimension 
    [10],     # element is in an inner dimension
    [20]      # element is in an inner dimension
])            # end outer dimension
print(w.shape)

(2,1)


5

สำหรับคลาสอาเรย์พื้นฐานของมันอาร์เรย์ 2d นั้นไม่พิเศษกว่า 1d หรือ 3d มีการดำเนินการบางอย่างในการอนุรักษ์มิติบางอย่างที่ลดขนาดรวมอื่น ๆ หรือแม้แต่ขยาย

M=np.arange(9).reshape(3,3)
M[:,0].shape # (3,) selects one column, returns a 1d array
M[0,:].shape # same, one row, 1d array
M[:,[0]].shape # (3,1), index with a list (or array), returns 2d
M[:,[0,1]].shape # (3,2)

In [20]: np.dot(M[:,0].reshape(3,1),np.ones((1,3)))

Out[20]: 
array([[ 0.,  0.,  0.],
       [ 3.,  3.,  3.],
       [ 6.,  6.,  6.]])

In [21]: np.dot(M[:,[0]],np.ones((1,3)))
Out[21]: 
array([[ 0.,  0.,  0.],
       [ 3.,  3.,  3.],
       [ 6.,  6.,  6.]])

นิพจน์อื่นที่ให้อาร์เรย์เหมือนกัน

np.dot(M[:,0][:,np.newaxis],np.ones((1,3)))
np.dot(np.atleast_2d(M[:,0]).T,np.ones((1,3)))
np.einsum('i,j',M[:,0],np.ones((3)))
M1=M[:,0]; R=np.ones((3)); np.dot(M1[:,None], R[None,:])

MATLAB เริ่มต้นด้วยอาร์เรย์ 2 มิติ รุ่นใหม่ช่วยให้มิติมากขึ้น แต่ยังคงมีขีด จำกัด ล่างของ 2 แต่คุณยังคงต้องใส่ใจกับความแตกต่างระหว่างเมทริกซ์แถวและคอลัมน์หนึ่งหนึ่งที่มีรูปร่างวี(1,3) (3,1)คุณเขียนบ่อยแค่ไหน[1,2,3].'? ฉันกำลังจะเขียนrow vectorและcolumn vectorด้วยข้อ จำกัด 2 มิตินั้นไม่มีเวกเตอร์ใด ๆ ใน MATLAB - อย่างน้อยก็ไม่ได้อยู่ในความรู้สึกทางคณิตศาสตร์ของเวกเตอร์ว่าเป็น 1d

คุณเคยดูnp.atleast_2d(เช่น _1d และ _3d เวอร์ชั่น) หรือไม่


1

1) เหตุผลที่ไม่ชอบรูปร่างที่(R, 1)สูงเกินไป(R,)คือมันทำให้สิ่งต่าง ๆ มีความซับซ้อนโดยไม่จำเป็น นอกจากนี้ทำไมมันจะดีกว่าที่จะมีรูปร่างเป็น(R, 1)ค่าเริ่มต้นสำหรับเวกเตอร์ความยาว R แทน(1, R) ? มันจะดีกว่าเพื่อให้ง่ายและชัดเจนเมื่อคุณต้องการขนาดเพิ่มเติม

2) สำหรับตัวอย่างของคุณคุณกำลังประมวลผลผลิตภัณฑ์ด้านนอกเพื่อให้คุณสามารถทำได้โดยไม่ต้องreshapeโทรโดยใช้np.outer:

np.outer(M[:,0], numpy.ones((1, R)))

ขอบคุณสำหรับคำตอบ. 1) M[:,0]เป็นหลักได้รับแถวทั้งหมดที่มีองค์ประกอบแรกจึงทำให้รู้สึกมากขึ้นที่จะมีมากกว่า(R, 1) (1, R)2) มันไม่สามารถเปลี่ยนได้เสมอโดยnp.outerเช่นจุดสำหรับเมทริกซ์ในรูปร่าง (1, R) จากนั้น (R, 1)
clwen

1) ใช่นั่นอาจเป็นการประชุม แต่ก็ทำให้สะดวกกว่าในกรณีอื่น การประชุมอาจเป็นได้สำหรับ M [1, 1] เพื่อส่งกลับอาร์เรย์ (1, 1) รูปร่าง แต่ก็ยังสะดวกกว่าสเกลาร์ หากคุณต้องการพฤติกรรมที่เหมือนเมทริกซ์จริง ๆ แล้วคุณควรใช้matrixวัตถุดีกว่า 2) ที่จริงnp.outerการทำงานโดยไม่คำนึงว่ารูปทรงที่มี(1, R), (R, 1)หรือการรวมกันของทั้งสอง
bogatron

0

มีคำตอบที่ดีมากมายที่นี่แล้ว แต่สำหรับฉันมันยากที่จะหาตัวอย่างที่รูปร่างหรืออาร์เรย์สามารถทำลายโปรแกรมทั้งหมด

ดังนั้นนี่คือหนึ่ง:

import numpy as np
a = np.array([1,2,3,4])
b = np.array([10,20,30,40])


from sklearn.linear_model import LinearRegression
regr = LinearRegression()
regr.fit(a,b)

สิ่งนี้จะล้มเหลวโดยมีข้อผิดพลาด:

ValueError: คาดหวังว่าอาร์เรย์ 2 มิติมี 1D อาร์เรย์แทน

แต่ถ้าเราเพิ่มreshapeไปที่a:

a = np.array([1,2,3,4]).reshape(-1,1)

มันทำงานถูกต้อง!

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