programing

연속 어레이와 비연속 어레이의 차이점은 무엇입니까?

bestprogram 2023. 7. 6. 22:24

연속 어레이와 비연속 어레이의 차이점은 무엇입니까?

reshape() 기능에 대한 numpy 매뉴얼에는 다음과 같이 나와 있습니다.

>>> a = np.zeros((10, 2))
# A transpose make the array non-contiguous
>>> b = a.T
# Taking a view makes it possible to modify the shape without modifying the
# initial object.
>>> c = b.view()
>>> c.shape = (20)
AttributeError: incompatible shape for a non-contiguous array

제 질문은 다음과 같습니다.

  1. 연속 및 비연속 어레이란 무엇입니까?연속 메모리 블록이란 무엇인가와 같이 C의 연속 메모리 블록과 유사합니까?
  2. 이 둘 사이에 성능 차이가 있습니까?우리는 언제 둘 중 하나를 사용해야 합니까?
  3. 왜 transcose는 배열을 비연속적으로 만드는가?
  4. 왜 그럴까요?c.shape = (20) 오를던 다니집류▁an를 던집니다.incompatible shape for a non-contiguous array?

답변 감사합니다!

연속 어레이는 메모리 블록에 저장된 어레이일 뿐입니다. 어레이의 다음 값에 액세스하기 위해 다음 메모리 주소로 이동합니다.

어레이 2D를 .arr = np.arange(12).reshape(3,4)다음과 같이 표시됩니다.

enter image description here

에서 터의기서억에은, 가들치의 arr다음과 같이 저장됩니다.

enter image description here

이것은 의미합니다.arr이 메모리의 연속 블록으로 저장되기 때문에 C 연속 배열입니다.다음 메모리 주소는 해당 행의 다음 행 값을 유지합니다.열을 아래로 이동하려면 세 블록을 건너뛰기만 하면 됩니다(예: 0에서 4로 점프하는 것은 1, 2, 3을 건너뛰는 것을 의미).

을 배을다 바꾸기로로 전치하는 것arr.T인접 행 항목이 더 이상 인접 메모리 주소에 없기 때문에 C 연속성이 손실됨을 의미합니다. 하만지,arr.T이 메모리의 연속 블록에 있으므로 Fortran이 연속적입니다.

enter image description here


성능 측면에서는 서로 인접한 메모리 주소에 액세스하는 것이 더 "분산"된 주소에 액세스하는 것보다 더 빠른 경우가 많습니다(RAM에서 값을 가져오려면 CPU용으로 많은 인접 주소를 가져와 캐시해야 할 수 있습니다).즉, 인접 어레이를 통한 작업이 더 빨라지는 경우가 많습니다.

C 연속 메모리 레이아웃의 결과로 행 단위 작업이 열 단위 작업보다 일반적으로 빠릅니다.예를 들어, 일반적으로 다음을 확인할 수 있습니다.

np.sum(arr, axis=1) # sum the rows

다음보다 약간 빠름:

np.sum(arr, axis=0) # sum the columns

마찬가지로 Fortran 연속 어레이의 경우 열에 대한 작업이 약간 더 빠릅니다.


마지막으로, 새로운 모양을 할당하여 Fortran 연속 배열을 평탄화할 수 없는 이유는 무엇입니까?

>>> arr2 = arr.T
>>> arr2.shape = 12
AttributeError: incompatible shape for a non-contiguous array

가 NumPy의 행을 넣어야 .arr.T이렇게 함께:

enter image description here

(설정)shape속성은 C 순서를 직접 가정합니다. 즉,NumPy는 행 단위로 작업을 수행하려고 합니다.)

이것은 불가능합니다.모든 축에 대해 NumPy는 배열의 다음 요소로 이동하려면 일정한 스트라이드 길이(이동할 바이트 수)를 가져야 합니다.평탄화arr.T이러한 방식으로 배열의 연속적인 값을 검색하려면 메모리에서 앞뒤로 건너뛰어야 합니다.

우리가 썼다면,arr2.reshape(12)대신 NumPy는 arr2의 값을 새 메모리 블록에 복사합니다(이 셰이프에 대한 원래 데이터에 대한 뷰를 반환할 수 없기 때문입니다).

12개의 서로 다른 배열 값을 사용하는 이 예는 다음과 같은 도움이 될 수 있습니다.

In [207]: x=np.arange(12).reshape(3,4).copy()

In [208]: x.flags
Out[208]: 
  C_CONTIGUOUS : True
  F_CONTIGUOUS : False
  OWNDATA : True
  ...
In [209]: x.T.flags
Out[209]: 
  C_CONTIGUOUS : False
  F_CONTIGUOUS : True
  OWNDATA : False
  ...

C order값은 생성된 순서대로 표시됩니다.전치된 것들은 아닙니다.

In [212]: x.reshape(12,)   # same as x.ravel()
Out[212]: array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11])

In [213]: x.T.reshape(12,)
Out[213]: array([ 0,  4,  8,  1,  5,  9,  2,  6, 10,  3,  7, 11])

둘 다 1D 보기를 얻을 수 있습니다.

In [214]: x1=x.T

In [217]: x.shape=(12,)

의 모양x변경할 수도 있습니다.

In [220]: x1.shape=(12,)
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-220-cf2b1a308253> in <module>()
----> 1 x1.shape=(12,)

AttributeError: incompatible shape for a non-contiguous array

그러나 전치의 모양은 변경할 수 없습니다.data아직 있습니다.0,1,2,3,4...다음으로 액세스할 수 없는 주문0,4,8...1차원 배열로

하지만 한 부는x1변경 가능:

In [227]: x2=x1.copy()

In [228]: x2.flags
Out[228]: 
  C_CONTIGUOUS : True
  F_CONTIGUOUS : False
  OWNDATA : True
  ...
In [229]: x2.shape=(12,)

을 살피는 것strides도움이 될 수도 있습니다.진전이란 다음 값을 얻기 위해 얼마나 멀리 가야 하는지를 의미합니다(바이트 단위).2D 배열의 경우 2개의 스트라이드 값이 있습니다.

In [233]: x=np.arange(12).reshape(3,4).copy()

In [234]: x.strides
Out[234]: (16, 4)

다음 행으로 이동하려면 16바이트, 다음 열만 4단계를 수행합니다.

In [235]: x1.strides
Out[235]: (4, 16)

transcose는 단지 단계의 순서를 바꿉니다.다음 행은 4바이트, 즉 다음 숫자입니다.

In [236]: x.shape=(12,)

In [237]: x.strides
Out[237]: (4,)

모양을 변경하면 단계도 변경됩니다. 한 번에 4바이트씩 버퍼를 통과하면 됩니다.

In [238]: x2=x1.copy()

In [239]: x2.strides
Out[239]: (12, 4)

그럼에도 불구하고.x2와 꼭 닮았습니다x1값 순서가 다른 자체 데이터 버퍼가 있습니다.다음 열은 이제 4바이트가 넘고 다음 행은 12(3*4)입니다.

In [240]: x2.shape=(12,)

In [241]: x2.strides
Out[241]: (4,)

그리고 마치x모양을 1d로 변경하면 스텝이 감소합니다.(4,).

위해서x1데이터를 저장한 상태에서0,1,2,...질서, 1단 보폭은 없습니다.0,4,8....

__array_interface__어레이 정보를 표시하는 또 다른 유용한 방법은 다음과 같습니다.

In [242]: x1.__array_interface__
Out[242]: 
{'strides': (4, 16),
 'typestr': '<i4',
 'shape': (4, 3),
 'version': 3,
 'data': (163336056, False),
 'descr': [('', '<i4')]}

x1데이터 버퍼 주소는 다음과 같습니다.x데이터를 공유할 수 있습니다. x2버퍼 주소가 다릅니다.

다음을 추가하는 실험도 할 수 있습니다.order='F' 매개변에 대한 copy그리고.reshape명령을 실행합니다.

언급URL : https://stackoverflow.com/questions/26998223/what-is-the-difference-between-contiguous-and-non-contiguous-arrays