python - 넘파이 - 파이썬 numpy



NumPy 행렬 클래스의 사용 중단 상태 (1)

tl; dr : numpy.matrix 클래스가 더 이상 사용되지 않습니다. 종속성 ( scipy.sparse 중 가장 큰 것)으로 클래스에 의존하는 주목할만한 라이브러리가 몇 가지 있습니다. ndarray 클래스는 적절한 단기간의 비추천을 방해하지만 사용자는 ndarray 클래스를 사용하도록 강력히 권장됩니다 (일반적으로 numpy.array 편의 함수). 행렬 곱셈에 대한 @ 연산자의 도입으로 행렬의 상대적 이점이 많이 제거되었습니다.

왜 매트릭스 클래스가 아닌가?

numpy.matrixnumpy.matrix 의 하위 클래스입니다. 그것은 원래 선형 대수를 포함하는 계산에서의 편리한 사용을위한 것이었지만 더 일반적인 배열 클래스의 인스턴스와 비교하여 그들이 행동하는 방법에있어 한계와 놀라운 차이점이 있습니다. 행동의 근본적인 차이에 대한 예 :

  • 모양 : 배열은 0에서 무한대 (또는 32) 범위의 임의의 수를 가질 수 있습니다. 행렬은 항상 2 차원입니다. 이상하게도, 행렬을 더 많은 차원으로 생성 할 수는 없지만, 단일 차원을 행렬에 삽입하여 기술적으로 다차원 행렬을 만들 수 있습니다 : np.matrix(np.random.rand(2,3))[None,...,None].shape == (1,2,3,1) (실제적인 중요성은 없습니다).
  • 인덱싱 : 인덱싱 배열 은 인덱싱 방법 에 따라 모든 크기의 배열을 제공 할 수 있습니다. 행렬의 식을 인덱싱하면 항상 행렬을 얻을 수 있습니다. 즉, 2 차원 배열에 대한 arr[:,0]arr[0,:] 은 1d ndarray 를 제공하고 mat[:,0] 은 shape (N,1) 가지며 mat[0,:] matrix 경우 (1,M) .
  • 산술 연산 : 예전에 행렬을 사용하는 주된 이유는 행렬의 산술 연산 (특히 곱셈과 출력)이 행렬 연산 (행렬 곱셈과 행렬 연산)을 수행한다는 것이 었습니다. 배열의 경우도 요소 단위의 곱셈과 출력이됩니다. 결과적으로 mat1 * mat2mat1.shape[1] == mat2.shape[0] 인 경우 유효하지만 arr1 * arr2arr1.shape == arr2.shape 경우 유효합니다. 물론 결과가 완전히 다른 것을 의미합니다. 또한, 놀랍게도, mat1 / mat2 는 두 개의 행렬을 요소 mat1 / mat2 . 이 동작은 아마도 ndarray 에서 상속 ndarray 것이지만, 특히 * 의 의미에 비추어 볼 때 행렬에는 의미가 없습니다.
  • 특수 속성 : 행렬에는 몇 가지 편리한 속성 이 있습니다. mat.Amat.A1 은 각각 np.array(mat)np.array(mat).ravel() 과 같은 값을 갖는 배열 뷰입니다. . mat.Tmat.H 는 행렬의 전치와 공역 전치 (adjoint)입니다. arr.Tndarray 클래스에 대해 존재하는 유일한 속성입니다. 마지막으로, mat.Imat 의 역행렬 mat .

ndarrays 또는 행렬에 대해 작동하는 코드 작성이 쉽습니다. 그러나 두 클래스가 코드에서 상호 작용해야하는 경우, 상황이 어려워지기 시작합니다. 특히, 많은 코드 ndarray 하위 클래스에 대해 자연스럽게 작동 할 수 있지만 matrix 은 오리 입력에 의존하려고하는 코드를 쉽게 손상시킬 수있는 부적절한 하위 클래스입니다. shape (3,4) 의 배열과 행렬을 사용하는 다음 예제를 고려하십시오.

import numpy as np

shape = (3, 4)
arr = np.arange(np.prod(shape)).reshape(shape) # ndarray
mat = np.matrix(arr) # same data in a matrix
print((arr + mat).shape)           # (3, 4), makes sense
print((arr[0,:] + mat[0,:]).shape) # (1, 4), makes sense
print((arr[:,0] + mat[:,0]).shape) # (3, 3), surprising

두 객체의 조각을 추가하는 것은 우리가 슬라이스하는 치수에 따라 대격변입니다. 행렬과 배열 모두에 추가하면 모양이 같을 때 요소 단위로 발생합니다. 위의 첫 번째 두 경우는 직관적입니다. 두 개의 배열 (행렬)을 추가 한 다음 각 행에서 두 개의 행을 추가합니다. 마지막 사례는 실제로 놀랍습니다. 아마도 두 개의 열을 추가하고 행렬로 끝나야 할 것입니다. 물론 arr[:,0] 은 shape (1,3) 과 호환되는 shape (3,) (1,3) 이지만 mat[:.0] 은 shape (3,1) 가지고 있기 때문입니다. 두 사람은 함께 broadcast (3,3) 합니다.

마지막으로, @ matmul 연산자가 파이썬 3.5 에서 처음 도입 되었을 때, 행렬 클래스의 가장 큰 이점 (즉, 많은 행렬 곱을 포함하는 복잡한 행렬 표현식을 간결하게 공식화 할 수있는 가능성)이 제거되었습니다. 처음 numpy 1.10으로 구현 되었습니다 . 간단한 2 차 형식의 계산을 비교하십시오.

v = np.random.rand(3); v_row = np.matrix(v)
arr = np.random.rand(3,3); mat = np.matrix(arr)

print(v.dot(arr.dot(v))) # pre-matmul style
# 0.713447037658556, yours will vary
print(v_row * mat * v_row.T) # pre-matmul matrix style
# [[0.71344704]]
print(v @ arr @ v) # matmul style
# 0.713447037658556

위의 것을 살펴보면 행렬 클래스가 선형 대수와 함께 작업하기 위해 널리 선호되는 이유는 분명합니다. 중급 연산자는 표현을 훨씬 덜 모호하고 훨씬 읽기 쉽도록 만들었습니다. 그러나 현대의 파이썬과 numpy를 사용하여 @ 연산자로 동일한 가독성을 얻습니다. 또한, 행렬의 경우는 기술적으로 스칼라이어야하는 모양의 행렬 (1,1) 을 제공합니다. 이것은 또한 우리가이 "스칼라"로 열 벡터를 곱할 수 없다는 것을 의미합니다. 위의 예제에서 (v_row * mat * v_row.T) * v_row.T 는 모양 (1,1)(3,1) (1,1) 행렬 (3,1) 은이 순서로 곱할 수 없습니다.

완벽을 기하기 위해서는 matmul 연산자가 ndarray가 행렬에 비해 차선책 인 가장 일반적인 시나리오를 수정하지만 ndarrays를 사용하여 선형 대수를 우아하게 처리하는 데는 몇 가지 단점이 여전히 있음을 유의해야합니다 (사람들은 여전히 ​​전체적으로 후자에 충실하는 것이 바람직 함). 그러한 예는 매트릭스 파워입니다. mat ** 3 은 매트릭스의 적절한 제 3 매트릭스 파워입니다 (반면 ndarray의 요소 별 큐브입니다). 불행히도 numpy.linalg.matrix_power 는 매우 장황합니다. 또한, in-place 행렬 곱셈은 행렬 클래스에서만 잘 작동합니다. 대조적으로, PEP 465파이썬 문법 모두 @= matmul과 함께 증가 된 할당으로 허용하지만 ndarrays의 경우 numpy 1.15로 구현되지 않습니다.

지원 중단 기록

matrix 클래스에 관한 위의 복잡성을 고려해 볼 때 오랫동안 가능한 더 이상 사용되지 않는 기능에 대한 논의가 반복적으로있었습니다. 이 프로세스의 거친 전제 조건이었던 @ 삽입 연산자는 2015 년 9 월에 도입되었습니다 . 불행하게도 초기에 행렬 클래스의 장점은 그 사용이 널리 퍼져 있음을 의미했습니다. 행렬 클래스에 의존하는 라이브러리가 있습니다 (가장 중요한 종속 numpy.matrix 중 하나는 numpy.matrix 이며 numpy.matrix 의미를 사용하고 numpy.matrix 때 행렬을 반환하는 경우가 많기 때문에 항상 비추천합니다).

이미 2009 년부터 메일 링 목록에 실종 된 메일 목록에

numpy는 일반 목적의 계산 요구 사항을 위해 설계된 것이지 수학의 한 분기가 아닙니다. ND 배열은 많은 것들을 위해 매우 유용합니다. 반대로, Matlab은 원래 선형 대수 패키지에 쉽게 적용 할 수 있도록 설계되었습니다. 개인적으로, Matlab을 사용했을 때 나는 매우 어색함을 발견했습니다. 저는 대수 행렬을 실제로 수행 한 몇 줄마다 선형 대수와 상관없는 코드 라인을 보통 100 개 작성했습니다. 그래서 저는 대수적 인 방법을 선호합니다 - 선형 대수학 코드 행은 더 어색하지만 더 쉬울 것입니다. 나머지는 훨씬 좋습니다.

Matrix 클래스는 이것을 제외하고 선형 대수를 자연스럽게 표현하기 위해 작성되었습니다. 그러나 행렬과 배열을 섞을 때 상황이 조금 복잡해지며 심지어 행렬을 고수 할 때 혼란과 한계가 있습니다. 행과 열 벡터를 어떻게 표현합니까? 매트릭스를 반복 할 때 무엇을 얻을 수 있습니까? 기타

이 쟁점들, 많은 좋은 아이디어들, 그것을 향상시키는 방법에 대한 약간의 의견 일치에 관해서 많은 논의가 있었지만 그것을 할 수있는 기술을 가진 사람은 아무도 그것을 할 동기가 충분하지 않습니다.

이는 매트릭스 클래스에서 발생하는 이점과 어려움을 반영합니다. 내가 발견 할 수있는 가장 쓸모없는 제안 은 2008 년 부터이지만, (특히 행렬을 썰어서 반복하면 (행) 행렬이 발생할 가능성이 높기 때문에) 변경된 비 직관적 인 동작에 부분적으로 동기가 있지만 부분적으로는 동기가 있습니다. 이 제안은 이것이 논쟁의 여지가 많은 주제이고 행렬 곱셈을위한 중위 연산자가 중요하다는 것을 보여 주었다.

내가 찾을 수있는 다음 언급은 매우 유익한 실로 밝혀진 2014 년부터 입니다. 이어지는 논의 는 전반적인 주제가 여전히 탁월한 하위 주제 를 다루는 문제를 제기 합니다 . 또한 강력한 비판이있다 .

이 토론 (Github에서)을 촉발시킨 것은 다음을 위해 올바르게 작동하는 덕 타입 코드를 작성하는 것이 불가능하다는 것입니다.

  • ndarrays
  • 행렬
  • scipy.sparse 스파 스 매트릭스

세 가지 모두의 의미는 다릅니다. scipy.sparse는 매트릭스와 ndarrays 사이의 어딘가에 있으며 매트릭스와 다른 것과 같이 무작위로 작동하는 것도 있습니다.

일부 hyberbole이 추가되면서 개발자 관점에서 np.matrix는 파이썬에서 ndarray 의미의 무의미한 규칙을 어지럽히는 것으로 이미 기존의 방식으로 악의적 인 작업을 수행하고 있다고 말 할 수 있습니다.

행렬에 대한 가능한 미래에 대한 많은 가치있는 논의가 이어졌다. 당시 @ 연산자가 없어도 행렬 클래스의 비추천에 대한 생각과 어떻게 하류 사용자에게 영향을 줄 수 있는지 생각 해왔다. 지금까지이 논의가 matte를 소개 한 PEP 465의 시작을 직접 이끌어 냈다는 것을 알 수 있습니다.

2015 년 초 :

제 의견으로는, np.matrix의 "고정 된"버전은 (1) np.ndarray 서브 클래스가 아니어야하며 (2) numpy가 아닌 제 3 자 라이브러리에 존재해야합니다.

나는 ndarray 서브 클래스로서 현재의 상태에서 np.matrix를 수정하는 것이 실제로 가능하지 않다고 생각하지만 고정 매트릭스 클래스조차 실제로 numpy 자체에 속하지 않는다. 너무 긴 릴리스 사이클과 실험을위한 호환성 보장 - numpy에서 행렬 클래스의 단순한 존재만으로 새로운 사용자가 길을 잃는 것은 말할 것도 없습니다.

@ 연산자가 잠시 동안 사용 가능 해지면, 비추천에 대한 논의가 다시 떠올랐다 . 매트릭스 비추천과 scipy.sparse 의 관계에 관한 주제를 다시 scipy.sparse .

결국 numpy.matrix 를 비추천 조치 한 첫 번째 조치는 2017 년 11 월 말에 수행되었습니다 . 수업의 부양 가족에 관해서 :

커뮤니티가 scipy.sparse 행렬 하위 클래스를 어떻게 처리합니까? 이들은 여전히 ​​공통적으로 사용됩니다.

그들은 꽤 오래 동안 아무데도 가지 않을 것입니다 (적어도 희박한 ndarrays가 실현 될 때까지). 따라서 np.matrix는 삭제되지 않고 이동해야합니다.

( source ) 및

누군가와 마찬가지로 np.matrix를 없애고 싶지만 언제든지 그렇게하면 정말 혼란 스러울 것입니다.

  • 더 잘 알지 못하는 사람들이 쓴 작은 스크립트가 많이 있습니다. 우리는 그들이 np.matrix를 사용하지 않는 것을 배우기를 원하지만 모든 스크립트를 깨는 것은 그렇게하기위한 고통스러운 방법입니다

  • scipy.sparse 때문에 np.matrix를 사용하는 것 외에 다른 대안이없는 scikit-learn과 같은 주요 프로젝트가 있습니다.

그래서 앞으로의 길은 다음과 같을 것이라고 생각합니다.

  • 이제 또는 누군가가 PR을 얻게 될 때마다 : np.matrix .__ init__에서 PendingDeprecationWarning을 발행하고 (scikit-learn 및 친구들의 경우 성능을 떨어 뜨리지 않는 한) 문서 맨 위에 큰 경고 상자를 둡니다. 여기에있는 아이디어는 실제로 누군가의 코드를 어 기지 않는 것이지만, 다른 대안이 있다면 누군가가 이것을 사용해야한다고 생각하지 않는다는 메시지를 내기 시작합니다.

  • scipy.sparse에 대한 대안이있다 : 경고를 올리면 FutureWarning으로 가서 기존 스크립트가 중단되지 않도록 할 수 있지만 시끄러운 경고를 받는다.

  • 궁극적으로 유지 관리 비용을 절감 할 수 있다고 생각한다면 서브 패키지

( source ).

현상 유지

2018 년 5 월 (numpy 1.15, 관련 끌어 오기 요청commit ) 행렬 클래스 docstring 에 다음 메모가 포함됩니다.

선형 대수학에서도이 클래스를 사용하는 것이 더 이상 권장되지 않습니다. 대신 정규 배열을 사용하십시오. 나중에 클래스가 제거 될 수 있습니다.

동시에 PendingDeprecationWarningmatrix.__new__ 추가되었습니다. 안타깝게도 deprecation 경고는 (거의 항상) 기본적으로 잠잠 해 지므로 numpy의 최종 사용자에게는이 강력한 힌트가 표시되지 않습니다.

마지막으로, 2018 년 11 월 현재의 멍청한 로드맵 에는 여러 관련 주제가 " 작업량과 기능 [리소스가 부족한 커뮤니티]가 자원을 투자하게 될 것 "중 하나로 언급 됩니다 .

NumPy 내의 일부 항목은 NumPy의 범위와 실제로 일치하지 않습니다.

  • numpy.fft에 대한 백엔드 시스템 (예 : fft-mkl이 numpy를 monkeypatch 할 필요가 없도록)
  • 마스크 된 배열을 ndarray 서브 클래스가 아닌 다른 프로젝트에 다시 작성 하시겠습니까?
  • 오리 배열 유형의 MaskedArray 및 / 또는
  • 누락 된 값을 지원하는 dtype
  • linalg와 fft에 numpy와 scipy 사이의 중첩을 처리하는 방법에 대한 전략을 작성하십시오 (그리고 구현하십시오).
  • np.matrix 사용 중단

이 상태는 더 큰 라이브러리 / 많은 사용자 (특히 scipy.sparse )가 행렬 클래스에 의존하는 한 계속 유지 될 것입니다. 그러나 scipy.sparsepydata/sparse 와 같은 다른 것에 의존하도록 이동시키는 논의진행 중 입니다. 비추천 프로세스의 개발에 관계없이 사용자는 새 코드에서 ndarray 클래스를 사용하고 가능하면 이전 코드를 포팅해야합니다. 결국 매트릭스 클래스는 현재 패키지 형태로 존재하는 부담을 제거하기 위해 별도의 패키지로 끝날 것입니다.

NumPy에서 matrix 클래스의 상태는 무엇입니까?

나는 ndarray 클래스를 사용해야한다고 계속 말하고있다. 그것은 내가 쓸 새로운 코드에서 matrix 클래스를 사용하는 것이 안전할까요? 대신 왜 ndarray 를 사용 ndarray 이해할 수 없습니다.





deprecated