ผลิตภัณฑ์ดอทสำหรับอาร์เรย์ NumPy ที่มีรูปร่างตามอำเภอใจ

เมื่อพิจารณาวัตถุ numpy.ndarray สองวัตถุ A และ B ที่มีรูปร่างตามใจชอบ ฉันต้องการคำนวณ numpy.ndarray C ด้วยคุณสมบัติที่ C[i] == np.dot(A[i], B[i]) สำหรับ i ทั้งหมด ฉันจะทำเช่นนี้ได้อย่างไร?

ตัวอย่างที่ 1: A.shape==(2,3,4) และ B.shape==(2,4,5) ดังนั้นเราควรมี C.shape==(2,3,5)

ตัวอย่างที่ 2: A.shape==(2,3,4) และ B.shape==(2,4) เราก็ควรมี C.shape==(2,3)


person dshin    schedule 20.06.2016    source แหล่งที่มา
comment
ดังนั้นรูปร่างของ A และ B จึงไม่ได้เป็นไปตามอำเภอใจโดยสิ้นเชิง จำเป็นต้องมีรูปร่างที่เข้ากันได้ในแต่ละ i กล่าวคือ A.shape[0] == B.shape[0] ต้องเป็น True   -  person piRSquared    schedule 20.06.2016
comment
einsum('ijk,ik...->ij...',A,B) จัดการ 2 กรณีของคุณ มันแค่จำกัด A ให้เป็น 3 มิติ, B อาจเป็น 2,3 เป็นต้น   -  person hpaulj    schedule 21.06.2016


คำตอบ (2)


นี่เป็นวิธีแก้ปัญหาทั่วไปที่ครอบคลุมทุกกรณี / รูปร่างตามอำเภอใจโดยใช้ reshaping และ np.einsum. einsum ช่วยได้ที่นี่เนื่องจากเราต้องการการจัดตำแหน่งตามแกนแรกและลดตามแกนสุดท้ายของอาร์เรย์อินพุต การใช้งานจะมีลักษณะเช่นนี้ -

def dotprod_axis0(A,B):
    N,nA,nB = A.shape[0], A.shape[-1], B.shape[1]
    Ar = A.reshape(N,-1,nA)
    Br = B.reshape(N,nB,-1)
    return np.squeeze(np.einsum('ijk,ikl->ijl',Ar,Br))

กรณีต่างๆ

ฉัน ก : 2D, B : 2D

In [119]: # Inputs
     ...: A = np.random.randint(0,9,(3,4))
     ...: B = np.random.randint(0,9,(3,4))
     ...: 

In [120]: for i in range(A.shape[0]):
     ...:     print np.dot(A[i], B[i])
     ...:     
33
86
48

In [121]: dotprod_axis0(A,B)
Out[121]: array([33, 86, 48])

ครั้งที่สอง ก : 3D, B : 3D

In [122]: # Inputs
     ...: A = np.random.randint(0,9,(2,3,4))
     ...: B = np.random.randint(0,9,(2,4,5))
     ...: 

In [123]: for i in range(A.shape[0]):
     ...:     print np.dot(A[i], B[i])
     ...:     
[[ 74  70  53 118  43]
 [ 47  43  29  95  30]
 [ 41  37  26  23  15]]
[[ 50  86  33  35  82]
 [ 78 126  40 124 140]
 [ 67  88  35  47  83]]

In [124]: dotprod_axis0(A,B)
Out[124]: 
array([[[ 74,  70,  53, 118,  43],
        [ 47,  43,  29,  95,  30],
        [ 41,  37,  26,  23,  15]],

       [[ 50,  86,  33,  35,  82],
        [ 78, 126,  40, 124, 140],
        [ 67,  88,  35,  47,  83]]])

III. ก : 3D, B : 2D

In [125]: # Inputs
     ...: A = np.random.randint(0,9,(2,3,4))
     ...: B = np.random.randint(0,9,(2,4))
     ...: 

In [126]: for i in range(A.shape[0]):
     ...:     print np.dot(A[i], B[i])
     ...:     
[ 87 105  53]
[152 135 120]

In [127]: dotprod_axis0(A,B)
Out[127]: 
array([[ 87, 105,  53],
       [152, 135, 120]])

IV. ก : 2D, B : 3D

In [128]: # Inputs
     ...: A = np.random.randint(0,9,(2,4))
     ...: B = np.random.randint(0,9,(2,4,5))
     ...: 

In [129]: for i in range(A.shape[0]):
     ...:     print np.dot(A[i], B[i])
     ...:     
[76 93 31 75 16]
[ 33  98  49 117 111]

In [130]: dotprod_axis0(A,B)
Out[130]: 
array([[ 76,  93,  31,  75,  16],
       [ 33,  98,  49, 117, 111]])
person Divakar    schedule 20.06.2016
comment
โดยทั่วไป np.dot(x,y) สามารถกำหนดได้ชัดเจนแม้เมื่อ len(x.shape)>2 และแม้กระทั่งเมื่อ len(x.shape)!=len(y.shape) ในทางปฏิบัติฉันอาจจะทำได้ถ้า/อย่างอื่นโดยขึ้นอยู่กับรูปร่างของ A และ B สำหรับบางกรณีที่ฉันสนใจอยู่ในปัจจุบัน แต่หวังว่าจะไม่ทำอย่างนั้น - person dshin; 20.06.2016
comment
@ดีชิน ใช่แล้ว! การปรับรูปร่างใหม่บางอย่างอาจช่วยได้ - person Divakar; 20.06.2016
comment
@dshin ตรวจสอบโค้ดที่แก้ไขแล้วเพื่อให้ครอบคลุมทุกกรณี! - person Divakar; 21.06.2016

สมมติว่าคุณต้องการการคูณเมทริกซ์แบบธรรมดาสำหรับ dot (ไม่ใช่พูดเมทริกซ์ - เวกเตอร์หรืออึแปลก ๆ dot ทำเพื่อมิติที่สูงกว่า) ดังนั้นเวอร์ชัน NumPy ล่าสุดที่เพียงพอ (1.10+) ก็ให้คุณทำได้

C = numpy.matmul(A, B)

และ Python เวอร์ชันล่าสุดที่เพียงพอ (3.5+) ให้คุณเขียนสิ่งนั้นเป็น

C = A @ B

สมมติว่า NumPy ของคุณยังล่าสุดเพียงพอ

person user2357112 supports Monica    schedule 20.06.2016
comment
ฉันได้เพิ่มตัวอย่างสองสามตัวอย่างใน OP ซึ่งหนึ่งในนั้นมีเมทริกซ์-เวกเตอร์ - person dshin; 20.06.2016