Saya memiliki tiga array 2D numpy:

A1 with the shape of (x * y)
A2 with the shape of (x * z)
A3 with the shape of (y * z)

Nilai dalam tiga array adalah True atau False. Sekarang, saya ingin membuat array bentuk 3D (x * y * z) sehingga setiap elemen dalam array 3D berikut:

3D_array[x, y, z] = A1[x, y] & A2[x, z] & A3[y, z]

Saya tahu saya bisa melakukannya dengan satu lingkaran. Tetapi apakah ada cara yang lebih cepat untuk melakukan ini? Seperti melalui vektorisasi?

Atau, tiga larik 2D sebenarnya hanyalah beberapa interaksi berpasangan antara tiga larik 1D. Jadi cara yang lebih umum untuk menyajikan pertanyaan saya adalah:

Berikan tiga array numpy 1D (X), (Y), (Z) masing-masing dengan panjang x, y, z, apa cara terbaik untuk membuat array numpy 3D sehingga setiap elemen dalam array 3D sama dengan:

3D_array[i, j, k] = my_function(X[i], Y[j], Z[k])

Di mana my_function adalah fungsi khusus yang mengembalikan, katakanlah, Benar/Salah. Sekali lagi, saya mencari sesuatu yang lebih baik daripada perulangan.

Setiap solusi untuk pertanyaan pertama atau yang lebih umum disambut. Terimakasih banyak!

0
Briant 27 Mei 2021, 07:54

2 jawaban

Jawaban Terbaik

TL;DR:

np.apply_along_axis(sum, axis=0, np.stack(np.meshgrid(x, y, z)))

Panduan:

Mari kita lihat contoh konkret dan mulai dengan membuat tiga array 1-d:

x, y, z = [1, 2], [3, 4], [5, 6]

Sekarang, mari kita ubah ini menjadi meshgrid:

a, b, c = np.meshgrid(x, y, z)

Kali ini kita mendapatkan tiga array 3-d:

>>> a
array([[[1, 1],
        [2, 2]],

       [[1, 1],
        [2, 2]]])

Array ini sesuai dengan argumen pertama kami, yaitu 1 separuh waktu dan 2 separuh lainnya. Ini adalah dua nilai yang kita miliki di x. Kami memiliki total delapan nilai karena bentuk keluaran akhir kami seharusnya 2 x 2 x 2 = 8.

Demikian pula, kami memiliki b dan c:

>>> b
array([[[3, 3],
        [3, 3]],

       [[4, 4],
        [4, 4]]])
>>> c
array([[[5, 6],
        [5, 6]],

       [[5, 6],
        [5, 6]]])

Pada titik ini Anda sudah dapat mulai menggabungkan ketiga larik ini dengan berbagai cara sehingga untuk fungsi sederhana (yang dapat Anda bagi menjadi dua langkah), Anda cukup menjalankan a + b + c atau a & b & c.

Dalam kasus umum, Anda mungkin ingin mendefinisikan fungsi yang mengambil tiga angka dan menghasilkan satu keluaran berdasarkan logika arbitrer. Untuk menerapkan fungsi tersebut, pertama-tama kita perlu menumpuk ketiga fungsi ini array menjadi satu dengan melakukan:

>>> np.stack([a, b, c])
array([[[[1, 1],
         [2, 2]],

        [[1, 1],
         [2, 2]]],


       [[[3, 3],
         [3, 3]],

        [[4, 4],
         [4, 4]]],


       [[[5, 6],
         [5, 6]],

        [[5, 6],
         [5, 6]]]])

Sekarang kami memiliki tiga larik berukuran delapan (bentuk sebenarnya adalah 3,2,2,2) dan kami ingin terapkan fungsi delapan kali ke tiga angka sekaligus:

>>> np.apply_along_axis(sum, axis=0, np.stack(np.meshgrid(x, y, z)))
array([[[ 9, 10],
        [10, 11]],

       [[10, 11],
        [11, 12]]])

Kami mendapatkan delapan poin sebagai hasil seperti yang diharapkan di mana setiap poin adalah jumlah dari salah satu 1 atau 2, salah satu dari 3 atau 4 dan salah satu dari 5 atau 6.

Hati-hati bahwa numpy akan meneruskan array 1-d ke f daripada urutan argumen jadi jika Anda memiliki fungsi seperti:

def f(a, b, c):
  return a + b - c

Anda perlu mendefinisikan fungsi tambahan yang membungkus yang asli:

def f2(vals):
  return f(*vals)

# Alternatively:
f2 = lambda x: f(*x)

Jadi, sekarang kita bisa menerapkan f2 ke data kita:

>>> np.apply_along_axis(f2, 0, np.stack(np.meshgrid(x, y, z)))
array([[[-1, -2],
        [ 0, -1]],

       [[ 0, -1],
        [ 1,  0]]])
0
rudolfovic 27 Mei 2021, 08:12

Dengan penyiaran

3D_array[x, y, z] = A1[x, y] & A2[x, z] & A3[y, z]

Bisa dilakukan dengan:

B = A1[:,:,None] & A2[:,None,:] & A3[None,:,:]

Secara efektif ini mengubah semua 3 larik menjadi larik 3d yang bekerja sama dengan sebagian besar operator numpy.

Kasus yang lebih umum:

3D_array[i, j, k] = my_function(X[i], Y[j], Z[k])

Lebih sulit.

B = X[:,None,None] + Y[None,:,None] + Z[None,None,:]

Sekali lagi ini berfungsi untuk operator (dan ufunc) yang menggunakan penyiaran, tetapi tidak untuk fungsi yang ditentukan pengguna yang hanya berfungsi dengan skalar.

Saya ragu untuk menyarankan ini, tapi mungkin itu perlu. np.vectorize dapat membuat fungsi yang berfungsi dengan penyiaran seperti ini. Tapi itu bukan alat kinerja.

apply_along_axis yang disarankan di jawaban lain bukanlah alat kinerjanya. Iterasi pada sumbu other. Untuk array multidimensi seperti ini, kodenya dapat lebih sederhana daripada iterasi yang lebih eksplisit, tetapi tidak lebih cepat.

0
hpaulj 27 Mei 2021, 16:11