Telah benar-benar terjebak pada masalah yang agak konyol: Saya mencoba menghitung produk titik dari beberapa atribut di antara objek, tetapi terus mendapatkan Kesalahan Nilai - Bentuk Ketidakcocokan - tetapi bentuknya identik (2,1) dan (2,1 ), karena array hanyalah atribut dari instance berbeda dari kelas yang sama:

class MyClass(Object):
      def __init__(self, a,b, x,y):
          self.prop_1 = np.array((a,b))
          self.prop_2 = np.array((x,y))

Dimana semua a, b, x, dan y adalah skalar. kemudian lebih jauh ke bawah saya mencoba

def MyFunction(Obj1, Obj2):
    results = np.dot(Obj1.prop_1 - Obj2.prop_1, Obj2.prop_2 - Obj2.prop_3)

Yang terus melempar Nilai Kesalahan

ValueError: shapes (2,1) and (2,1) not aligned: 1 (dim 1) != 2 (dim 0)

Secara matematis, produk titik ini seharusnya baik-baik saja - tetapi bit terakhir dari jenis pesan kesalahan menyarankan saya harus mentranspos salah satu array. Saya akan sangat berterima kasih atas penjelasan singkat tentang interpretasi bentuk numpy untuk menghindari kesalahan semacam ini!

EDIT:

Pikir saya salah mengartikan ini sedikit. Ketika saya memulai objek saya melalui (kasus a)

a,b = np.random.rand(2)
x,y = np.random.rand(2)
MyClass(a, b, x, y)

Semuanya bekerja seperti pesona. Namun jika sebaliknya saya memulai sebagai (kasus b)

a = np.random.rand(1)
b = np.random.rand(1)
x = np.random.rand(1)
y = np.random.rand(1)
MyClass(a, b, x, y)

Produk titik nanti gagal berfungsi karena ketidakcocokan bentuk.

Saya perhatikan bahwa dalam kasus b, setiap nilai individu berbentuk (1,) dan jelas bagi saya bahwa menggabungkan dua nilai ini akan menghasilkan bentuk (2,1) alih-alih bentuk () dalam kasus a - tetapi mengapa kedua cara mendeklarasikan variabel ini menghasilkan bentuk yang berbeda?

Seperti yang Anda tahu saya relatif baru di Python dan berpikir ini hanya cara yang rapi untuk melakukan banyak tugas - ternyata ada beberapa alasan lebih lanjut di baliknya, dan saya akan tertarik untuk mendengarnya.

1
LoschmidtsSchnitzel 6 Juli 2020, 18:58

1 menjawab

Jawaban Terbaik

Bagian 1

Masalahnya adalah bahwa array Anda adalah matriks 2-D lengkap, bukan "vektor" 1D dalam artian np.dot memahaminya. Agar perkalian Anda berfungsi, Anda perlu (a) mengonversi vektor Anda menjadi vektor:

np.dot(a.reshape(-1), b.reshape(-1))

T

np.dot(a.T, b)

Atau (c), gunakan np.einsum untuk menyetel secara eksplisit dimensi jumlah:

np.einsum('ij,ij->j', a, b).item()

Untuk semua contoh yang menggunakan dot, Anda dapat menggunakan np.matmul (atau setara dengan operator @), atau np.tensordot, karena Anda memiliki larik 2D.

Secara umum, ingatlah aturan berikut saat bekerja dengan dot. Sel tabel adalah einsum subskrip

                                      A
      |         1D        |          2D         |                ND             |
   ---+-------------------+---------------------+-------------------------------+
   1D | i,i->             | ij,j->i             | a...yz,z->a...y               |
   ---+-------------------+---------------------+-------------------------------+
B  2D | i,ij->j           | ij,jk->ik           | a...xy,yz->a...xz             |
   ---+-------------------+---------------------+-------------------------------+
   ND | y,a...xyz->a...xz | ay,b...xyz->ab...xz | a...mxy,n...wyz->a...mxn...wz |
   ---+-------------------+---------------------+-------------------------------+

Pada dasarnya, dot mengikuti aturan normal untuk perkalian matriks sepanjang dua dimensi terakhir, tetapi dimensi terdepan selalu digabungkan. Jika Anda ingin dimensi utama disiarkan bersama untuk larik > 2D (yaitu, mengalikan elemen yang bersesuaian dalam tumpukan matriks, bukan semua kemungkinan kombinasi), gunakan matmul atau @ sebagai gantinya.

Bagian 2

Saat Anda menginisialisasi input sebagai a, b = np.random.rand(2), Anda membongkar dua elemen larik ke dalam skalar:

>>> a, b = np.random.rand(2)
>>> a
0.595823752387523
>>> type(a)
numpy.float64
>>> a.shape
()

Perhatikan bahwa jenisnya bukan numpy.ndarray dalam kasus ini. Namun, ketika Anda melakukan a = np.random.rand(1), hasilnya adalah larik 1D dari satu elemen:

>>> a = np.random.rand(1)a
>>> a
array([0.21983553])
>>> type(a)
numpy.ndarray
>>> a.shape
(1,)

Saat Anda membuat array numpy dari array numpy, hasilnya adalah array 2D:

>>> np.array([1, 2]).shape
(2,)
>>> np.array([np.array([1]), np.array([2])]).shape
(2, 1)

Ke depan, Anda memiliki dua opsi. Anda bisa lebih berhati-hati dengan input Anda, atau Anda bisa membersihkan array setelah Anda membuatnya.

Anda dapat memperluas array yang Anda masukkan:

ab = np.random.rand(2)
xy = np.random.rand(2)
MyClass(*ab, *xy)

Atau Anda bisa meratakan/menguraikan array setelah Anda membuatnya:

def __init__(self, a, b, x, y):
     self.prop_1 = np.array([a, b]).ravel()
     self.prop_2 = np.array([x, y]).ravel()

Anda dapat menggunakan ....reshape(-1) sebagai ganti ...ravel().

2
Mad Physicist 6 Juli 2020, 17:35