Saya mencoba mengalikan masing-masing istilah dalam array 2D dengan istilah yang sesuai dalam array 1D. Ini sangat mudah jika saya ingin mengalikan setiap kolom dengan array 1D, seperti yang ditunjukkan pada numpy.multiply fungsi . Tapi saya ingin melakukan yang sebaliknya, mengalikan setiap suku di baris. Dengan kata lain saya ingin memperbanyak:
[1,2,3] [0]
[4,5,6] * [1]
[7,8,9] [2]
dan dapatkan
[0,0,0]
[4,5,6]
[14,16,18]
tapi malah saya dapatkan
[0,2,6]
[0,5,12]
[0,8,18]
Adakah yang tahu jika ada cara elegan untuk melakukannya dengan numpy? Terima kasih banyak, Alex
A * B
Anda harus melakukanA * B[...,None]
transposisi yang manaB
dengan menambahkan sumbu baru (None
).x = [[1],[2],[3]]
atau sesuatu.Jawaban:
Perkalian normal seperti yang Anda tunjukkan:
>>> import numpy as np >>> m = np.array([[1,2,3],[4,5,6],[7,8,9]]) >>> c = np.array([0,1,2]) >>> m * c array([[ 0, 2, 6], [ 0, 5, 12], [ 0, 8, 18]])
Jika Anda menambahkan sumbu, itu akan mengalikan seperti yang Anda inginkan:
>>> m * c[:, np.newaxis] array([[ 0, 0, 0], [ 4, 5, 6], [14, 16, 18]])
Anda juga dapat mengubah urutan dua kali:
>>> (m.T * c).T array([[ 0, 0, 0], [ 4, 5, 6], [14, 16, 18]])
sumber
[a,b] op [c,d] -> [[a*c, b*c], [a*d, b*d]]
.Saya telah membandingkan opsi kecepatan yang berbeda dan menemukan bahwa - sangat mengejutkan saya - semua opsi (kecuali
diag
) sama cepatnya. Saya pribadi menggunakanA * b[:, None]
(atau
(A.T * b).T
) karena pendek.Kode untuk mereproduksi plot:
import numpy import perfplot def newaxis(data): A, b = data return A * b[:, numpy.newaxis] def none(data): A, b = data return A * b[:, None] def double_transpose(data): A, b = data return (A.T * b).T def double_transpose_contiguous(data): A, b = data return numpy.ascontiguousarray((A.T * b).T) def diag_dot(data): A, b = data return numpy.dot(numpy.diag(b), A) def einsum(data): A, b = data return numpy.einsum("ij,i->ij", A, b) perfplot.save( "p.png", setup=lambda n: (numpy.random.rand(n, n), numpy.random.rand(n)), kernels=[ newaxis, none, double_transpose, double_transpose_contiguous, diag_dot, einsum, ], n_range=[2 ** k for k in range(13)], xlabel="len(A), len(b)", )
sumber
Anda juga bisa menggunakan perkalian matriks (alias perkalian titik):
a = [[1,2,3],[4,5,6],[7,8,9]] b = [0,1,2] c = numpy.diag(b) numpy.dot(c,a)
Mana yang lebih elegan mungkin soal selera.
sumber
dot
benar-benar berlebihan di sini. Anda hanya melakukan perkalian yang tidak perlu dengan 0 dan penambahan menjadi 0.diag
matriks padat .Namun trik lain (pada v1.6)
A=np.arange(1,10).reshape(3,3) b=np.arange(3) np.einsum('ij,i->ij',A,b)
Saya mahir dengan penyiaran numpy (
newaxis
), tetapi saya masih menemukan cara untuk menggunakaneinsum
alat baru ini . Jadi saya bermain-main sedikit untuk menemukan solusi ini.Pengaturan waktu (menggunakan waktu Ipython):
einsum: 4.9 micro transpose: 8.1 micro newaxis: 8.35 micro dot-diag: 10.5 micro
Kebetulan, mengubah
i
kej
,np.einsum('ij,j->ij',A,b)
, menghasilkan matriks yang Alex tidak mau. Dannp.einsum('ji,j->ji',A,b)
, pada dasarnya, transpose ganda.sumber
einsumm
(25 mikro) dua kali lebih cepat dari yang lain (dot-diag lebih melambat). Ini adalah np 1.7, baru saja dikompilasi dengan 'libatlas3gf-sse2' dan 'libatlas-base-dev' (Ubuntu 10.4, prosesor tunggal).timeit
memberikan yang terbaik dari 10.000 loop.numpy
versi sebelumnya.Bagi mereka yang kehilangan jiwa di google, menggunakan
numpy.expand_dims
thennumpy.repeat
akan berhasil, dan juga akan berfungsi dalam kasus dimensi yang lebih tinggi (yaitu mengalikan bentuk (10, 12, 3) dengan (10, 12)).>>> import numpy >>> a = numpy.array([[1,2,3],[4,5,6],[7,8,9]]) >>> b = numpy.array([0,1,2]) >>> b0 = numpy.expand_dims(b, axis = 0) >>> b0 = numpy.repeat(b0, a.shape[0], axis = 0) >>> b1 = numpy.expand_dims(b, axis = 1) >>> b1 = numpy.repeat(b1, a.shape[1], axis = 1) >>> a*b0 array([[ 0, 2, 6], [ 0, 5, 12], [ 0, 8, 18]]) >>> a*b1 array([[ 0, 0, 0], [ 4, 5, 6], [14, 16, 18]])
sumber
Mengapa Anda tidak melakukannya saja
>>> m = np.array([[1,2,3],[4,5,6],[7,8,9]]) >>> c = np.array([0,1,2]) >>> (m.T * c).T
??
sumber