1. Arti bentuk dalam NumPy
Anda menulis, "Saya tahu ini daftar angka dan daftar daftar di mana semua daftar hanya berisi angka" tetapi itu sedikit cara yang tidak membantu untuk memikirkannya.
Cara terbaik untuk berpikir tentang array NumPy adalah bahwa mereka terdiri dari dua bagian, buffer data yang hanya merupakan blok elemen mentah, dan pandangan yang menjelaskan cara menafsirkan buffer data.
Misalnya, jika kita membuat array 12 bilangan bulat:
>>> a = numpy.arange(12)
>>> a
array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])
Kemudian a
terdiri dari buffer data, disusun seperti ini:
┌────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┐
│ 0 │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ 8 │ 9 │ 10 │ 11 │
└────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┘
dan tampilan yang menjelaskan cara menafsirkan data:
>>> 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,)
Di sini bentuknya (12,)
berarti array diindeks oleh indeks tunggal yang berjalan dari 0 hingga 11. Secara konseptual, jika kita memberi label pada indeks tunggal ini i
, array tersebut a
terlihat seperti ini:
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 │
└────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┘
Jika kami membentuk kembali sebuah array, ini tidak mengubah buffer data. Alih-alih, itu menciptakan tampilan baru yang menjelaskan cara berbeda untuk menginterpretasikan data. Jadi setelah:
>>> b = a.reshape((3, 4))
array b
memiliki buffer data yang sama dengan a
, tetapi sekarang diindeks oleh dua indeks yang berjalan dari 0 ke 2 dan 0 hingga 3 masing-masing. Jika kami memberi label pada dua indeks i
dan j
, array b
terlihat seperti ini:
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 │
└────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┘
yang berarti:
>>> b[2,1]
9
Anda dapat melihat bahwa indeks kedua berubah dengan cepat dan indeks pertama berubah dengan lambat. Jika Anda memilih ini sebagai sebaliknya, Anda dapat menentukan order
parameter:
>>> c = a.reshape((3, 4), order='F')
yang menghasilkan array yang diindeks seperti ini:
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 │
└────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┘
yang berarti:
>>> c[2,1]
5
Seharusnya sekarang menjadi jelas apa artinya bagi array untuk memiliki bentuk dengan satu atau lebih dimensi ukuran 1. Setelah:
>>> d = a.reshape((12, 1))
array d
diindeks oleh dua indeks, yang pertama berjalan dari 0 hingga 11, dan indeks kedua selalu 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 │
└────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┘
sehingga:
>>> d[10,0]
10
Dimensi panjang 1 adalah "bebas" (dalam arti tertentu), jadi tidak ada yang menghentikan Anda untuk pergi ke kota:
>>> e = a.reshape((1, 2, 1, 6, 1))
memberikan array yang diindeks seperti ini:
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 │
└────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┘
sehingga:
>>> e[0,1,0,0,0]
6
Lihat dokumentasi internal NumPy untuk detail lebih lanjut tentang bagaimana array diterapkan.
2. Apa yang harus dilakukan?
Karena numpy.reshape
hanya menciptakan tampilan baru, Anda tidak perlu takut menggunakannya kapan pun diperlukan. Ini alat yang tepat untuk digunakan ketika Anda ingin mengindeks array dengan cara yang berbeda.
Namun, dalam perhitungan yang panjang biasanya memungkinkan untuk mengatur untuk membangun array dengan bentuk "benar", dan dengan demikian meminimalkan jumlah pembentukan kembali dan transpos. Tetapi tanpa melihat konteks aktual yang mengarah pada kebutuhan untuk membentuk kembali, sulit untuk mengatakan apa yang harus diubah.
Contoh dalam pertanyaan Anda adalah:
numpy.dot(M[:,0], numpy.ones((1, R)))
tetapi ini tidak realistis. Pertama, ungkapan ini:
M[:,0].sum()
menghitung hasilnya lebih sederhana. Kedua, apakah benar-benar ada sesuatu yang istimewa tentang kolom 0? Mungkin yang sebenarnya Anda butuhkan adalah:
M.sum(axis=0)