Numpy içinde yerinde bir matris geçirme


27

Python's numpy kitaplığını kullanarak, satırlarının ve sütunlarının birçoğunun sırasını değiştirerek, yoğun bir kare geçiş matrisini yerinde değiştirmek istiyorum. Matematiksel olarak bu, matrisin permütasyon matrisi P ile önceden çarpılması ve P ^ -1 = P ^ T ile çarpılması ve sonradan hesaplanması açısından makul bir çözüm değildir.

Şu anda elle satırları ve sütunları değiştiriyorum, ancak N'nin n satır ya da sütuna sahip olduğu f'nin (M, v) güzel bir işlevi olmasını ve f'nin (M, v) güncellemelerini sağlayacak şekilde n girişleri olmasını beklerdim. Endeks müsaadesine göre v. Belki de sadece internette arama yapmakta başarısız oluyorum.

Bunun gibi bir şey, numpy'nin “gelişmiş indeksleme” si ile mümkün olabilir, fakat benim fikrim, böyle bir çözümün yerinde olmamasıdır. Ayrıca bazı basit durumlar için, bir endeks permütasyonunu sadece ayrı olarak izlemek yeterli olabilir, ancak bu benim durumumda uygun değil.

Eklendi:
Bazen insanlar permütasyonlar hakkında konuştuğunda, örneğin istatistiklerde p-değerleri elde etme prosedürünün bir parçası olarak sadece rastgele permütasyonların örneklenmesi anlamına gelir. Veya tüm olası permütasyonları saymak veya saymak anlamına gelir. Bu şeyler hakkında konuşmuyorum.

Eklendi:
Matris, masaüstü RAM'e sığacak kadar küçük, ancak düşüncesizce kopyalamak istemediğim kadar büyük. Aslında matrisleri mümkün olduğu kadar büyük kullanmak istiyorum, ancak bunları RAM'de tutamamak zorluğuyla uğraşmak istemiyorum ve matris üzerinde O (N ^ 3) LAPACK işlemi yapıyorum. pratik matris boyutunu sınırlayın. Şu anda matrisleri gereksiz yere bu kadar büyük kopyalıyorum, ancak bunun permütasyon için kolayca önlenebileceğini umuyorum.


3
Matrislerinizin boyutunu vermek için soruyu güncellemeniz iyi olurdu. "Gigantic" bütün insanlar için aynı anlama gelmez.
Bill Barth

2
Gelişmiş (veya fantezi adı verilen) endekslemenin bir kopya oluşturması konusunda haklısınız. Ancak bu gerçek ile yaşamayı kabul ederseniz, kodunuz sadece M[v]satırlara izin vermektir.
Daniel Velkov

@ daniel: Ve bütün müsaadeyi yapmak M [v,:] [:, v] olur mu? Fantezi indeksleme kullanarak izin almanın en iyi yolu bu mu? Ve orijinal matrisin boyutu, satır + sütun izinli matris ve geçici satır izinli matris de dahil olmak üzere 3 kat matris belleği kullanır mıydı?
hiçbiri

Bu doğru, orijinal matrisinizi ve 2 kopyanızı alırsınız. BT, neden aynı anda hem de hem de sütunlara izin vermeniz gerekiyor?
Daniel Velkov

4
İzin verilen matrisle ne yapacaksın? İşleci uygularken vektöre basitçe izin vermek daha iyi olabilir.
Jed Brown

Yanıtlar:


9

Dokümanlara göre, numdar'da ndarray.sort gibi herhangi bir yerinde permütasyon metodu yoktur .

Yani seçenekleriniz (bunun Mbir matrisi ve permütasyon vektörü olduğu varsayılmaktadır )N×Np

  1. kendi algoritmanızı bir C modülünde bir uzatma modülü olarak uygulamak (ancak yerinde algoritmalar zor, en azından benim için!)
  2. N bellek yükü

    for i in range(N):
        M[:,i] = M[p,i]
    for i in range(N):
        M[i,:] = M[i,p]
    
  3. N2 bellek yükü

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

Umarım bu asılsız hackler faydalıdır.


@ hiçbiri hack 2. ne diyorsun 'elle satırları ve sütunları değiştirerek'?
Stefano M

1
Seçenekler 1 ve 2'yi birleştiririm: her izin verilen sütunu yazmak için N sırası bir tampon kullanan C kodunu yazar, sonra geldiği yere yazar; sonra satırlar için de aynısını yapın. @Stefano'nun yazdığı gibi, bu, sadece ilk etapta saklamak için harcadığınız ekstra belleği alır . pO(N)p
Erik P.,

@ErikP. Bir C uygulaması için fazladan bellek makul ve saçma yazıcınızın geçici ve kopyalamak için yazdığı yaklaşımın kesin olduğu kesin. Ancak ilginç soru, ekstra bellek verilen daha etkili algoritmalar olup olmadığıdır . Cevabı zor, çünkü işlemci mimarisini, bellek erişim düzenlerini, önbellek vuruşlarını dikkate almalıyız ... Bu sizin tavsiyenizi izleyeceğimi ve basit ve uygulaması kolay bir algoritma kullanacağımı söyledi. 0 ( N )O(N)O(N)
Stefano M

2
Bu bir cython işlevi için gerçekten iyi bir canidate. 10 satırdan fazla olamaz. . . bir çatlak vermemi ister misin?
meawoppl

Lol. Bunu Cython'a başladım, sonra her zaman kullandığım bir fonksiyonda doğru cevabı buldum. Hamuru. Gönderilmiş cevabımı gör.
meawoppl

6

Uyarı: Aşağıdaki örnek düzgün çalışır, ancak posta ucunda önerilen tüm parametrelerin kullanılması, bir hata veya en azından numpy.take () işlevinde "belgelenmemiş bir özellik" ortaya çıkarır . Ayrıntılar için aşağıdaki yorumlara bakınız. Hata raporu verildi .

Numpy'nin take () işleviyle bunu yerinde yapabilirsiniz , ancak biraz çember atlama gerektirir.

Bir kimlik matrisinin satırlarına rastgele bir permütasyon yapma örneği:

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.]])

Yerinde yapmak için yapmanız gereken tek şey "out" parametresini giriş dizisi ile aynı olacak şekilde belirlemektir VE mode = "clip" veya mode = "wrap" ayarlamanız gerekir. Modu ayarlamadıysanız, Python istisnasında dizi durumunu geri yüklemek için bir kopya oluşturulur (buraya bakın) .

Son bir notta, almak yerine bir dizi yöntemi gibi görünüyor

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

arayabilirsin

i.take(rr, axis=0)

eğer bu damak zevkinize uygunsa. Yani toplamda aradığınız aşağıdaki gibi bir şey olmalı

#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")

Hem satırlara hem de sütunlara izin vermek için bence ya iki kere çalıştırmanız gerekecek ya da düşünmek için başımı inciten numpy.unravel_index ile çirkin bazı şeytanları çekin .


Dediği gibi, yerinde algoritmalar zor. Çözümünüz numpy 1.6.2 ile çalışmıyor . ve 1.7.1 (yinelenen satırlar / sütunlar). 1.8.x'in bu sorunu çözüp çözmediğini kontrol etmek için zaman yoktu
Stefano M

Hmmm. Test kodunu bir yere gönderebilir misin? Kafamda, kopmadan önce olan endekslerde bir sıralama işlemi yapılması gerektiğini düşünüyorum. Bu PM hakkında daha fazla araştırma yapacağım.
meawoppl

1
Ben çalıştırdığınızda bu kodu alıyorum 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]. Yani np.takeen azından 1.6.2 numpy için yerinde bir permütasyon yapmanın farkında değil ve işleri berbat ediyor.
Stefano M

Yeouch. İyi gösterdi. Bu muhtemelen bir IMHO hatası olarak nitelendirilir. En azından, dokümanlar girdi ve çıktı aynı dizi olamaz diyebilir, muhtemelen olup olmadığını görmek için kontrol edin.
meawoppl

Böceğe karar verildi: belki de okuyucunuza çözümünüzün yanlış sonuçlar verebileceği konusunda uyarmak için yazınıza bir not eklemelisiniz.
Stefano M

2

COOFormatında saklanmış seyrek bir matrisiniz varsa , aşağıdakiler yararlı olabilir:

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

varsayarak Aiçeren COOmatris ve perma, numpy.arraypermütasyon ihtiva etmektedir. Bu sadece hafıza ek yüküne sahip olacaktır ; burada , matrisin sıfır olmayan öğelerinin sayısıdır.mmm


ama tam yoğun bir matrisi seyrek bir C00matris olarak ilk etapta saklamak için kullanılan bellek nedir?
Federico Poloni

intfloatfloatn2numpy.ndarray

1

Yorum yapmak için yeterli itibarım yok, ancak aşağıdaki SO sorusunun faydalı olabileceğini düşünüyorum: https://stackoverflow.com/questions/4370745/view-onto-a-numpy-array

Temel noktalar kendinizin kullanabileceği olan temel dilimleme ve kopyalamadan diziye bir görünüm yaratacaktır, ancak bunu yaparsanız gelişmiş dilimleme / indeksleme o zaman olacak bir kopyasını oluşturmak.


OP bir permütasyon istiyor ve bu temel dilimleme ile mümkün değil.
Stefano M,

Elbette haklısın. OP'nin, ne zaman olacağı konusunda endişelendiği için dilimlemeyle ne olduğunu anlamalarının yararlı olacağını düşündüm. Cevabınızdan bir şey kullanırsa, bunları döngülerinizin içinde kullandığınızdan beri bunu bilmek iyi olacağını düşünüyorum.
13'te

-1

Ne dersin

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


1
Bu geçici bir yapı kurar, tam olarak kaçınmak istediği budur.
Michael Grant
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.