Numpy에서 제자리에 행렬을 퍼머 트


27

파이썬의 numpy 라이브러리를 사용하여 여러 행과 열의 순서를 변경하여 밀도가 높은 사각형 전이 행렬을 제자리에서 수정하고 싶습니다. 수학적으로 이것은 순열 행렬 P에 의해 행렬을 미리 곱하고 P ^ -1 = P ^ T에 의해 곱셈하는 것에 해당하지만, 이것은 계산적으로 합리적인 해결책은 아닙니다.

지금은 수동으로 행과 열을 교환하고 있지만 numpy에는 멋진 함수 f (M, v)가 있고 여기서 M에는 n 개의 행과 열이 있고 v에는 n 개의 항목이 있으므로 f (M, v)가 업데이트됩니다. 인덱스 순열 v에 따르면 M. 어쩌면 인터넷 검색에 실패했을 것입니다.

numpy의 "고급 인덱싱"으로 이와 같은 것이 가능할 수도 있지만, 그러한 해결책이 제자리에 있지 않다는 것을 이해합니다. 또한 몇 가지 간단한 상황에서는 인덱스 순열을 개별적으로 추적하는 것으로 충분할 수 있지만 제 경우에는 편리하지 않습니다.

추가됨 :
때로는 사람들이 순열에 대해 이야기 할 때 통계에서 p- 값을 얻는 절차의 일부로 임의 순열의 샘플링 만 의미합니다. 또는 가능한 모든 순열을 세거나 열거하는 것을 의미합니다. 나는 이것에 대해 이야기하지 않습니다.

추가 :
매트릭스는 데스크탑 RAM에 들어갈만큼 작지만 생각없이 복사하고 싶지 않을만큼 큽니다. 실제로 행렬을 가능한 한 많이 사용하고 싶지만 RAM에 넣을 수 없다는 불편 함을 다루고 싶지 않으며 행렬에 대해 O (N ^ 3) LAPACK 작업을 수행합니다. 실제 매트릭스 크기를 제한하십시오. 필자는 현재이 행렬을 불필요하게 복사하지만 순열을 위해 쉽게 피할 수 있기를 바랍니다.


3
행렬 크기를 지정하기 위해 질문을 업데이트 할 수 있다면 좋을 것입니다. "거대한"은 모든 사람에게 같은 의미가 아닙니다.
Bill Barth

2
고급 (또는 팬시) 인덱싱으로 사본을 생성 할 수 있습니다. 그러나 그 사실에 따라 생활하는 것을 받아들이면 코드는 M[v]행을 퍼밋하는 것입니다.
Daniel Velkov

@daniel : 그리고 전체 순열을하는 것이 M [v, :] [:, v]일까요? 멋진 인덱싱을 사용하여 순열을 얻는 가장 좋은 방법입니까? 그리고 원래 행렬의 크기, 행 + 열 순열 행렬 및 임시 행 순열 행렬을 포함하여 3 배의 행렬 메모리를 사용합니까?
없음

맞습니다. 원본 행렬과 2 개의 사본이 있습니다. Btw 왜 행과 열을 동시에 퍼뮤 테이션해야합니까?
Daniel Velkov

4
순열 행렬로 무엇을 하시겠습니까? 연산자를 적용 할 때 단순히 벡터를 치환하는 것이 좋습니다.
Jed Brown

답변:


9

문서에 따르면 numpy에는 ndarray.sort 와 같은 내부 순열 방법이 없습니다 .

그래서 옵션 (즉 가정합니다 MA는 행렬과 순열 벡터)N×Np

  1. C에서 자신의 알고리즘을 확장 모듈로 구현 ( 적어도 제 위치 알고리즘 은 어렵습니다!)
  2. 메모리 오버 헤드N

    for i in range(N):
        M[:,i] = M[p,i]
    for i in range(N):
        M[i,:] = M[i,p]
  3. 메모리 오버 헤드N2

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

이러한 차선책이 유용하기를 바랍니다.


@none is hack 2. '수동으로 행과 열을 수동으로 교환'이라고 부르는 것은 무엇입니까?
Stefano M

1
옵션 1과 2를 결합하여 순서 N의 버퍼를 사용하여 각 순열을 쓰는 C 코드를 작성한 다음 원래 위치로 다시 씁니다. 그런 다음 행에 대해서도 동일하게 수행하십시오. @Stefano가 쓰는 것처럼 이것은 추가 메모리 만 사용하므로 이미 순열 p 를 저장하는 데 소비하고 있습니다 . O(N)
Erik P.

@ErikP. C 구현 추가 메모리가 합리적이며 temp 및 copy back 접근 방식의 산란 쓰기가 올바른지 확인하십시오. 그러나 흥미로운 질문은 O ( N )에 추가 메모리가 주어지면 더 효율적인 알고리즘이 있는지 여부 입니다. 프로세서 아키텍처, 메모리 액세스 패턴, 캐시 적중 등을 고려해야하기 때문에 대답은 어렵다고 생각합니다. 이것은 귀하의 조언을 따르고 간단하고 구현하기 쉬운 알고리즘을 사용하겠다고 말했습니다. 영형()영형()
Stefano M

2
이것은 cython 함수에 정말 좋은 후보입니다. Shoudln은 10 줄을 넘지 않아야합니다. . . 내가 균열을주고 싶어?
meawoppl

롤 Cython을 시작한 다음 항상 사용하는 함수에서 정답을 찾았습니다. 도 게시 된 답변을 참조하십시오.
meawoppl

6

경고 : 아래 예제는 제대로 작동하지만 포스트 엔드에서 제안 된 전체 매개 변수 집합을 사용 하면 numpy.take () 함수에서 버그 또는 "문서화되지 않은 기능"이 노출됩니다. 자세한 내용은 아래 주석을 참조하십시오. 버그 보고서 제출 .

numpy의 take () 함수를 사용 하여이 작업을 대신 수행 할 수 있지만 약간의 농구 점프가 필요합니다.

다음은 항등 행렬의 행을 무작위로 치환하는 예입니다.

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

제자리에서 수행하려면 "out"매개 변수를 입력 배열 동일 하게 지정하고 mode = "clip"또는 mode = "wrap"을 설정해야합니다. 모드를 설정하지 않으면 파이썬 예외에서 배열 상태를 복원하기 위해 복사합니다 (여기 참조) .

마지막으로, take는 배열 방법 인 것처럼 보입니다.

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

당신은 전화 할 수 있었다

i.take(rr, axis=0)

그것이 당신의 취향에 더 가깝다면. 따라서 총 전화는 다음과 같아야합니다.

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

행과 열을 모두 바꾸 려면 두 번 실행하거나 numpy.unravel_index 를 사용 하여 추악한 shenanigans를 가져 와야 한다고 생각합니다.


말했듯이, 그 자리에서 알고리즘은 어렵다. 솔루션 numpy 1.6.2에서 작동 하지 않습니다 . 및 1.7.1 (중복 행 / 열). 1.8.x가이 문제를 해결하는지 확인할 시간이 없었습니다
Stefano M

흠. 어딘가에 테스트 코드를 게시 할 수 있습니까? 내 머릿속에서는 뜯어 내기 전에 먼저 발생하는 인덱스에 대해 정렬 작업이 필요한 것처럼 느낍니다. 이 PM에 대해 더 조사하겠습니다.
meawoppl

1
내가 실행하면 이 코드 내가 얻을를 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]. 그래서 np.takeNumPy와 1.6.2에 대한 적어도 현재 위치에서 순열과 놨 일을 일을 인식하지 못합니다.
Stefano M

예 우치 잘 설명했다. 이것은 아마도 버그 IMHO로 자격이 있습니다. 적어도 문서는 입력과 출력이 같은 배열 일 수 없다고 말해야합니다. 아마 확인하고 있는지 확인하십시오.
meawoppl

버그에 동의 : 게시물에 메모를 추가하여 독자에게 솔루션에서 잘못된 결과가 발생할 수 있음을 경고해야합니다.
Stefano M

2

희소 행렬이 COO형식으로 저장된 경우 다음이 도움이 될 수 있습니다.

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

ACOOpermnumpy.array


그러나 전체 밀도 매트릭스를 희소 C00매트릭스 로 저장하기위한 메모리 오버 헤드는 무엇 입니까?
Federico Poloni

intfloatfloat2numpy.ndarray

1

의견을 말할만큼 평판이 좋지 않지만 다음과 같은 질문이 도움이 될 것이라고 생각합니다. https://stackoverflow.com/questions/4370745/view-onto-a-numpy-array

기본 요점은 기본 슬라이싱을 사용할 수 있으며 복사하지 않고 어레이에 대한 뷰를 생성하지만 고급 슬라이싱 / 인덱싱 을 수행 하면 복사본 생성 된다는 입니다.


OP가 순열을 요구하고 있으며 기본 슬라이싱에서는 불가능합니다.
Stefano M

물론 맞습니다. OP가 사본의 발생시기에 대해 염려했기 때문에 OP가 슬라이싱 (알 수없는 경우)으로 발생한 상황을 이해하는 것이 유용 할 것이라고 생각했습니다. 그가 당신의 대답에서 무언가를 사용했다면, 당신은 그것을 당신의 고리 안에서 사용하기 때문에 그것을 알고 좋을 것이라고 생각합니다.
hadsed

-1

이건 어떤가요

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


1
이것은 그가 피하고 싶었던 일시적인 것을 구성합니다.
Michael Grant
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.