Numpy
Numpy
Numpy는 Numerical Python의 줄임말로, 파이썬에서 산술 계산을 위한 가장 중요한 필수 패키지 중 하나다.
Numpy가 파이썬 산술 계산 영역에서 중요한 위치를 차지하는 이유 중 하나는 대용량 데이터 배열을 효율적으로 다룰 수 있도록 설계되었다는 점이다. 실제로, Numpy배열은 파이썬 리스트에 비해서 훨씬 빠르고 메모리도 적게 사용한다.
1. ndarray
- ndarray 생성하기
data2 = [[1, 2, 3, 4], [5, 6, 7, 8]]
arr2 = np.array(data2) # numpy 배열로 변환
arr2.ndim
>>> 2
arr2.shape
>>> (2, 4)
arr2.dtype
>>> dtype('int64')
np.zeros((2,3))
>>> array([0., 0., 0.],
[0., 0., 0.],
[0., 0., 0.])
- 배열 생성 함수
함수 | 설명 |
---|---|
array | 입력 데이터(리스트, 튜플, 배열 또는 다른 순차형 데이터)를 ndarray로 변환하며 dtype을 명시하지 않은 경우 자료형을 추론하여 저장한다. 기본적으로 입력 데이터는 복사된다. |
asarray | 입력 데이터를 ndarray로 변환하지만 입력 데이터가 이미 ndarray일 경우 복사가 일어나지 않는다. |
arange | 내장 range 함수와 유사하지만 리스트 대신 ndarray를 반환한다. |
ones, ones_like | 주어진 dtype과 모양을 가지는 배열을 생성하고 내용을 모두 1로 초기화한다. |
zeros, zeros_like | 주어진 dtype과 모양을 가지는 배열을 생성하고 내용을 모두 0으로 초기화한다. |
empty, empty_like | 메모리를 할당하여 새로운 배열을 생성하지만 값을 초기화하지 않는다. |
full, full_like | 인자로 받은 dtype과 배열의 모양을 가지는 배열을 생성하고 인자로 받은 값으로 배열을 채운다. |
eye, identity | N x N 크기의 단위행렬을 생성한다. |
-
astype
배열의 dtype을 다른 type으로 명시적으로 변환
arr = np.array([1, 2, 3, 4, 5]) arr.dtype >>> dtype('int64') float_arr = arr.astype(np.float64) float_arr.dtype >>> dtype('float64')
-
Numpy 배열의 비교 연산
arr = np.array([[1., 2., 3.], [4., 5., 6.]]) arr2 = np.array([[0., 4., 1.], [7., 2., 12.]]) arr2 > arr >>> array([[False, Trye, False], [True, False, True]], dtype=bool)
-
슬라이싱
numpy array는 리스트와는 다르게 배열 조각이 원본 배열의 뷰라는 점이다. 즉, 데이터는 복사되지 않고 뷰에 대한 변경은 그대로 원본 배열에 반영된다. 따라서, 데이터 복사를 원할 경우엔 .copy()를 사용해야 한다.
arr = np.arrange(10) arr_slice = arr[5:8] arr_slice[1] = 12 arr >>> array([0, 1, 2, 3, 4, 5, 12, 7, 8, 9])
단순히 [:]로 슬라이스를 하면 배열의 모든 값을 할당한다.
arr_slice[:] = 64 arr >>> array([0, 1, 2, 3, 4, 64, 64, 64, 8, 9])
다차원 배열의 요소 접근 방법
arr2d = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) arr2d[2] >>> array([7, 8, 9]) arr2d[0][2] >>> 3 arr2d[0, 2] >>> 3
2차원 배열 슬라이싱
arr = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) arr[2] >>> array([7, 8, 9]) # shape : (3,) arr[2, :] >>> array([7, 8, 9]) # shape : (3,) arr[2:, :] >>> array([[7, 8, 9]]) # shape : (3, 2)
-
불리언값으로 선택하기
names = np.array(['Bob', 'Joe', 'Will', 'Bob', 'Will', 'Joe', 'Joe']) data = np.random.randn(7, 4) data >>> array([[ 0.59121224, -0.04524579, -0.13953923, 0.76120115], [ 1.09306497, -0.76275502, -0.43073352, 0.03650304], [ 1.25717796, -1.50223001, -1.22789095, 0.23870066], [-0.78150188, 1.69973467, -0.28157892, 1.03837459], [ 0.24987916, -0.23686396, 1.84426461, 0.14067641], [ 0.20287385, 0.246164 , 1.48979903, -0.00950569], [-1.26958203, 1.54379097, -0.64812676, 0.18417653]]) names == 'Bob' >>> array([ True, False, False, True, False, False, False]) data[names == 'Bob'] >>> array([[ 0.59121224, -0.04524579, -0.13953923, 0.76120115], [-0.78150188, 1.69973467, -0.28157892, 1.03837459]]) data[data < 0] = 0 data >>> array([[0.59121224, 0. , 0. , 0.76120115], [1.09306497, 0. , 0. , 0.03650304], [1.25717796, 0. , 0. , 0.23870066], [0. , 1.69973467, 0. , 1.03837459], [0.24987916, 0. , 1.84426461, 0.14067641], [0.20287385, 0.246164 , 1.48979903, 0. ], [0. , 1.54379097, 0. , 0.18417653]])
-
Fancy Indexing
arr = np.arange(32).reshape((8, 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], [24, 25, 26, 27], [28, 29, 30, 31]]) arr[[4, 3, 0, 6]] # 행별로 데이터에 접근 >>> array([[16, 17, 18, 19], [12, 13, 14, 15], [ 0, 1, 2, 3], [24, 25, 26, 27]]) arr[[-3, -5, -7]] # '-'붙을 경우 뒤에서부터 접근 >>> array([[20, 21, 22, 23], [12, 13, 14, 15], [ 4, 5, 6, 7]]) arr[[1, 5, 7, 2], [0, 3, 1, 2]] #','가 있어서 행,열에 차례로 접근하여 원소를 뽑아냄 >>> array([ 4, 23, 29, 10]) arr[[1, 5, 7, 2]][:, [0, 3, 1, 2]] >>> array([[ 4, 7, 5, 6], [20, 23, 21, 22], [28, 31, 29, 30], [ 8, 11, 9, 10]])
-
배열 연산으로 조건절 표현하기
numpy.where 함수는 x if 조건 else y 같은 삼항식의 벡터화된 버전이다. 따라서 간결하게 작성할 수 있다는 장점.
xarr = np.array([1.1, 1.2, 1.3, 1.4, 1.5]) yarr = np.array([2.1, 2.2, 2.3, 2.4, 2.5]) cond = np.array([True, False, True, True, False]) result = [(x if c else y) for x, y, c in zip(xarr, yarr, cond)] result >>> [1.1, 2.2, 1.3, 1.4, 2.5] np.where(cond, xarr, yarr) >>> array([1.1, 2.2, 1.3, 1.4, 2.5])
where의 두 번째 인자와 세 번째 인자는 배열이 아니어도 상관없다. 둘 중 하나 혹읜 둘 다 스칼라값이어도 동작한다.
arr = np.random.randn(4, 4) arr >>> array([[ 2.54853567, -0.36547023, -0.14069661, 1.50669036], [ 0.69536721, 0.6803319 , 0.69550533, 0.47494734], [-1.48340217, 0.36163438, 0.46765405, 1.54305179], [-0.48093816, 1.03942503, 0.08678082, -1.37288758]]) np.where(arr > 0, 2, arr) # 양수인 경우에만 2를 대입 >>> array([[ 2. , -0.36547023, -0.14069661, 2. ], [ 2. , 2. , 2. , 2. ], [-1.48340217, 2. , 2. , 2. ], [-0.48093816, 2. , 2. , -1.37288758]])
-
불리언 배열을 위한 method
arr = np.random.randn(100) (arr > 0).sum() # 양수인 원소의 개수 >>> 42 bools = np.array([False, False, True, False]) bools.any() # 하나 이상의 값이 True인지 검사 >>> True bools.all() # 모든 원소가 True인지 검사 >>> False
-
집합 관련 함수
# 순수 파이썬 이용 sorted(set(names)) >>> ['Bob', 'Joe', 'Will'] # numpy 함수 이용 names = np.array(['Bob', 'Joe', 'Will', 'Bob', 'Will', 'Joe', 'Joe']) np.unique(names) >>> array(['Bob', 'Joe', 'Will'], dtype='<U4')
배열 집합 연산
method 설명 unique(x) 배열 x에서 중복된 원소를 제거한 뒤 정렬하여 반환 intersect1d(x, y) 배열 x와 y에 공통적으로 존재하는 원소를 정렬하여 반환 union1d(x, y) 두 배열의 합집합을 반환 in1d(x, y) x의 원소가 y의 원소에 포함되는지 나타내는 불리언 배열을 반환 setdiff1d(x, y) x와 y의 차집합을 반환 setxor1d(x, y) 한 배열에는 포함되지만 두 배열 모두에는 포함되지 않는 원소들의 집합인 대칭차집합을 반환 -
배열 재형성하기
배열의 모양을 변환하려면 배열의 인스턴스 메서드인 reshape 메서드에 새로운 모양을 나타내는 튜플을 넘기면 된다. reshape에 넘기는 값 중 하나가 -1이 될 수도 있는데 이 경우에는 원본 데이터를 참조해서 적절한 값을 추론하게 된다.
arr = np.arange(15) arr.reshape((5, -1)) >>> array([[ 0, 1, 2], [ 3, 4, 5], [ 6, 7, 8], [ 9, 10, 11], [12, 13, 14]])
다차원 배열을 낮은 차원으로 변환하는 것은 flattening, raveling라고 한다.
arr = np.arange(15).reshape((5, 3)) arr >>> array([[ 0, 1, 2], [ 3, 4, 5], [ 6, 7, 8], [ 9, 10, 11], [12, 13, 14]]) arr.ravel() # 원본 데이터의 복사본 생성 x >>> array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]) arr.flatten() # 원본 데이터의 복사본 생성 o >>> array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14])
-
배열 이어붙이고 나누기
-
numpy.cancatenate
arr1 = np.array([[1, 2, 3], [4, 5, 6]]) arr2 = np.array([[7, 8, 9], [10, 11, 12]]) np.concatenate([arr1, arr2], axis=0) >>> array([[ 1, 2, 3], [ 4, 5, 6], [ 7, 8, 9], [10, 11, 12]]) np.concatenate([arr1, arr2], axis=1) >>> array([[ 1, 2, 3, 7, 8, 9], [ 4, 5, 6, 10, 11, 12]])
-
vstack / hstack
np.vstack((arr1, arr2)) >>> array([[ 1, 2, 3], [ 4, 5, 6], [ 7, 8, 9], [10, 11, 12]]) np.hstack((arr1, arr2)) >>> array([[ 1, 2, 3, 7, 8, 9], [ 4, 5, 6, 10, 11, 12]])
-
split
arr = np.random.randn(5, 2) arr >>> array([[ 0.50979365, 0.71316992], [-0.41749511, 0.40273321], [ 0.5692544 , 0.05420052], [-0.59428463, 0.03749489], [ 1.09871856, -0.65844961]]) first, second, third = np.split(arr, [1, 3]) # [1, 3]은 나눌 때 기준이 되는 위치 first >>> array([[0.50979365, 0.71316992]]) second >>> array([[-0.41749511, 0.40273321], [ 0.5692544 , 0.05420052]]) third >>> array([[-0.59428463, 0.03749489], [ 1.09871856, -0.65844961]])
-
-
원소 반복하기
-
repeat
# 일차원 arr = np.arange(3) arr >>> array([0, 1, 2]) arr.repeat(3) >>> array([0, 0, 0, 1, 1, 1, 2, 2, 2]) arr.repeat([2, 3, 4]) # 원소마다 반복 횟수 다르게 지정 >>> array([0, 0, 1, 1, 1, 2, 2, 2, 2]) # 다차원 arr = np.random.randn(2, 2) arr >>> array([[ 0.74938208, -0.26172799], [-1.80225469, 0.50714339]]) arr.repeat([2, 3], axis = 0) >>> array([[ 0.74938208, -0.26172799], [ 0.74938208, -0.26172799], [-1.80225469, 0.50714339], [-1.80225469, 0.50714339], [-1.80225469, 0.50714339]])
-
tile : 타일을 이어붙이듯이 같은 내용의 배열을 이어붙인다.
np.tile(arr, 2) >>> array([[ 0.74938208, -0.26172799, 0.74938208, -0.26172799], [-1.80225469, 0.50714339, -1.80225469, 0.50714339]]) np.tile(arr, (2, 1)) # 두 번째 인자는 타일을 이어붙일 모양을 나타내는 튜플 >>> array([[ 0.74938208, -0.26172799], [-1.80225469, 0.50714339], [ 0.74938208, -0.26172799], [-1.80225469, 0.50714339]]) np.tile(arr, (3, 2)) >>> array([[ 0.74938208, -0.26172799, 0.74938208, -0.26172799], [-1.80225469, 0.50714339, -1.80225469, 0.50714339], [ 0.74938208, -0.26172799, 0.74938208, -0.26172799], [-1.80225469, 0.50714339, -1.80225469, 0.50714339], [ 0.74938208, -0.26172799, 0.74938208, -0.26172799], [-1.80225469, 0.50714339, -1.80225469, 0.50714339]])
-
-
브로드캐스팅
arr = np.random.randn(4, 3) arr.mean(0) >>> array([-0.48306577, -0.08000496, 0.25506222]) arr.mean(0).shape >>> (3,) demeaned = arr - arr.mean(0) # 브로드캐스팅 규칙에 어긋나지 않아서 에러 x arr.mean(1).shape >>> (4,) demeaned = arr - arr.mean(1) # 규칙에 어긋나서 에러 발생 >>> ValueError: operands could not be broadcast together with shapes (4,3) (4,) demeaned = arr - arr.mean(1).reshape(4, 1) # 열방향으로 계산하기 위해서 (4, 1)로 변형
※ 참고문헌 및 자료
- [ Python for Adata Analysis ]