728x90
728x170
배열 객체 관리와 연산
- 넘파이는 수백만 개의 수치 데이터를 빠르게 처리함으로써 파이썬의 과학 계산을 빠르게 처리하는 라이브러리이다.
- 넘파이의 N차원 배열은 데이터를 빠르게 처리할 수 있는 구조이다.
- 이러한 구조는 요소의 데이터 타입과 크기가 정해져 있으며, 인덱싱으로 빠르게 필드에 접근하고 변경할 수 있는 장점이 있다.
- 넘파이는 메모리 버퍼에 있는 같은 타입의 매트릭스나 벡터 같은 배열 데이터를 하드웨어 레벨인 저수준 형태로 메모리에 저장하고 처리한다.
- 또한 넘파이는 같은 크기의 메모리를 할당받고, 연속된 메모리 공간에 존재하는 벡터 연산을 지원한다.
- 효율적인 인터페이스와 최적화된 관련 함수들, 그리고 최적화된 C 코드를 통해 CPU를 관리하는 벡터화 기능을 사용한 빠른 연산도 지원한다.
뷰와 복사
뷰(View)
- 배열 데이터를 보는 하나의 방법
- 기술적으로 두 객체의 데이터가 공유된다는 것을 의미한다.
- 원래 배열에서 슬라이싱하는 슬라이스 뷰는 dtype을 변경하는 dtype 뷰로 생성할 수 있다.
- 배열의 변화를 반영하므로 새로운 데이터 타입의 배열이 위치하는 메모리를 다시 해석한다.
- 슬라이스 뷰는 넘파이에서 뷰를 생성하는 가장 일반적인 방법으로, 다음과 같이 사용한다.
>>> arr = np.arange(10)
>>> arr
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
>>> v1 = arr[1:2]
>>> v1
array([1])
>>> arr[1] = 2
>>> v1
array([2])
>>> v2 = arr[1::3]
>>> v2
array([2, 4, 7])
>>> arr[7] = 10
>>> v2
array([ 2, 4, 10])
- dtype 뷰로 같은 데이터 영역에 또 하나의 데이터 타입을 할당할 수 있다.
>>> arr = np.zeros(2, dtype=np.uint16)
>>> arr
array([0, 0], dtype=uint16)
>>> arr.view(np.uint8)
array([0, 0, 0, 0], dtype=uint8)
>>> arr.view(np.uint32)
array([0], dtype=uint32)
- astype을 이용하면 새로운 데이터 타입을 가지는 배열을 복사할 수 있는데 그 결과는 뷰와 다르다.
>>> arr = np.zeros(2, dtype=np.uint16)
>>> arr
array([0, 0], dtype=uint16)
>>> arr.astype(np.uint8)
array([0, 0], dtype=uint8)
>>> arr.astype(np.uint32)
array([0, 0], dtype=uint32)
- 2차원 배열의 뷰를 실행하는 경우
>>> arr = np.arange(4, dtype=np.uint16).reshape(2, 2)
>>> arr
array([[0, 1],
[2, 3]], dtype=uint16)
>>> arr.view(np.uint8)
array([[0, 0, 1, 0],
[2, 0, 3, 0]], dtype=uint8)
>>> arr * 100
array([[ 0, 100],
[200, 300]], dtype=uint16)
>>> (arr * 100).view(np.uint8)
array([[ 0, 0, 100, 0],
[200, 0, 44, 1]], dtype=uint8)
- dtype이 uint16인 arr에 dtype이 uint8인 뷰를 실행하면 마지막 축인 열을 따라서 shape가 (2, 4)로 변경된다.
- 이 결과는 데이터 타입 uint16인 배열 요소 2는 2개의 uint8과 같으므로, 배열 요소가 2와 0으로 변경되는 것과 같다.
- 그런데 배열 요소의 수가 255를 넘어가면 256은 0으로 세팅되어 300은 44가 된다.
- uint8이 8비트 이므로 255의 수까지 표현할 수 있기 때문에 그 이상의 수인 256부터는 0이 된다.
- 따라서 데이터 타입 uint16인 300을 uint8로 변경하면 300과 0이 아니라 44와 1이 된다.
- 1은 255를 한 번 넘었다는 뜻이다.
- 뷰는 데이터를 복사하지 않고 여러 방법으로 메모리 내에서 넘파이가 효율적으로 수행되도록 한다.
- 뷰는 정확한 strides와 shape로 배열을 생성한다.
- 여기서 strides는 특정 축에서 한 단계 이동하기 위해 메모리에서 이동할 바이트 수들을 알려준다.
- strides가 (4, 2)라는 것은 다른 행으로 이동하려면 4바이트, 열을 이동하려면 2바이트가 소요된다는 것을 의미한다.
>>> arr
array([[0, 1],
[2, 3]], dtype=uint16)
>>> arr.strides
(4, 2)
복사
- 배열 객체 arr을 불리언으로 인덱싱하면 arr 중 해당하는 부분의 복사를 반환한다.
- 복사는 arr1의 요소를 변경하더라도 원본 배열인 arr의 요소에는 변화가 없다.
>>> arr = np.random.randn(3, 4)
>>> arr
array([[-0.15138 , -0.37173983, -1.96645828, 0.30214658],
[ 0.76395484, 0.33710357, -1.37829904, 1.5614794 ],
[-0.04186889, -0.73269011, 0.37541069, -1.00037301]])
>>> arr1 = arr[arr>0]
>>> arr1
array([0.30214658, 0.76395484, 0.33710357, 1.5614794 , 0.37541069])
>>> arr1[:] = 0
>>> arr
array([[-0.15138 , -0.37173983, -1.96645828, 0.30214658],
[ 0.76395484, 0.33710357, -1.37829904, 1.5614794 ],
[-0.04186889, -0.73269011, 0.37541069, -1.00037301]])
- 그러나 같은 원본 배열에 슬라이싱을 실행해 다른 값을 동적 할당하면 원본 배열인 arr의 요소가 변경되었음을 확인할 수 있다.
>>> arr1 = arr[0, :]
>>> arr1
array([-0.15138 , -0.37173983, -1.96645828, 0.30214658])
>>> arr1[:] = 0
>>> arr
array([[ 0. , 0. , 0. , 0. ],
[ 0.76395484, 0.33710357, -1.37829904, 1.5614794 ],
[-0.04186889, -0.73269011, 0.37541069, -1.00037301]])
- 뷰를 사용하는 경우와 copy() 함수를 사용하는 경우의 비교
>>> arr = np.random.randn(3, 4)
>>> arr
array([[ 0.50856536, 0.30074826, -1.97176039, 0.34067095],
[ 0.03926801, 0.60489558, 0.06880529, 0.44914903],
[ 0.2767649 , -0.45157678, 1.58307681, 0.56481563]])
>>> arr1 = arr[0, :]; arr1
array([ 0.50856536, 0.30074826, -1.97176039, 0.34067095])
>>> arr2 = arr1[:].copy()
>>> arr2[:] = 0
>>> arr1
array([ 0.50856536, 0.30074826, -1.97176039, 0.34067095])
- arr1을 복사한 배열 arr2의 요소에 새로운 값을 동적 할당해도 원래 배열인 arr1의 요소는 변경되지 않는다.
- 따라서 배열 arr의 어떤 요소도 변경되지 않는다.
- 넘파이는 빅데이터를 처리하는 연산에서 복사보다 뷰를 사용함으로써 메모리에 주는 부담을 줄여 처리 속도를 높인다.
브로드캐스팅
- 일반적으로 크기가 다른 배열을 더하거나 빼는 등의 산술 연산은 할 수 없다.
- 브로드캐스팅은 다른 shape를 가진 배열들을 산술 연산할 수 있도록 방법을 제공한다.
- 또한 브로드캐스팅을 이용하면 코드를 단순화할 수 있다.
>>> a = np.array([1.0, 2.0, 3.0])
>>> b = np.array([2.0, 2.0, 2.0])
>>> arr = a * b
>>> arr
array([2., 4., 6.])
- 가장 간단한 브로드캐스팅은 배열과 스칼라 값이 결합되어 연산될 때 발생한다.
>>> a = np.array([1.0, 2.0, 3.0])
>>> b = 2.0
>>> a * b
array([2., 4., 6.])
- 산술 연산을 수행하는 동안, 스칼라 b가 a와 같은 shape를 가지는 배열로 확장되는 개념으로 이해할 수 있다.
- 이러한 브로드캐스팅은 곱셈 연산 작업 동안 메모리를 최적화하고 효율적으로 사용한다.
- shape (4, 3)인 배열 a와 shape (3, )인 배열 b를 더하면 브로드캐스팅 규칙에 따라 다음 그림과 같은 확장 개념으로 호환성을 확보한다.
브로드캐스팅 규칙
- 넘파이에서 두 배열을 연산할 때, 요소 단위로 두 배열의 shape를 비교한 차원이 동일하거나 둘 중 하나가 1일 때 호환할 수 있다.
- 두 배열을 연산한 결과의 크기는 입력 배열들 중 최대 크기를 가진 차원을 따라 정해진다.
예제 : 빛의 3원색 RGB 값인 256x256x3 배열을 가진 이미지의 색을 조정(scale)할 경우
- 이때 이미지를 값이 3개 있는 1차원 배열로 곱한다고 할 수 있다.
- 브로드캐스팅 규칙에 의해 이 배열들의 후행 축을 따라 정렬하면 호환성이 있음을 알 수 있다.
A (4차원 배열) : 256 x 256 x 3
B (3차원 배열) : 3
결과 (4차원 배열) : 256 x 256 x 3
- 3개의 값이 있는 1차원 배열은 3차원 배열과 연산할 수 있다.
- 비교 차원들 중, 크기가 1인 차원이 있다면 다른 차원과 일치되기 위해 차원이 늘려지거나 복사된다.
- 길이가 1인 축들을 가진 경우
- A는 4차원 배열, B는 3차원 배열로써 브로드캐스팅 연산을 하는 동안 길이가 1인 축은 더 큰 크기로 확장된다.
A (4차원 배열) : 8 x 1 x 6 x 1
B (3차원 배열) : 7 x 1 x 5
결과 (4차원 배열) : 8 x 7 x 6 x 5
- A가 3차원 배열, B가 3차원 배열일 때 축의 크기가 1인 연산은 다음과 같이 수행된다.
A (3차원 배열) : 15 x 3 x 5
B (3차원 배열) : 15 x 1 x 5
결과 (3차원 배열) : 15 x 3 x 5
- A가 3차원 배열, B가 2차원 배열일 때 shape가 다르거나 축의 크기가 1인 연산은 다음과 같이 수행된다.
A (3차원 배열) : 15 x 3 x 5
B (2차원 배열) : 3 x 5
결과 (3차원 배열) : 15 x 3 x 5
A (3차원 배열) : 15 x 3 x 5
B (2차원 배열) : 3 x 1
결과 (3차원 배열) : 15 x 3 x 5
- 브로드캐스팅 규칙이 적용된 예제
>>> arr1 = np.arange(4)
>>> arr2 = arr1.reshape(4, 1)
>>> arr3 = np.ones(5)
>>> arr4 = np.ones((3, 4))
>>> arr1.shape
(4,)
>>> arr3.shape
(5,)
>>> arr1 + arr3
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: operands could not be broadcast together with shapes (4,) (5,)
>>> arr2.shape
(4, 1)
>>> (arr2 + arr3).shape
(4, 5)
>>> arr2 + arr3
array([[1., 1., 1., 1., 1.],
[2., 2., 2., 2., 2.],
[3., 3., 3., 3., 3.],
[4., 4., 4., 4., 4.]])
>>> arr4.shape
(3, 4)
>>> (arr1 + arr4).shape
(3, 4)
>>> arr1 + arr4
array([[1., 2., 3., 4.],
[1., 2., 3., 4.],
[1., 2., 3., 4.]])
numpy.newaxis 적용
- 상수인 numpy.newaxis를 적용하면 1차원 배열을 2차원 열 벡터나 행 벡터로 변환할 수 있다.
>>> arr = np.array([0, 1, 2, 3])
>>> arr.shape
(4,)
>>> arr[np.newaxis, :] # 행 벡터로 변환
array([[0, 1, 2, 3]])
>>> arr[:, np.newaxis] # 열 벡터로 변환
array([[0],
[1],
[2],
[3]])
- shape (4, 1)과 shape (3,)의 연산
- 넘파이 인덱스 연산자인 newaxis를 사용해 1차원 shape (4,)인 배열 arr1을 2차원 shape (4, 1)로 만들어 shape (3,)인 arr2와 덧셈 연산을 할 수 있도록 한다.
>>> arr1 = np.array([0, 1, 2, 3])
>>> arr2 = np.array([10, 20, 30])
>>> arr11 = arr1[:, np.newaxis]
>>> arr11 + arr2
array([[10, 20, 30],
[11, 21, 31],
[12, 22, 32],
[13, 23, 33]])
broadcast 클래스
- 브로드캐스팅을 모방하는 객체를 생성한다.
- 입력 매개 변수들을 차례로 브로드캐스팅하고 결과를 감싸는(Encapsulation) 객체를 반환한다.
클래스 | numpy.broadcast |
매개 변수 | in1, in2, ...:유사 배열, 입력 매개 변수 |
반환 값 | b: broadcast 객체 |
- broadcast 클래스의 속성과 메소드
구분 | 종류 | 기능 |
속성 | index | 브로드캐스팅된 결과에서 현재 인덱스 |
iters | self의 요소에 따른 이터레이터(iterators)의 튜플 | |
nd | 브로드캐스팅된 결과의 차원 수 | |
ndim | 브로드캐스팅된 결과의 차원 수(넘파이 1.12.0 이후 버전) | |
numiter | 브로드캐스트 된 결과에 의해 소유된 반복자의 수 | |
shape | 브로드캐스트 된 결과의 shape | |
size | 브로드캐스트 된 결과의 총 크기 | |
메소드 | reset() | 브로드캐스트 된 결과의 iterators를 리셋 |
사용 예
- 속성 numiter
>>> arr1 = np.array([1, 2, 3])
>>> arr2 = np.array([[4], [5], [6]])
>>> arr = np.broadcast(arr1, arr2)
>>> arr.numiter
2
- shape (3, 1)과 shape(3,)인 배열의 연산
- 브로드캐스팅을 이용해 2개의 벡터를 더한다.
- 브로드캐스팅 실행 결과는 broadcast 객체이며, arr1의 shape는 (3, 1)이고, arr2의 shape가 (3,)이 되어 브로드캐스팅할 수 있는 조건이 된다.
- arr2과 arr2가 브로드캐스팅되면 arr1의 shape는 (3, 1)로 확장되고, arr2의 shape도 (3, 3)으로 확장되어 연산할 수 있는 상태가 된다.
>>> arr1 = np.array([[1], [2], [3]])
>>> arr2 = np.array([4, 5, 6])
>>> arr = np.broadcast(arr1, arr2)
>>> arr
<numpy.broadcast at 0x6bb60f8>
>>> arr.shape
(3, 3)
- flatiter 객체 생성, arr1 + arr2 연산
- out.flat을 실행하면 반복 처리할 수 있는 상태의 객체인 numpy.flatiter가 된다.
- for 반복문이나 next() 메소드를 호출함으로써 마치 1차원 배열인 것처럼 배열의 반복 처리(Iteration)를 허용한다.
- [u+v for (u, v) in arr]를 반복 처리한 값들을 out.flat인 flatiter 객체에 동적 할당하므로 배열 객체인 out이 생성된다.
- out.flat을 실행하면 반복 처리할 수 있는 상태의 객체인 numpy.flatiter가 된다.
>>> out = np.empty(arr.shape)
>>> out.flat = [u+v for (u, v) in arr]
>>> type(out.flat)
<class 'numpy.flatiter'>
>>> out
array([[5., 6., 7.],
[6., 7., 8.],
[7., 8., 9.]])
>>> arr1 + arr2
array([[5, 6, 7],
[6, 7, 8],
[7, 8, 9]])
- flatiter 클래스의 속성과 메소드
구분 | 종류 | 기능 |
속성 | base | 반복되는 대상인 배열을 참조(Reference) |
coords | 현재 좌표(Coordinate)의 N차원 튜플 | |
index | flat 인덱스를 배열로 나타냄. | |
메소드 | copy() | 1차원 배열로써 이터레이터의 복사본을 얻음. |
- flatiter 이터레이터는 flatiter 생성자를 호출하여 동작하고, 파이썬 코드로 직접 생성할 수는 없다.
>>> arr = np.arange(6).reshape(2, 3)
>>> f1 = arr.flat
>>> for item in f1:
... print(item)
...
0
1
2
3
4
5
>>> type(f1)
<class 'numpy.flatiter'>
>>> f1[2:4]
array([2, 3])
- base와 index 속성의 사용
>>> arr1 = np.arange(5)
>>> f1 = arr1.flat
>>> f1.base is arr1
True
>>> arr2 = np.arange(6).reshape(2, 3)
>>> f2 = arr2.flat
>>> f2.index
0
- flatiter의 속성 중 하나인 numpy.flatiter.coords는 현재 좌표를 N차원의 튜플로 표기한다.
>>> arr1 = np.arange(6).reshape(2, 3)
>>> f1 = arr1.flat
>>> f1.coords
(0, 0)
>>> next(f1)
0
>>> f1.coords
(0, 1)
>>> next(f1)
1
>>> f1.coords
(0, 2)
- flat 속성
- ndarray 클래스
- 1차원 배열을 반복하는 이터레이터
- numpy.flatiter 인스턴스
- 다음과 같이 arr.flat을 실행하면 2차원 배열인 arr이 반복 처리할 수 있는 1차원 배열이 되어 arr.flat[3]과 같은 값을 구할 수 있다.
>>> arr = np.arange(1, 7).reshape(2, 3)
>>> arr
array([[1, 2, 3],
[4, 5, 6]])
>>> arr.flat[3]
4
>>> arr.T
array([[1, 4],
[2, 5],
[3, 6]])
>>> arr.T.flat[3]
5
>>> type(arr.flat)
<class 'numpy.flatiter'>
- 다음과 같이 flat 속성을 적용하고 동적 할당을 할 수 있다.
>>> arr.flat[[1, 4]]
array([2, 5])
>>> arr.flat = 3; arr
array([[3, 3, 3],
[3, 3, 3]])
>>> arr.flat[[1, 4]] = 1; arr
array([[3, 1, 3],
[3, 1, 3]])
브로드캐스팅 연산
- 크기가 서로 다른 배열을 크기가 같아지도록 확장 개념을 사용해 브로드캐스팅으로 변환하면 크기가 다른 배열 간 연산을 실행할 수 있다.
- 입력 데이터보다 더 많은 출력을 얻는 문제를 해결할 때 이 방법을 사용할 수 있다.
>>> arr = np.arange(10)
>>> arr_br = arr - arr[:, np.newaxis]
>>> arr_br
array([[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
[-1, 0, 1, 2, 3, 4, 5, 6, 7, 8],
[-2, -1, 0, 1, 2, 3, 4, 5, 6, 7],
[-3, -2, -1, 0, 1, 2, 3, 4, 5, 6],
[-4, -3, -2, -1, 0, 1, 2, 3, 4, 5],
[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4],
[-6, -5, -4, -3, -2, -1, 0, 1, 2, 3],
[-7, -6, -5, -4, -3, -2, -1, 0, 1, 2],
[-8, -7, -6, -5, -4, -3, -2, -1, 0, 1],
[-9, -8, -7, -6, -5, -4, -3, -2, -1, 0]])
- 브로드캐스팅은 이미지 처리 및 관리 분야에도 적용할 수 있다.
import numpy as np
import matplotlib.pyplot as plt
arr1 = np.arange(10)
arr2 = np.arange(7)
arr_img = np.sqrt(arr1[:, np.newaxis]**2 + arr2**2)
plt.pcolor(arr_img)
plt.colorbar()
plt.axis('equal')
plt.show()
예제 : 수능 성적 분석
- 수능에서 국어, 영어, 수학 점수가 정규 분포를 따른다고 할 때, 평균과 편차를 알고 있고, 수능의 난이도가 같다면 특정 학교의 학력을 측정하는 데이터로 사용할 수 있다.
- 전국 학생들의 국어, 영어, 수학 평균 점수가 각각 70, 67, 59점이며 표준 편차는 각각 5, 7, 9일 때 샘플 15개를 활용한 정규 분포 그리고 브로드캐스팅을 적용한 예제는 다음과 같다.
>>> arr = np.random.normal(loc=[70., 67., 59.], scale = [5., 7., 9.], size = (5, 3))
>>> arr
array([[65.55729619, 70.75992918, 48.7683003 ],
[78.76417195, 62.58442299, 63.39660319],
[69.94811844, 54.83676312, 68.23035151],
[71.4668727 , 60.38309697, 60.72215292],
[67.83736681, 74.23596354, 55.02305071]])
- 다음으로 열 단위 평균을 구한 후, arr에서 arr_vec를 뺀다.
- arr의 shape는 (5, 3), arr_avc의 shape는 (3,)으로써 브로드캐스팅 조건에 적합하므로 뺄셈을 할 수 있다.
>>> arr_avc = arr.mean(axis = 0)
>>> arr_avc
array([70.71476522, 64.56003516, 59.22809172])
>>> arr - arr_avc
array([[ -5.15746903, 6.19989402, -10.45979142],
[ 8.04940673, -1.97561217, 4.16851146],
[ -0.76664678, -9.72327204, 9.00225979],
[ 0.75210749, -4.17693819, 1.49406119],
[ -2.87739841, 9.67592838, -4.20504101]])
>>> arr_avr = arr.mean(axis = 1)
>>> arr_avr
array([61.69517522, 68.24839937, 64.33841102, 64.19070753, 65.69879369])
- 행 단위로 평균을 구할 때 arr_avr의 shape는 (5,)이고, arr의 shape가 (5, 3)이므로 브로드캐스팅 조건에 적합하지 않아 연산할 수 없다.
- 따라서 브로드캐스팅 조건에 적합하도록 np.newaxis 상수를 사용해 arr_avr의 차원을 2차원인 (5, 1)로 확장하여 연산한다.
>>> arr_avr[:, np.newaxis]
array([[61.69517522],
[68.24839937],
[64.33841102],
[64.19070753],
[65.69879369]])
>>> arr - arr_avr[:, np.newaxis]
array([[ 3.86212097, 9.06475395, -12.92687492],
[ 10.51577257, -5.66397639, -4.85179619],
[ 5.60970742, -9.5016479 , 3.89194049],
[ 7.27616517, -3.80761056, -3.46855461],
[ 2.13857312, 8.53716985, -10.67574297]])
배열 조작과 정렬
C 우선 배치와 F 우선 배치
- 넘파이 배열은 행 우선순위로 처리된다.
- 배열의 행에 위치한 데이터들이 서로 인접해 로딩된다는 것을 의미한다.
- 옵션에 F, C를 정하지 않으면 기본값인 C 우선 배치로 처리된다.
- F : Fortran 언어
- C : C 언어
>>> arr = np.arange(12).reshape(3, 4)
>>> arr
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]])
>>> arr.ravel(order='F')
array([ 0, 4, 8, 1, 5, 9, 2, 6, 10, 3, 7, 11])
>>> arr.ravel(order='C')
array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])
- ravel() 함수는 numpy.ndarray.ravel과 numpy.ravel로 구분하여 사용하지만, 1차원 배열을 반환한다는 점에서 기능은 같다.
>>> arr.reshape(2, 6)
array([[ 0, 1, 2, 3, 4, 5],
[ 6, 7, 8, 9, 10, 11]])
>>> arr.ravel(order='F').reshape(2, 6)
array([[ 0, 4, 8, 1, 5, 9],
[ 2, 6, 10, 3, 7, 11]])
- 배열 arr을 F순으로 인덱싱하고, shape (2, 6)으로 변형한다.
- order 키워드
- 배열 arr에서 값들을 가져오고 값들을 출력 배열에 배치하기 위해 인덱스 순서를 제어한다.
- C 우선 배치와 F 우선 배치는 인접(Contigunous) 배열과 비인접(Uncontiguous) 배열 개념으로 설명할 수 있다.
- 배열의 요소는 메모리에 저장되는데 인접 배열은 연속된 메모리 블록에 저장되며, 배열에서 다음 요솟값으로 접근할 때는 메모리 내에서 다음 주소로 이동하게 된다.
- 옵션이 설정되지 않을 때 배열 요소는 다음 처럼 C 우선으로 배치되어 arr이 shape (3, 2)로 표시된다.
- 그리고 메모리는 인접 배치되어 접근한다.
- 행이 연속된 메모리 블록으로 저장되므로 C 인접 배열이 된다.
- 여기에서 다음과 같이 배열 arr을 arr.T로 전치하면 열이 메모리 인접 블록으로 저장되므로 F 인접 배열이 된다.
- 메모리 인접 블록으로 저장된 배열을 연산하면 매우 빠르게 처리할 수 있다.
- C 인접 배열이 F 인접 배열보다 빠른 연산을 할 수 있으며, 넘파이는 C 인접 배열을 기본으로 한다.
>>> arr = np.arange(6)
>>> np.reshape(arr, (2, 3))
array([[0, 1, 2],
[3, 4, 5]])
>>> np.reshape(np.ravel(arr), (2, 3))
array([[0, 1, 2],
[3, 4, 5]])
>>> np.reshape(arr, (2, 3), order='F')
array([[0, 2, 4],
[1, 3, 5]])
>>> np.reshape(np.ravel(arr, order='F'), (2, 3), order='F')
array([[0, 2, 4],
[1, 3, 5]])
배열을 이어 붙이고 스택으로 배치하기
- 배열을 이어 붙일 때 numpy.concatenate() 함수를 사용한다.
- 이 함수는 설정한 축을 따라 배열을 이어 붙인다.
>>> arr1 = np.array([[1, 2], [3, 4]])
>>> arr2 = np.array([[5, 6]])
>>> np.concatenate((arr1, arr2), axis=0)
array([[1, 2],
[3, 4],
[5, 6]])
>>> np.concatenate((arr1, arr2.T), axis=1)
array([[1, 2, 5],
[3, 4, 6]])
>>> np.concatenate((arr1, arr2), axis=None)
array([1, 2, 3, 4, 5, 6])
- numpy.vstack()은 수직으로 배열을 쌓는다. (행 단위)
- axis=0을 설정하여 이어 붙이는 것과 동일
- numpy.hstack()은 수평으로 배열을 쌓는다. (열 단위)
- axis=1을 설정하여 이어 붙이는 것과 동일
>>> np.hstack((arr1, arr2))
ValueError: all the input array dimensions for the concatenation axis must match exactly, but along dimension 0, the array at index 0 has size 2 and the array at index 1 has size 1
>>> np.vstack((arr1, arr2))
array([[1, 2],
[3, 4],
[5, 6]])
- 다음 예의 arrays는 shape (3, 4)의 2차원 배열 10개 요소로 구성되는 리스트이다.
- 이것을 수직으로 쌓기 위해 axis=0인 stack() 함수를 실행하면 shape (10, 3, 4)인 3차원 배열이 된다.
- 수평으로 쌓기 위해 axis=1로 설정하면 shape (3, 10, 4)가 된다.
- axis=2로 설정하면 shape (3, 4, 10)이 된다.
>>> arrays = [np.random.randn(3, 4) for _ in range(10)]
>>> np.stack(arrays, axis=0).shape
(10, 3, 4)
>>> np.stack(arrays, axis=1).shape
(3, 10, 4)
>>> np.stack(arrays, axis=2).shape
(3, 4, 10)
>>> arr1 = np.array([1, 2, 3])
>>> arr2 = np.array([2, 3, 4])
>>> np.stack((arr1, arr2))
array([[1, 2, 3],
[2, 3, 4]])
>>> np.stack((arr1, arr2), axis=-1)
array([[1, 2],
[2, 3],
[3, 4]])
- numpy.vstack()은 행 단위로 수직 순서대로 배열을 쌓는다.
- 이것은 shape가 (N,)인 1차원 배열 (1, N) shape로 변형한 후 첫 번째 축을 따라 이어 붙이는 것과 동일하다.
>>> arr1 = np.array([1, 2, 3])
>>> arr2 = np.array([2, 3, 4])
>>> np.vstack((arr1, arr2))
array([[1, 2, 3],
[2, 3, 4]])
>>> arr3 = np.array([[1], [2], [3]])
>>> arr4 = np.array([[2], [3], [4]])
>>> np.vstack((arr3, arr4))
array([[1],
[2],
[3],
[2],
[3],
[4]])
- numpy.hstack()은 열 단위로 수평 순서대로 배열을 쌓는다.
- 이것은 첫 번째 축을 따라 이어 붙이는 1차원 배열을 제외하고 두 번째 축을 따라 이어 붙이는 것과 동일하다.
>>> arr1 = np.array((1, 2, 3))
>>> arr2 = np.array((2, 3, 4))
>>> np.hstack((arr1, arr2))
array([1, 2, 3, 2, 3, 4])
>>> arr3 = np.array([[1], [2], [3]])
>>> arr4 = np.array([[2], [3], [4]])
>>> np.hstack((arr3, arr4))
array([[1, 2],
[2, 3],
[3, 4]])
배열 순서 정렬
- 넘파이에는 순서를 정렬(Sorting)하는 여러 함수가 있다.
- 이 함수들은 실행 속도, 요구되는 작업 공간이나 안정도 등에 따라 구분하기도 한다.
>>> arr = np.array([[1, 4], [3, 1]])
>>> np.sort(arr) # 마지막 축을 따라 정렬
array([[1, 4],
[1, 3]])
>>> np.sort(arr, axis=None) # 풀린 배열을 정렬
array([1, 1, 3, 4])
>>> np.sort(arr, axis=0) # 첫 번째 축을 따라 정렬
array([[1, 1],
[3, 4]])
- 구조화된 배열을 정렬할 때, order 키워드로 정렬할 필드를 지정할 수 있다.
>>> dtype = [('name', 'S10'), ('height', float), ('age', int)]
>>> values = [('Jin', 175, 59), ('Suho', 185, 19), ('Naeun', 162, 28)]
>>> arr = np.array(values, dtype=dtype) # 구조화된 배열 생성
>>> np.sort(arr, order='height')
array([(b'Naeun', 162., 28), (b'Jin', 175., 59), (b'Suho', 185., 19)],
dtype=[('name', 'S10'), ('height', '<f8'), ('age', '<i4')])
- 배열을 age 기준으로 정렬한다.
- age가 동일하면 height를 기준으로 정렬한다.
>>> np.sort(arr, order=['age', 'height'])
array([(b'Suho', 185., 19), (b'Naeun', 162., 28), (b'Jin', 175., 59)],
dtype=[('name', 'S10'), ('height', '<f8'), ('age', '<i4')])
- 배열 정렬 함수 numpy.ndarray.sort()를 이용해 정렬할 수도 있다.
>>> arr = np.array([[1, 4], [3, 1]])
>>> arr.sort(axis=1)
>>> arr
array([[1, 4],
[1, 3]])
>>> arr.sort(axis=0)
>>> arr
array([[1, 3],
[1, 4]])
- numpy.argsort는 배열을 정렬할 때 인덱스를 반환한다.
>>> arr = np.array([3, 1, 2])
>>> sorted_by_index = np.argsort(arr)
>>> sorted_by_index
array([1, 2, 0], dtype=int64)
>>> for i in sorted_by_index:
... print(arr[i])
...
1
2
3
>>> arr = np.array([[0, 3], [2, 2]])
>>> arr
array([[0, 3],
[2, 2]])
>>> np.argsort(arr, axis=0) # 첫 번째 축을 따라 정렬
array([[0, 1],
[1, 0]], dtype=int64)
>>> np.argsort(arr, axis=1) # 마지막 축을 따라 정렬
array([[0, 1],
[0, 1]], dtype=int64)
- order 키워드로 다음과 같이 배열을 정렬할 수 있다.
>>> arr = np.array([(1, 0), (0, 1)], dtype=[('x', '<i4'), ('y', '<i4')])
>>> arr
array([(1, 0), (0, 1)], dtype=[('x', '<i4'), ('y', '<i4')])
>>> np.argsort(arr)
array([1, 0], dtype=int64)
>>> np.argsort(arr, order=('x', 'y'))
array([1, 0], dtype=int64)
>>> np.argsort(arr, order=('y', 'x'))
array([0, 1], dtype=int64)
- numpy.lexsort는 keys 인수의 순서를 사용하여 간접적으로 안정적인(stable) 정렬을 수행한다.
>>> arr1 = np.array([2, 2, 1, 1])
>>> arr2 = np.array([2, 2, 1, 1])
>>> arr = np.lexsort((arr1, arr2))
>>> arr
array([2, 3, 0, 1], dtype=int64)
- lexsort는 keys 인수인 튜플(arr1, arr2) 중 먼저 arr2를 정렬하고 그 다음 arr1을 정렬한다.
- arr2 요솟값들이 모두 같으면 arr1을 기준으로 정렬한다.
- 따라서 arr2의 [2, 2, 1, 1]에서 세 번째 1과 네 번째 1을 우선 정렬해야 하는데 값이 같으므로 arr1을 참조해야 한다.
- arr1 역시 세 번째와 네 번째 요소가 같으므로 앞부분의 1이 우선 정렬된다.
- 결국 arr의 세 번째 위치에 있는 1이 가장 먼저 정렬되므로 그 인덱스인 2가 가장 앞에 위치한다.
>>> surnames = ('Hong', 'Na', 'Kim')
>>> first_names = ('Gildong', 'Haeseok', 'Mandeok')
>>> ind = np.lexsort((first_names, surnames))
>>> ind
array([0, 2, 1], dtype=int64)
>>> [surnames[i] + "," + first_names[i] for i in ind]
['Hong,Gildong', 'Kim,Mandeok', 'Na,Haeseok']
- 다음과 같이 숫자들로 구성된 a와 b를 인수로 정렬할 수 있다.
- a열에서 1은 2개이며, 위치는 인덱스 0과 2이다.
- 따라서 동일한 숫자를 인덱싱하는 것이므로 서열을 정하기 위해 b를 참조할 때 첫 번째 1은 b에서 9고 두 번째 1은 0이므로 두 번째가 앞에 위치한다.
- 따라서 인덱스 2가 가장 앞에 위치하는 것이다.
- 이런 방법을 나머지 요소에도 적용한다.
>>> a = [1, 5, 1, 4, 3, 4, 4] # 첫 번째 열
>>> b = [9, 4, 0, 4, 0, 2, 1] # 두 번째 열
>>> ind = np.lexsort((b, a)) # a를 기준으로 정렬한 다음 b를 기준으로 정렬
>>> ind
array([2, 0, 4, 6, 5, 3, 1], dtype=int64)
>>> print(ind)
[2 0 4 6 5 3 1]
>>> [(a[i], b[i]) for i in ind]
[(1, 0), (1, 9), (3, 0), (4, 1), (4, 2), (4, 4), (5, 4)]
>>> [(a[i], b[i]) for i in np.argsort(a)]
[(1, 9), (1, 0), (3, 0), (4, 4), (4, 2), (4, 1), (5, 4)]
- 구조화된 배열은 argsort를 이용해 정렬할 수 있다.
>>> arr = np.array([(1, 9), (5, 4), (1, 0), (4, 4), (3, 0), (4, 2), (4, 1)], dtype=np.dtype([('x', int), ('y', int)]))
>>> np.argsort(arr) # 또는 np.argsort(arr, order=('x', 'y'))
array([2, 0, 4, 6, 5, 3, 1], dtype=int64)
- numpy.searchsorted는 삽입하는 위치에서 순서에 따라 인덱스를 찾는다.
>>> np.searchsorted([1, 2, 3, 4, 5], 3)
2
>>> np.searchsorted([1, 2, 3, 4, 5], 3, side = 'right')
3
>>> np.searchsorted([1, 2, 3, 4, 5], [-10, 10, 2, 3])
array([0, 5, 1, 2], dtype=int64)
히스토그램 함수
- numpy.histogram은 데이터 세트의 히스토그램을 그리며 numpy.searchsorted와 함께 자주 사용한다.
- 히스토그램 : 연속된 데이터 집합의 도수 분포를 기둥 모양의 직사각형을 이용해 나타내는 그래프
- numpy.histogram을 사용하면 히스토그램 값과 구간인 bins를 구할 수 있다.
- histogram() 함수를 실행해 반환되는 값은 요소를 2개 가지는 튜플형 데이터이다.
- 첫 번째 항 : 도수 분포를 나타내는 히스토그램 값
- 두 번째 항 : 균일한 너비의 등급을 나타내는 bins
- 따라서 요소를 a와 b, 즉 첫 번째 항과 두 번째 항으로 각각 나타낼 수 있다.
>>> arr = np.array([15, 16, 16, 17, 19, 20, 22, 35, 43, 45, 55, 59, 60, 75, 88])
>>> np.histogram(arr, bins=[0, 20, 40, 60, 80, 100])
(array([5, 3, 4, 2, 1], dtype=int64), array([ 0, 20, 40, 60, 80, 100]))
>>> a, b = np.histogram(arr, bins=[0, 20, 40, 60, 80, 100])
>>> a
array([5, 3, 4, 2, 1], dtype=int64)
>>> b
array([ 0, 20, 40, 60, 80, 100])
- matplotlib 모듈을 사용하면 수식으로 표현된 히스토그램을 그래프로 간단히 변환할 수 있다.
import matplotlib.pyplot as plt
import numpy as np
arr = np.array([15, 16, 16, 17, 19, 20, 22, 35, 43, 45, 55, 59, 60, 75, 88])
plt.hist(arr, bins=[0, 20, 40, 60, 80, 100])
plt.title("numbers depending on ages")
plt.show()
- histogram()에 다양한 인수를 적용할 수 있다.
>>> np.histogram([1, 2, 1], bins=[0, 1, 2, 3])
(array([0, 2, 1], dtype=int64), array([0, 1, 2, 3]))
>>> np.histogram(np.arange(4), bins=np.arange(5), density=True)
(array([0.25, 0.25, 0.25, 0.25]), array([0, 1, 2, 3, 4]))
>>> np.histogram([[1, 2, 1], [1, 0, 1]], bins=[0, 1, 2, 3])
(array([1, 4, 1], dtype=int64), array([0, 1, 2, 3]))
- bins=[0, 1, 2, 3]은 첫 번째 bin [1, 2), 두 번째 bin [2, 3), 마지막 bin [3, 4) 범위를 나타낸다.
- [1, 2)에서 오른쪽 소괄호 앞에 있는 값은 포함되지 않음을 의미하므로 1보다 크거나 같고 2보다 작은 범위이다.
배열 연산
- 넘파이에서 배열은 같은 타입 요소를 가지는 다차원 배열이다.
- 요소를 나타내는 인덱스는 양의 정수인 튜플이라는 데이터 타입으로 표기된다.
- 넘파이에서 중요하게 언급되는 차원은 축이라고 한다.
다차원 배열 연산
- 파이썬은 고수준의 동적 언어이지만, 파이썬의 넘파이 라이브러리는 저수준 언어인 C 보다 느리다.
- 하지만, 다차원 배열 연산을 빠르게 처리하기 위해 고성능 수치 계산을 수행하는 특별한 데이터 구조를 제공한다.
- 넘파이는 C로 설계된 다차원 배열 구조를 실행하면서 파이썬 인터페이스를 제공하므로 빠르게 연산을 처리할 수 있다.
예제 : 축이 2개인 2차원 배열 연산하기
>>> arr = np.array([[1, 2, 3], [4, 5, 6]], dtype='int32')
>>> arr
array([[1, 2, 3],
[4, 5, 6]])
>>> arr.sum(axis=0)
array([5, 7, 9])
>>> arr.sum(axis=1)
array([ 6, 15])
- 0축은 열, 1축은 행 방향으로 연산을 수행한다.
- axis=1 은 행 방향으로 더하므로 열 방향으로 더하는 axis=0 보다 빠르게 연산을 처리한다.
예제 : 축이 3개인 3차원 배열 연산하기
>>> arr = np.arange(24).reshape(3, 2, 4)
>>> arr
array([[[ 0, 1, 2, 3],
[ 4, 5, 6, 7]],
[[ 8, 9, 10, 11],
[12, 13, 14, 15]],
[[16, 17, 18, 19],
[20, 21, 22, 23]]])
>>> arr.shape
(3, 2, 4)
>>> arr.sum(axis=0)
array([[24, 27, 30, 33],
[36, 39, 42, 45]])
>>> arr.sum(axis=1)
array([[ 4, 6, 8, 10],
[20, 22, 24, 26],
[36, 38, 40, 42]])
>>> arr.sum(axis=2)
array([[ 6, 22],
[38, 54],
[70, 86]])
- axis=1은 가장 안쪽 대괄호를 기준으로 열 방향으로 더한다.
- axis=0은 두 번째 대괄호를 기준으로 하여 그 괄호 안에서 요소들을 각각 더한다.
- arr의 shape (3, 2, 4)는 순서대로 axis 0, axis 1, axis 2가 된다.
- axis=0을 따라 3개의 요소를 axis=1을 따라 2개의 요소를, axis=2를 따라 4개의 요소를 가진다는 뜻이다.
예제 : random() 함수를 활용해 리스트를 생성하는 속도와 넘파이에서 배열을 연산하는 처리하는 속도의 비교
- 파이썬만을 이용하는 ln [8]과 넘파이 배열만 이용하는 ln [9]의 연산 처리 속도에 많은 차이가 있는 것을 알 수 있다.
- ln [8]은 리스트 a와 b의 요소를 직접 더하는 것이 아니라 결합하는 경우이므로 arr1과 arr2의 각 요소를 더하는 ln [9] 연산과는 다르다.
- 그러나 같은 조건 연산인 ln [10]과 ln [11]의 연산 처리 속도를 비교하면 넘파이 배열 객체의 연산이 빠른 것을 확인할 수 있다.
배열 반복
- 파이썬에서 리스트를 반복하는 것처럼 배열도 반복할 수 있다.
>>> arr = np.array([1, 3, 5, 7])
>>> for i in arr:
... print(i)
...
1
3
5
7
- 다차원 배열을 반복하면 첫 번째 축에서 배열이 하위 요소를 반환한다.
>>> arr = np.arange(8).reshape(4, 2)
>>> for i in arr:
... print(i)
...
[0 1]
[2 3]
[4 5]
[6 7]
- 곱셈 연산을 하는 배열은 다음과 같이 반복한다.
>>> arr = np.arange(8).reshape(4, 2)
>>> for (a, b) in arr:
... print(a*b)
...
0
6
20
42
임의의 수 생성
- random 모듈의 rand() 함수는 주어진 shape에 대해 임의의 값들을 반환한다.
>>> np.random.rand(3, 2)
array([[0.74977373, 0.93662644],
[0.69571843, 0.47650603],
[0.78964881, 0.84466786]])
- 입력한 shape 배열을 생성하고, [0, 1) 안에서 일정한 분포의 임의의 값을 생성해 덧붙인다.
- random 모듈의 randint(low, high) 함수는 low를 포함하고 high를 제외하는 임의의 정수들을 반환한다.
- 반만 열린 범위 [low, high)에서는 특정 dtype의 이산 균등 분포에서 임의의 정수들을 반환한다.
- 만약 high가 기본값인 None이면 결과는 [0, low)이다.
>>> np.random.randint(2, size=10)
array([0, 0, 1, 0, 0, 0, 0, 0, 1, 1])
>>> np.random.randint(5, size=10)
array([3, 4, 4, 3, 2, 0, 0, 0, 1, 2])
- 다음은 0과 4 사이의 정수로 2×4 배열을 생성하는 예제이다.
>>> np.random.randint(5, size=(2, 4))
array([[4, 2, 1, 0],
[1, 4, 0, 1]])
- random 모듈의 choice() 함수는 주어진 1차원 배열에서 임의의 샘플을 생성한다.
>>> np.random.choice(5, 3)
array([2, 2, 3])
- size가 3이고 np.arange(5)에서 일정한 임의의 샘플을 생성하는 결과는 np.random.randint(0, 5, 3)과 같다.
- 다음은 size가 3이고 np.arange(5) 범위에서 임의의 샘플을 생성하는 예제이다.
- 확률을 정의하는 p 인수가 설정되었으므로 1, 4가 생성될 확률은 0이다.
>>> np.random.choice(5, 3, p=[0.1, 0, 0.3, 0.6, 0])
array([3, 3, 3])
- 다음 예제는 size가 10으로 일정한 배열 객체 arr에서 임의의 샘플을 생성한다.
- 인수 replace가 True이면 복원 추출(Sample with Replacement)을 사용한다.
- 이는 생성되는 요소 중 반복되는 요소가 있다는 의미이다.
>>> arr = np.arange(12)
>>> np.random.choice(arr, size=10, replace=True)
array([ 7, 10, 2, 1, 1, 3, 9, 3, 0, 9])
>>> np.random.choice(arr, size=10, replace=False)
array([ 7, 5, 1, 4, 2, 8, 9, 10, 6, 11])
- 다음 예제는 재형성(Reshape) 없이 size는 3이고 np.arange(5) 범위에서 일정하지 않은 임의의 샘플을 생성한다.
>>> np.random.choice(5, 3, p=[0.1, 0, 0.3, 0.6, 0])
array([2, 0, 0])
- 다음과 같이 정수 대신 임의의 유사 배열을 반복할 수 있다.
>>> arr_like = ['yakyong', 'jegong', 'manduck', 'haeseok']
>>> np.random.choice(arr_like, 5, p=[0.5, 0.1, 0.1, 0.3])
array(['jegong', 'yakyong', 'yakyong', 'haeseok', 'yakyong'], dtype='<U7')
선형 대수
- 넘파이는 선형 대수(Linear Algebra)를 지원하는 numpy.linalg 모듈을 제공한다.
- 이 모듈은 선형 대수에서 요구하는 많은 기능을 제공하며, 넘파이 배열에 선형 대수를 적용하는 수단이다.
- 또한 인공지능의 머신러닝과 딥러닝에 자주 적용한다.
- 선형 대수에서 행렬과 벡터곱을 위한 함수
함수의 종류 | 기능 |
dot(a, b[, out]) | Dot product of two arrays. |
linalg.multi_dot(arrays, *[, out]) | Compute the dot product of two or more arrays in a single function call, while automatically selecting the fastest evaluation order. |
vdot(a, b, /) | Return the dot product of two vectors. |
inner(a, b, /) | Inner product of two arrays. |
outer(a, b[, out]) | Compute the outer product of two vectors. |
matmul(x1, x2, /[, out, casting, order, ...]) | Matrix product of two arrays. |
tensordot(a, b[, axes]) | Compute tensor dot product along specified axes. |
einsum(subscripts, *operands[, out, dtype, ...]) | Evaluates the Einstein summation convention on the operands. |
einsum_path(subscripts, *operands[, optimize]) | Evaluates the lowest cost contraction order for an einsum expression by considering the creation of intermediate arrays. |
linalg.matrix_power(a, n) | Raise a square matrix to the (integer) power n. |
kron(a, b) | Kronecker product of two arrays. |
- 선형 대수의 $ax = b$ 라는 행렬의 벡터 방정식이 있을 때, 벡터 $x$ 를 구할 수 있다.
예제 : 3개 변수를 가지는 연립 방정식에서 $x$ 구하기
연립 방정식 | 행렬 |
$x_{1} + 2x_{2} + 3x_{3} = -2$ $2x_{1} + x_{3} = 4$ $x_{1} - x_{2} + x_{3} = -1$ |
$a = \begin{bmatrix} 1 & 2 & 3 \\ 2 & 0 & 1 \\ 1 & -1 & 1 \end{bmatrix}$ $b = \begin{bmatrix} -2 \\ 4 \\ -1 \end{bmatrix}$ |
- 벡터 $a$ 와 $b$ 를 배열로 생성한 후, 다음과 같이 x를 구할 수 있는데 차례대로 $x_{1}, x_{2}, x_{3}$ 이다.
>>> a = np.array([[1, 2, 3], [2, 0, 1], [1, -1, 1]])
>>> b = np.array([-2, 4, -1])
>>> x = np.linalg.solve(a, b)
>>> x
array([ 3.42857143, 1.57142857, -2.85714286])
- numpy.linalg.solve 는 선형 매트릭스 방정식이나 선형 스칼라 방정식을 푼다.
예제 : 방정식 $x_{1} + 3x_{0} = 9$ 와 $2x_{1} + x_{0} = 8$ 풀기
>>> a = np.array([[3, 1], [1, 2]])
>>> b = np.array([9, 8])
>>> x = np.linalg.solve(a, b)
>>> x
array([2., 3.])
- 벡터 [3, 1]과 [1, 2]가 선형 독립적인 선형 매트릭스 방정식 $ax = b$ 의 $x$ 를 구한다.
- 벡터는 크기와 방향을 가진다.
- 내적은 방향을 가진 크기를 곱하며, 비슷한 차원을 가진 벡터 사이에서 작용한다.
- 이와 반대되는 개념은 외적이라고 하며, 다른 차원을 가진 벡터 사이의 작용을 의미한다.
- 2개의 1차원 배열 $a, b$ 의 내적을 계산하면 $a$ 와 $b$ 벡터 각각의 배열 내부 요소를 곱해서 더한다.
>>> a = np.array([1, 2, 3])
>>> b = np.array([4, 5, 6])
>>> np.dot(a, b)
32
- 2차원 배열 이상의 내적 계산은 배열 arr1의 마지막 축과 배열 arr2의 마지막의 두 번째 축을 곱해서 더하면 된다.
>>> arr1 = np.array([[1, 2], [3, 4]])
>>> arr2 = np.array([[4, 5], [6, 7]])
>>> np.dot(arr1, arr2)
array([[16, 19],
[36, 43]])
- arr1의 마지막 축은 0축이고, arr2의 마지막 두 번째 축은 1축이다.
- 선형 대수의 방정식 및 역행렬을 연산하는 함수는 다음과 같다.
함수 종류 | 기능 |
linalg.solve(a, b) | Solve a linear matrix equation, or system of linear scalar equations. |
linalg.tensorsolve(a, b[, axes]) | Solve the tensor equation a x = b for x. |
linalg.lstsq(a, b[, rcond]) | Return the least-squares solution to a linear matrix equation. |
linalg.inv(a) | Compute the (multiplicative) inverse of a matrix. |
linalg.pinv(a[, rcond, hermitian]) | Compute the (Moore-Penrose) pseudo-inverse of a matrix. |
linalg.tensorinv(a[, ind]) | Compute the 'inverse' of an N-dimensional array. |
728x90
그리드형(광고전용)
'In-depth Study > NumPy' 카테고리의 다른 글
[NumPy] 넘파이 적용 (0) | 2022.04.14 |
---|---|
[NumPy] 구조화된 배열 (0) | 2022.04.13 |
[NumPy] 넘파이 배열 (0) | 2022.04.13 |
[NumPy] 넘파이(NumPy) 개요 (0) | 2022.04.13 |