Numpy: Bagilah setiap baris dengan elemen vektor

119

Misalkan saya memiliki array numpy:

data = np.array([[1,1,1],[2,2,2],[3,3,3]])

dan saya memiliki "vektor:" yang sesuai

vector = np.array([1,2,3])

Bagaimana cara saya beroperasi di datasepanjang setiap baris untuk mengurangi atau membagi sehingga hasilnya adalah:

sub_result = [[0,0,0], [0,0,0], [0,0,0]]
div_result = [[1,1,1], [1,1,1], [1,1,1]]

Singkat cerita: Bagaimana cara melakukan operasi pada setiap baris array 2D dengan skalar 1D yang sesuai dengan setiap baris?

BFTM
sumber

Jawaban:

181

Ini dia. Anda hanya perlu menggunakan None(atau sebagai alternatif np.newaxis) dikombinasikan dengan penyiaran:

In [6]: data - vector[:,None]
Out[6]:
array([[0, 0, 0],
       [0, 0, 0],
       [0, 0, 0]])

In [7]: data / vector[:,None]
Out[7]:
array([[1, 1, 1],
       [1, 1, 1],
       [1, 1, 1]])
JoshAdel
sumber
13
di sini adalah doc.
sazary
2
sebuah contoh visual yang
PlsWork
@ user108569 menggunakan versi terbaru numpy (1.18.1), Nonemasih berfungsi sama dengan np.newaxis. Saya tidak yakin apa penyiapan Anda, atau masalah sebenarnya yang Anda alami, tetapi jawabannya masih valid.
JoshAdel
11

Seperti yang telah disebutkan, mengiris dengan Noneatau dengan np.newaxesadalah cara yang bagus untuk melakukan ini. Alternatif lain adalah menggunakan transposes dan penyiaran, seperti dalam

(data.T - vector).T

dan

(data.T / vector).T

Untuk array berdimensi lebih tinggi, Anda mungkin ingin menggunakan swapaxesmetode array NumPy atau rollaxisfungsi NumPy . Ada banyak cara untuk melakukan ini.

Untuk penjelasan lebih lengkap tentang penyiaran, lihat http://docs.scipy.org/doc/numpy/user/basics.broadcasting.html

IanH
sumber
4

Solusi JoshAdel menggunakan np.newaxis untuk menambahkan dimensi. Alternatifnya adalah menggunakan reshape () untuk menyelaraskan dimensi dalam persiapan penyiaran .

data = np.array([[1,1,1],[2,2,2],[3,3,3]])
vector = np.array([1,2,3])

data
# array([[1, 1, 1],
#        [2, 2, 2],
#        [3, 3, 3]])
vector
# array([1, 2, 3])

data.shape
# (3, 3)
vector.shape
# (3,)

data / vector.reshape((3,1))
# array([[1, 1, 1],
#        [1, 1, 1],
#        [1, 1, 1]])

Melakukan reshape () memungkinkan dimensi berbaris untuk penyiaran:

data:            3 x 3
vector:              3
vector reshaped: 3 x 1

Perhatikan bahwa data/vectortidak apa-apa, tetapi itu tidak memberi Anda jawaban yang Anda inginkan. Ini membagi masing-masing kolom dari array(bukannya setiap baris ) oleh setiap elemen yang sesuai vector. Itulah yang akan Anda dapatkan jika Anda secara eksplisit mengubah bentuk vectormenjadi, 1x3bukan 3x1.

data / vector
# array([[1, 0, 0],
#        [2, 1, 0],
#        [3, 1, 1]])
data / vector.reshape((1,3))
# array([[1, 0, 0],
#        [2, 1, 0],
#        [3, 1, 1]])
stackoverflowuser2010
sumber
2

Cara pythonic untuk melakukan ini adalah ...

np.divide(data.T,vector).T

Ini menangani pembentukan kembali dan juga hasilnya dalam format floating point. Dalam jawaban lain, hasil dalam format bilangan bulat bulat.

#CATATAN: Tidak ada kolom di data dan vektor yang harus cocok

shantanu pathak
sumber
Catatan: Ini tidak melakukan apa yang diminta OP. Hasil akhirnya adalah larik ([[1., 0.5, 0.33333333], [2., 1., 0.66666667], [3., 1.5, 1.]]). Ini mungkin 'Pythonic' tapi itu salah.
Mark Cramer
1
@MarkCramer Terima kasih. Saya telah mengoreksi jawaban saya untuk memberikan hasil yang benar.
shantanu pathak
1

Menambah jawaban stackoverflowuser2010, dalam kasus umum Anda bisa menggunakan

data = np.array([[1,1,1],[2,2,2],[3,3,3]])

vector = np.array([1,2,3])

data / vector.reshape(-1,1)

Ini akan mengubah vektor Anda menjadi column matrix/vector. Memungkinkan Anda melakukan operasi elementwise sesuai keinginan. Setidaknya bagi saya, ini adalah cara yang paling intuitif tentangnya dan karena (dalam banyak kasus) numpy hanya akan menggunakan tampilan memori internal yang sama untuk pembentukan kembali itu juga efisien.

meong
sumber
Ini harus menjadi jawaban yang diterima. Membuat vektor kolom dengan .reshape(-1,1) adalah cara paling intuitif untuk menggunakan penyiaran.
Paul Rougieux