Cho phép một ma trận tại chỗ trong numpy


27

Tôi muốn sửa đổi một ma trận chuyển tiếp hình vuông dày đặc tại chỗ bằng cách thay đổi thứ tự của một số hàng và cột của nó, sử dụng thư viện numpy của python. Về mặt toán học, điều này tương ứng với việc nhân trước ma trận với ma trận hoán vị P và nhân sau với P ^ -1 = P ^ T, nhưng đây không phải là một giải pháp hợp lý về mặt tính toán.

Ngay bây giờ tôi đang trao đổi các hàng và cột theo cách thủ công, nhưng tôi đã mong đợi numpy có một hàm đẹp f (M, v) trong đó M có n hàng và cột và v có n mục, để f (M, v) cập nhật M theo hoán vị chỉ số v. Có lẽ tôi chỉ thất bại trong việc tìm kiếm trên internet.

Một cái gì đó như thế này có thể khả thi với "lập chỉ mục nâng cao" của numpy nhưng sự hiểu biết của tôi là một giải pháp như vậy sẽ không được áp dụng. Ngoài ra đối với một số tình huống đơn giản, có thể chỉ cần theo dõi riêng một hoán vị chỉ số, nhưng điều này không thuận tiện trong trường hợp của tôi.

Đã thêm:
Đôi khi khi mọi người nói về hoán vị, họ chỉ có nghĩa là lấy mẫu các hoán vị ngẫu nhiên, ví dụ như một phần của quy trình để lấy giá trị p trong thống kê. Hoặc họ có nghĩa là đếm hoặc liệt kê tất cả các hoán vị có thể. Tôi không nói về những điều này.

Đã thêm:
Ma trận đủ nhỏ để vừa với RAM máy tính để bàn nhưng đủ lớn để tôi không muốn sao chép nó một cách thiếu suy nghĩ. Trên thực tế tôi muốn sử dụng ma trận càng lớn càng tốt, nhưng tôi không muốn đối phó với sự bất tiện khi không thể giữ chúng trong RAM và tôi thực hiện các thao tác LAPACK O (N ^ 3) trên ma trận cũng sẽ giới hạn kích thước ma trận thực tế. Tôi hiện đang sao chép ma trận lớn này một cách không cần thiết, nhưng tôi hy vọng điều này có thể dễ dàng tránh được cho hoán vị.


3
Sẽ tốt hơn nếu bạn có thể cập nhật câu hỏi để đưa ra kích thước ma trận của mình. "Gigantic" không có nghĩa là điều tương tự với tất cả mọi người.
Bill Barth

2
Bạn đúng rằng việc lập chỉ mục nâng cao (hay còn gọi là ưa thích) tạo ra một bản sao. Nhưng nếu bạn chấp nhận sống với thực tế đó thì mã của bạn chỉ M[v]để hoán vị các hàng.
Daniel Velkov

@daniel: Và nó sẽ là M [v ,:] [:, v] để thực hiện toàn bộ hoán vị? Đây sẽ là cách tốt nhất để có được hoán vị bằng cách sử dụng lập chỉ mục ưa thích? Và nó có sử dụng bộ nhớ ma trận gấp 3 lần, bao gồm kích thước của ma trận gốc, ma trận hàng + cột và ma trận hàng tạm thời?
không có

Điều đó đúng, bạn sẽ có ma trận gốc và 2 bản sao. Btw tại sao bạn cần phải hoán vị cả hai hàng và cột cùng một lúc?
Daniel Velkov

4
Bạn sẽ làm gì với ma trận hoán vị? Có thể tốt hơn là chỉ cần hoán vị vectơ khi áp dụng toán tử.
Jed Brown

Câu trả lời:


9

Theo các tài liệu, không có phương pháp hoán vị tại chỗ trong numpy, một cái gì đó giống như ndarray.sort .

Vì vậy, các tùy chọn của bạn là (giả sử đó Mlà ma trận và vectơ hoán vị)N×Np

  1. thực hiện thuật toán của riêng bạn trong C như một mô-đun mở rộng (nhưng thuật toán tại chỗ rất khó, ít nhất là đối với tôi!)
  2. N bộ nhớ trên không

    for i in range(N):
        M[:,i] = M[p,i]
    for i in range(N):
        M[i,:] = M[i,p]
    
  3. N2 bộ nhớ trên đầu

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

Hy vọng rằng những hack tối ưu này là hữu ích.


@none là hack 2. những gì bạn gọi là 'trao đổi hàng và cột' theo cách thủ công?
Stefano M

1
Tôi sẽ kết hợp các tùy chọn 1 và 2: viết mã C sử dụng bộ đệm có thứ tự N để ghi từng cột được thẩm thấu vào, sau đó ghi lại mã nguồn gốc của nó; sau đó làm tương tự cho các hàng. Như @Stefano viết, việc này chỉ mất thêm bộ nhớ mà bạn đã chi tiêu để lưu trữ hoán vị p ở vị trí đầu tiên. O(N)p
Erik P.

@ErikP. đối với triển khai C, bộ nhớ thêm là hợp lý và chắc chắn phân tán của bạn ghi vào temp và sao chép lại cách tiếp cận là âm thanh. Tuy nhiên, câu hỏi thú vị là nếu có các thuật toán hiệu quả hơn, có thêm bộ nhớ O ( N ) . Câu trả lời thật khó, tôi nghĩ, vì chúng ta nên tính đến kiến ​​trúc bộ xử lý, kiểu truy cập bộ nhớ, truy cập bộ đệm, ... Điều này cho biết tôi sẽ làm theo lời khuyên của bạn và đi theo thuật toán đơn giản và dễ thực hiện. O(N)O(N)
Stefano M

2
Đây là một canidate thực sự tốt cho một chức năng cython. Không được quá 10 dòng. . . muốn tôi cho nó một vết nứt?
meawoppl

Lol. Tôi bắt đầu Cython này, sau đó tìm thấy câu trả lời đúng trong một chức năng mà tôi sử dụng mọi lúc. Doh. Xem câu trả lời được đăng của tôi.
meawoppl

6

Cảnh báo: Ví dụ bên dưới hoạt động chính xác, nhưng sử dụng bộ tham số đầy đủ được đề xuất ở cuối bài đăng sẽ phát hiện ra lỗi hoặc ít nhất là "tính năng không có tài liệu" trong hàm numpy.take (). Xem ý kiến ​​dưới đây để biết chi tiết. Báo cáo lỗi đã nộp .

Bạn có thể thực hiện việc này tại chỗ với chức năng Take () của numpy , nhưng nó đòi hỏi một chút nhảy vọt.

Dưới đây là một ví dụ về thực hiện hoán vị ngẫu nhiên các hàng của ma trận danh tính:

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

Để thực hiện tại chỗ, tất cả những gì bạn cần làm là chỉ định tham số "out" giống với mảng đầu vào bạn phải đặt mode = "clip" hoặc mode = "quấn". Nếu bạn không đặt chế độ, nó sẽ tạo một bản sao để khôi phục trạng thái mảng trên một ngoại lệ Python (xem tại đây) .

Trên một lưu ý cuối cùng, dường như là một phương thức mảng, vì vậy thay vì

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

bạn có thể gọi

i.take(rr, axis=0)

nếu đó là nhiều hơn với khẩu vị của bạn. Vì vậy, trong tổng số bạn gọi nên trông giống như sau:

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

Để hoán vị cả hàng và cột tôi nghĩ rằng bạn phải chạy nó hai lần hoặc kéo một số shenanigans xấu xí bằng numpy.unravel_index làm tôi đau đầu khi nghĩ về.


Như đã nói, thuật toán tại chỗ là khó. Giải pháp của bạn không hoạt động với numpy 1.6.2. và 1.7.1 (hàng / cột trùng lặp). Không có thời gian để kiểm tra xem 1.8.x có khắc phục được sự cố này không
Stefano M

Hừm. Bạn có thể gửi mã kiểm tra ở đâu đó không? Trong đầu, tôi cảm thấy như thể cần phải có một thao tác sắp xếp trên các chỉ số xảy ra đầu tiên trước khi nhổ lông. Tôi sẽ điều tra thêm PM này.
meawoppl

1
Khi tôi chạy mã này tôi nhận được 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]. Vì vậy, np.takeít nhất đối với numpy 1.6.2 không nhận thức được việc hoán vị tại chỗ và làm mọi thứ rối tung lên.
Stefano M

Yeouch. Được chứng minh tốt. Điều này có thể đủ điều kiện là một lỗi IMHO. Ít nhất các tài liệu nên nói đầu vào và đầu ra không thể là cùng một mảng, có thể kiểm tra xem và ngoại trừ nếu có.
meawoppl

Đồng ý về lỗi: có lẽ bạn nên thêm một ghi chú vào bài đăng của mình để cảnh báo người đọc rằng giải pháp của bạn có thể tạo ra kết quả sai.
Stefano M

2

Nếu bạn có một ma trận thưa thớt được lưu trữ ở COOđịnh dạng, những điều sau đây có thể hữu ích

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

ACOOpermnumpy.arraymm


Nhưng những gì bộ nhớ trên để lưu trữ một ma trận dày đặc đầy đủ như một C00ma trận thưa thớt ở nơi đầu tiên?
Federico Poloni

intfloatfloatn2numpy.ndarray

1

Tôi không đủ danh tiếng để bình luận, nhưng tôi nghĩ câu hỏi SO sau đây có thể hữu ích: https://stackoverflow.com/questions/4370745/view-onto-a-numpy-array

Các điểm cơ bản là bạn có thể sử dụng cắt cơ bản và điều đó sẽ tạo ra một khung nhìn vào mảng mà không cần sao chép, nhưng nếu bạn thực hiện cắt / lập chỉ mục nâng cao thì nó sẽ tạo một bản sao.


OP đang yêu cầu hoán vị, và điều này là không thể đối với việc cắt lát cơ bản.
Stefano M

Bạn đúng tất nhiên. Tôi nghĩ rằng OP sẽ hữu ích để hiểu những gì đang xảy ra với việc cắt lát (trong trường hợp họ không biết) vì họ lo ngại khi nào các bản sao sẽ xảy ra. Nếu anh ấy sử dụng một cái gì đó từ câu trả lời của bạn, tôi nghĩ rằng sẽ tốt khi biết vì bạn sử dụng chúng trong các vòng lặp của bạn.
hadsed

-1

Thế còn

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


1
Điều này xây dựng tạm thời, đó là chính xác những gì anh ta muốn tránh.
Michael Grant
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.