Permute matriks di tempat di numpy

27

Saya ingin memodifikasi matriks transisi persegi yang padat di tempat dengan mengubah urutan beberapa baris dan kolomnya, menggunakan perpustakaan numpy python. Secara matematis ini berhubungan dengan pra-mengalikan matriks dengan matriks permutasi P dan mengalikannya dengan P ^ -1 = P ^ T, tetapi ini bukan solusi yang masuk akal secara komputasi.

Saat ini saya secara manual bertukar baris dan kolom, tetapi saya berharap numpy memiliki fungsi yang bagus f (M, v) di mana M memiliki n baris dan kolom, dan v memiliki n entri, sehingga f (M, v) memperbarui M menurut indeks permutasi v. Mungkin saya hanya gagal mencari di internet.

Sesuatu seperti ini mungkin terjadi dengan "pengindeksan maju" numpy, tetapi pemahaman saya adalah bahwa solusi seperti itu tidak akan ada di tempat. Juga untuk beberapa situasi sederhana mungkin cukup untuk hanya secara terpisah melacak permutasi indeks, tetapi ini tidak nyaman dalam kasus saya.

Ditambahkan:
Kadang-kadang ketika orang berbicara tentang permutasi, mereka hanya berarti pengambilan sampel permutasi acak, misalnya sebagai bagian dari prosedur untuk mendapatkan nilai-p dalam statistik. Atau mereka berarti menghitung atau menghitung semua permutasi yang mungkin. Saya tidak membicarakan hal-hal ini.

Ditambahkan:
Matriks ini cukup kecil untuk masuk ke RAM desktop tetapi cukup besar sehingga saya tidak ingin menyalinnya tanpa berpikir. Sebenarnya saya ingin menggunakan matriks sebesar mungkin, tetapi saya tidak ingin berurusan dengan ketidaknyamanan karena tidak dapat menahan mereka dalam RAM, dan saya melakukan operasi O (N ^ 3) LAPACK pada matriks yang juga akan membatasi ukuran matriks praktis. Saya saat ini menyalin matriks sebesar ini tidak perlu, tetapi saya berharap ini dapat dengan mudah dihindari untuk permutasi.

tidak ada
sumber
3
Akan lebih baik jika Anda dapat memperbarui pertanyaan untuk memberikan ukuran matriks Anda. "Raksasa" tidak berarti hal yang sama untuk semua orang.
Bill Barth
2
Anda benar bahwa pengindeksan lanjutan (atau yang disebut fancy) membuat salinan. Tetapi jika Anda menerima untuk hidup dengan fakta itu maka kode Anda hanya M[v]untuk mengubah baris.
Daniel Velkov
@aniel: Dan itu akan menjadi M [v,:] [:, v] untuk melakukan permutasi keseluruhan? Apakah ini cara terbaik untuk mendapatkan permutasi menggunakan pengindeksan mewah? Dan apakah akan menggunakan 3x memori matriks, termasuk ukuran matriks asli, baris + kolom permutasi matriks, dan baris sementara matriks permutasi?
tidak ada
Itu benar, Anda akan memiliki matriks asli dan 2 salinan. Btw mengapa Anda perlu mengubah urutan baris dan kolom secara bersamaan?
Daniel Velkov
4
Apa yang akan Anda lakukan dengan matriks permutasi? Mungkin lebih baik untuk hanya mengubah vektor ketika menerapkan operator.
Jed Brown

Jawaban:

9

Menurut dokumen, tidak ada metode permutasi di tempat di numpy, seperti ndarray.sort .

Jadi pilihan Anda (dengan asumsi bahwa Madalah matriks dan vektor permutasi)N×Np

  1. mengimplementasikan algoritma Anda sendiri di C sebagai modul ekstensi (tetapi algoritma di tempat sulit, setidaknya bagi saya!)
  2. memori overheadN

    for i in range(N):
        M[:,i] = M[p,i]
    for i in range(N):
        M[i,:] = M[i,p]
  3. Memori overhead N 2N2

    M[:,:] = M[p,:]
    M[:,:] = M[:,p]

Semoga peretasan suboptimal ini bermanfaat.

Stefano M
sumber
@tidak ada hack 2. apa yang Anda sebut 'bertukar baris dan kolom secara manual'?
Stefano M
1
Saya akan menggabungkan opsi 1 dan 2: menulis kode C yang menggunakan buffer urutan N untuk menulis setiap kolom yang diijinkan, kemudian menulisnya kembali ke tempat asalnya; kemudian lakukan hal yang sama untuk baris. Seperti @Stefano menulis, ini hanya membutuhkan memori ekstra , yang sudah Anda habiskan untuk menyimpan permutasi p di tempat pertama. O(N)p
Erik P.
O(N)O(N)
2
Ini adalah calon yang sangat baik untuk fungsi cython. Tidak boleh lebih dari 10 baris. . . ingin aku memberikannya sedikit?
meawoppl
Lol. Saya mulai menggunakan Cython ini, kemudian menemukan jawaban yang benar dalam suatu fungsi yang saya gunakan sepanjang waktu. Doh. Lihat jawaban saya yang diposting.
meawoppl
6

Peringatan: Contoh di bawah ini berfungsi dengan baik, tetapi menggunakan set lengkap parameter yang disarankan di akhir posting memperlihatkan bug , atau setidaknya "fitur tidak terdokumentasi" di fungsi numpy.take (). Lihat komentar di bawah untuk detailnya. Laporan bug diajukan .

Anda dapat melakukan ini di tempat dengan fungsi take () numpy , tetapi membutuhkan sedikit lompatan melingkar.

Berikut adalah contoh melakukan permutasi acak dari baris-baris matriks identitas:

import numpy as np
i = np.identity(10)
rr = range(10)
np.random.shuffle(rr)
np.take(i, rr, axis=0)
array([[ 0.,  1.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.],
       [ 0.,  0.,  0.,  0.,  0.,  1.,  0.,  0.,  0.,  0.],
       [ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  1.,  0.],
       [ 0.,  0.,  0.,  0.,  0.,  0.,  1.,  0.,  0.,  0.],
       [ 0.,  0.,  0.,  1.,  0.,  0.,  0.,  0.,  0.,  0.],
       [ 0.,  0.,  0.,  0.,  1.,  0.,  0.,  0.,  0.,  0.],
       [ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  1.,  0.,  0.],
       [ 1.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.],
       [ 0.,  0.,  1.,  0.,  0.,  0.,  0.,  0.,  0.,  0.],
       [ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  1.]])

Untuk melakukannya di tempat, yang perlu Anda lakukan adalah menentukan parameter "out" agar sama dengan array input DAN Anda harus mengatur mode = "clip" atau mode = "wrap". Jika Anda tidak mengatur mode itu akan membuat salinan untuk mengembalikan keadaan array pada pengecualian Python (lihat di sini) .

Pada catatan terakhir, take tampaknya merupakan metode array, jadi alih-alih

np.take(i, rr, axis=0)

Anda bisa menelepon

i.take(rr, axis=0)

jika itu lebih sesuai dengan selera Anda. Jadi total yang Anda panggil akan terlihat seperti berikut:

#Inplace Rearrange
arr = makeMyBixMatrix()
pVec0, pVec1 = calcMyPermutationVectors()
arr.take(pVec0, axis=0, out=arr, mode="clip")
arr.take(pVec1, axis=1, out=arr, mode="clip")

Untuk mengubah kedua baris dan kolom saya pikir Anda harus menjalankannya dua kali, atau menarik beberapa shenanigans jelek dengan numpy.unravel_index yang menyakitkan kepala saya untuk dipikirkan.

meawoppl
sumber
Seperti yang dikatakan, algoritma di tempat sulit. Solusi Anda tidak bekerja dengan numpy 1.6.2. dan 1.7.1 (baris / kolom rangkap). Tidak punya waktu untuk memeriksa apakah 1.8.x memperbaiki masalah ini
Stefano M
Hmmm. Bisakah Anda memposting kode uji di suatu tempat? Di kepala saya, saya merasa seolah-olah perlu ada semacam operasi pada indeks yang terjadi terlebih dahulu sebelum pemetikan. Saya akan menyelidiki lebih lanjut PM ini.
meawoppl
1
Ketika saya menjalankan kode ini saya mendapatkan 1.6.2, test take, not overwriting: True, test not-in-place take: True, test in-place take: False, rr [3, 7, 8, 1, 4, 5, 9, 0, 2, 6], arr [30 70 80 70 40 50 90 30 80 90], ref [30 70 80 10 40 50 90 0 20 60]. Jadi np.takesetidaknya untuk numpy 1.6.2 tidak sadar melakukan permutasi di tempat dan mengacaukan segalanya.
Stefano M
Yeouch. Ditunjukkan dengan baik. Ini mungkin memenuhi syarat sebagai bug IMHO. Paling tidak dokumen harus mengatakan input dan output tidak bisa menjadi array yang sama, mungkin periksa untuk melihat dan kecuali jika itu.
meawoppl
Menyetujui bug: mungkin Anda harus menambahkan catatan ke posting Anda untuk memperingatkan pembaca bahwa solusi Anda dapat menghasilkan hasil yang salah.
Stefano M
2

Jika Anda memiliki matriks jarang disimpan dalam COOformat, berikut ini mungkin bermanfaat

    A.row = perm[A.row];
    A.col = perm[A.col];

ACOOpermnumpy.arraymm

Vincent Traag
sumber
tapi apa overhead memori untuk menyimpan matriks padat penuh sebagai C00matriks jarang di tempat pertama?
Federico Poloni
intfloatfloatn2numpy.ndarray
1

Saya tidak memiliki reputasi yang cukup untuk berkomentar, tetapi saya pikir pertanyaan SO berikut ini mungkin bermanfaat: /programming/4370745/view-onto-a-numpy-array

Poin dasar adalah bahwa Anda dapat menggunakan irisan dasar dan yang akan membuat tampilan ke array tanpa menyalin, tetapi jika Anda melakukan irisan / pengindeksan lanjutan maka itu akan membuat salinan.

hadsed
sumber
OP meminta permutasi, dan ini tidak mungkin dilakukan dengan pemotongan dasar.
Stefano M
Anda tentu saja benar. Saya pikir akan bermanfaat bagi OP untuk memahami apa yang terjadi dengan pengirisan (jika mereka tidak tahu) karena mereka khawatir tentang kapan salinan akan terjadi. Jika dia menggunakan sesuatu dari jawaban Anda, saya pikir itu akan baik untuk diketahui karena Anda menggunakannya di dalam loop Anda.
Hadsed
-1

Bagaimana dengan

my_array [:, [0, 1]] = my_array [:, [1, 0]]

johnsankey
sumber
1
Ini membangun sementara, yang persis ingin ia hindari.
Michael Grant