[Python] Numpy-2
Numpy -2
오늘은 numpy 에 대하여 조금 더 알아보도록 하겠습니다.
Reshape vs Resize
numpy 내장 함수인 reshape
와 resize
에 대하여 알아보겠습니다. reshape
와 resize
는 행렬의 array를 shape을 변경하는 점에서 동일하나 차이점이 한가지가 있습니다.
reshape
이전의 행렬의 인자의 개수와 변경될 인자의 개수가 동일해야만 사용할 수 있습니다.
하지만 resize
경우에는 상관없이 사용가능합니다. 이전에 비해 인자가 부족할 경우 나머지 요소를 0으로 채우고, 남는경우에는 필요한 요소를 제외하고는 전부다 버려 행렬을 완성합니다.
하기 예제를 보며 차이점을 알아보도록 하겠습니다.
import numpy as np
#정수형태의 난수를 이용해서 (3,4) shape을 가지는 ndarray를 생성할 꺼에요!
np.random.seed(10)
arr = np.random.randint(0,10,(3,4))
print(arr)
result = arr.resize(2,6) # 원본을 변경
print(result) # None
print(arr)
arr.resize(3,5)
# reshape은 안됨 error 하지만 resize는 나머지 요소를 0으로 맞춤
print(arr)
arr.resize(2,2)
# 요소수가 줄면 나머지데이터를 버립니다.
print(arr)
Indexing & Slicing
Indexing
과 Slicing
모두 List 혹은 문자열에서 많이 사용하였습니다. 하지만 Numpy
에서도 비슷하게 사용할 수 있습니다.
자세한 내용은 하기 코드를 보면서 익혀보도록 하겠습니다.
Indexing
import numpy as np
arr = np.arange(10,20,1)
print(arr)
ndarray의 각요소를 축력하려면 어떻게 해야하나요?
for tmp in arr:
print(tmp)
for (idx, tmp) in enumerate(arr):
print('인덱스 : {}, 데이터 : {}'.format(idx, tmp))
'''
인덱스 : 0, 데이터 : 10
인덱스 : 1, 데이터 : 11
인덱스 : 2, 데이터 : 12
인덱스 : 3, 데이터 : 13
인덱스 : 4, 데이터 : 14
인덱스 : 5, 데이터 : 15
인덱스 : 6, 데이터 : 16
인덱스 : 7, 데이터 : 17
인덱스 : 8, 데이터 : 18
인덱스 : 9, 데이터 : 19
'''
Slicing
arr = np.arange(10,20,1)
print(arr[3]) # 13
print(arr[1:4]) # slicing은 원본의 형태를 그대로 가져옴
print(arr[:-1]) #[10 11 12 13 14 15 16 17 18]
print(arr[1:-1:2]) #[11 13 15 17] ,없이 표현
arr = np.arange(1,17,1).reshape(4,4).copy()
print(arr)
'''
[[ 1 2 3 4]
[ 5 6 7 8]
[ 9 10 11 12]
[13 14 15 16]]
'''
print(arr[1,2]) # 7
print(arr[1][2]) # 7
print(arr[2,:]) #[ 9 10 11 12]
print(arr[1:3,:])
'''
[[ 5 6 7 8]
[ 9 10 11 12]]
'''
print(arr[1:3,:2])
'''
[[ 5 6]
[ 9 10]]
'''
Boolean indexing & Fancy indexing
Numpy에는 특수한 indexing 방식이 있습니다. Boolean indexing
과 Fancy indexing
입니다.
먼저 Boolean indexing
부터 알아보도록 하겠습니다.
Boolean indexing
True, False로 구성된 Boolean mask를 이용하여 지정하는 방식입니다. boolean mask의 True에 해당하는 index 만을 조회하는 방식으로도 활용이 가능합니다. 즉 boolean indexing은 ndarray의 각 요소의 선택여부를 결정할 수 있습니다.
예제를 통하여 알아보도록 하겠습니다.
import numpy as np
np.random.seed(1)
arr = np.random.randint(0,10,(5,))
print(arr) # [5 8 9 5 0]
print(arr % 2) # [1 0 1 1 0]
print(arr % 2 == 0) # [False True False False True] => boolean mask
print(arr[arr % 2 == 0]) # [8 0] => boolean indexing
Fancy indexing
ndarray에 index배열을 전달하여 배열요소를 참조하는 방식입니다.
예제를 통하여 알아보도록 하겠습니다.
import numpy as np
arr = np.arange(0,12,1).reshape(3,4).copy()
print(arr)
print(arr[2,2]) # indexing : 10
print(arr[1:2, 2]) # slicing : [6]
print(arr[1:2, 1:2]) # slicing : [[5]] => 차원 주의 !!
print(arr[[0,2],2]) # [ 2 10]
print(arr[[0,2],2:3])
'''
[[ 2]
[10]]
'''
# 그렇다면 우리 다음의 2차원 ndarray를 추출해 보아요!!
'''
[[1 3]
[9 11]]
'''
print(arr[[0,2],[1,3]]) #[ 1 11] 행과 열에 동시에 fancy indexing을 할수가 없어요 !
# 해결방법 1
print(arr[[0,2]][:,[1,3]])
'''
[[1 3]
[9 11]]
'''
# 해결방법 2 - numpy 가 함수를 하나 제공해줘요!
print(arr[np.ix_([0,2],[1,3])])
'''
[[1 3]
[9 11]]
'''
ndarray의 사칙연산과 행렬곱
행렬도 행렬간의 덧셈, 뺄쎔, 나눗셈, 곱셈, 그리고 행렬곱을 실시할 수 있습니다.
행렬곱은 numpy에세 제공하는 dot product를 사용하여 쉽게 구할 수 있습니다.
예제를 통하여 알아보도록 하겠습니다.
import numpy as np
arr1 = np.array([[1,2,3],[4,5,6]])
arr2 = np.array([[7,8,9],[10,11,12]])
# python에서 list 할때.. + 얀산자는 concatenation!!
# ndarray에서 연산자는 vector, matrix연산..
# ndarray의 사칙연산의 기본 전제는.. shape이 같아야 연산이 성립
print(arr1 + arr2)
'''
[[ 8 10 12]
[14 16 18]]
'''
arr2 = 3
print(arr1 + arr2) # 수행이 되요 !! => ndarray가 broadcatin 을 수행
# shape 이 맞지않는 경우 ndarray 가 broadcating을 수행
# arr2 = [[3 3 3]
# [3 3 3]]
arr2 = np.array([1,2,3])
print(arr1 + arr2)
'''
[[2 4 6]
[5 7 9]]
'''
arr2 = np.array([1,2]) # shape을 맞출수가 없음 => 1,2,1,2 이런식으로 복제가 실행되기 떄문에
print(arr1 + arr2) # error
arr1 = np.array([[1,2,3],[4,5,6]])
arr2 = np.array([[7,8,9],[10,11,12]])
## 행렬곱 연산!!
print(arr1 * arr2) # 단순 곱셈만 실행
'''
[[ 7 16 27]
[40 55 72]]
'''
# 두 행렬간의 행렬곱은 np.dot(), np.matmul()로 수행이 가능해요!!
# np.dot(A, B)에서 A행렬의 열 vector와 B행렬의 행 Vector의 size가 같아야 해요!
# 만약 크기가 다르면 reshape() 이나 resize()나
# 이런것들을 이용해서 크기를 맞추고 연산을 수행해야 해요!!
arr1 = np.array([[1,2,3],[4,5,6]])
arr2 = np.array([[7,8],[9,10],[11,12]])
print(np.dot(arr1, arr2))
# 왜 이런 행렬곱 연산을 알아야 하나요??
# 만약에 행렬곱이 없으면 Matrix 연산은 같은 크기로만 연산을 수행해야 해요!!
# 하지만 행렬곱 연산을 이용하면
# 행렬곱 조건만 만족시키면 다양한 크기의 행렬을 우리가 연속적으로
# 이용해서 특정 작업을 수행할 수 있어요 !!
# 머신러닝, 이미지처리쪽에서 사용되요!!
# 예) 입력 : 32 X 32 matrix (이미지파일)
# 출력 : 32 X 10 matrix (다양한 처리가 적용된 이미지)
# 행렬곱 : (32 X 32) dot(32 X 128) dot (128 X 64) dot (64 X 10 ) = (32 X 10)
Transpose
Transpose (전체행렬)
에 대하여 알아보도록 하겠습니다. 전치행렬은 행과 열을 바꾼 행렬을 의미하며 윗첨자로 T를 사용합니다.
예제를 통하여 알아보도록 하겠습니다.
import numpy as np
arr = np.array([[1,2,3],[4,5,6]]) # 2 X 3 ndarray
print(arr)
t_arr = arr.T
print(t_arr)
arr[0,0] = 100
print(arr)
print(t_arr)
arr = np.array([1,2,3,4]) # vector (1차원 ndarray)
t_array = arr.T.reshape(4,1)
print(t_array)
Numpy iterator
iterator 의 동작방식입니다. 간단하게 행렬의 요소들을 출력하는 방식이라고 생각하시면 되겠습니다.
For VS iterator
import numpy as np
arr = np.array([1,2,3,4,5])
# for문을 이용하면 편해요!!
for tmp in arr:
print(tmp, end=' ') # 1 2 3 4 5
# 일단은 불편하지만 이 작업을 iterator를 이용해서 구현해보겠습니다.
# 각각의 칸을 지칭하는 것이 iterator
arr = np.array([1,2,3,4,5])
it = np.nditer(arr, flags=['c_index']) # flags 1차원인경우 'c_index'
while not it.finished: # iterator 가 지정하는 위치가 끝이 아닐동안 반복
idx = it.index # iterator가 현재 가리키는 곳의 index숫자를 가져와요!
print(arr[idx], end=' ')
it.iternext() # iterator를 다음요소로 이동시키는 작업을 해요 !!
################
# 2차원 ndarray에 대해서 각 요소를 순서대로 출력해보아요!!
# 요소를 순서대로 출력 => 0행0열 > 0행1열 > 0행2열 > 1행0열 > 1행1열 > 1행2열
arr = np.array([[1,2,3],[4,5,6]])
print(arr)
# 요소를 하나씩 뽑아서 순서대로 출력해보세요!!
for i in arr:
for x in i:
print(x, end=' ')
for row in range(arr.shape(0)):
for col in range(arr.shape(1)):
print(arr[row,col], end=' ')
it = np.nditer(arr, flags=['multi_index']) # flags 1차원인경우 'c_index'
while not it.finished:
idx = it.multi_index
print(arr[idx], end=' ')
it.iternext()
ndarray 비교연산
사칙연산과 마찬가지로 비교연산도 같은 index끼리 수행됩니다.
np.random.seed(0)
arr1 = np.random. randint(0,10,(2,3))
arr2 = np.random. randint(0,10,(2,3))
print(arr1)
print(arr2)
print(arr1 == arr2) # boolena 형 마스크
arr1 = np.arange(10)
arr2 = np.arange(10)
print(np.array_equal(arr1, arr2)) # True False 로 표현
Numpy 집계함수 & axis (축)
import numpy as np
arr = np.arange(1,7,1).reshape(2,3).copy()
print(arr)
print(arr.sum())
print(np.sum(arr))
print (np.cumsum(arr)) #누적합 #피보나치
print(np.mean(arr)) # 평균
print(np.max(arr)) # 최대값
print(np.min(arr)) # 최소값
print(np.argmax(arr)) # 최대값을 찾고 최대값의 index를 반환 순번으로 나타냄
print(np.argmin(arr)) # 최대값을 찾고 최소값의 index를 반환 순번으로 나타냄
print(np.std(arr)) # 표준편차 1.707825127659933
print(np.exp(arr)) # 자연상수 제곱
print(np.log10(arr)) # 로그
#이런 수많은 numpy의 집게함수와 수학함수가 우리에게 제공되요 !!
#Numpy의 모든 집계함수는 axis를 기준으로 계산되요!!
# np.sum()
# 만약 axis를 지정하지 않으면.. axis는 None으로 설정되고..
# 함수의 대상범위를 전체 ndarray로 지정하게 되요!
# axis를 어떻게 설정하고 어떤 효과가 나타나나요??
# 1차원 ndarray를 생성.
arr = np.array([1,2,3,4,5])
print(np.sum(arr)) # axis를 지정하지 않았기 떄문에 전체 ndarray를 대상으로 sum()수행
# 1차원은 축이 1개, 2차원은 축이 2개, 3차원은 축이 3개존재
# 1차원인 경우 axis = 0 열방향 !! 가로방향!!
# print(arr.sum(axis=0))
# print(arr.sum(axis=1)) # error
# 2차원 ndarray를 생성.
arr = np.array([[1,2,3],[4,5,6]])
print(arr.sum(axis=0)) #2차원에서 axis=0 이면 행방향!! > 세로방향 [5 7 9]
print(arr.sum(axis=1)) #2차원에서 axis=0 이면 열방향!! > 가로방향 [6 15]
print(arr.argmax(axis=1)) #2차원에서 axis=0 이면 열방향!! > 가로방향 [6 15]
np.random.seed(1)
arr1 = np.random.randint(0,10,(2,2,3))
print (arr1)
print(arr1.sum(axis=0))
# 3차원에서 axis=0은 => depth방향
# 3차원에서 axis=1은 => 행 / 세로방향
# 3차원에서 axis=2은 => 열 / 가로방향
집계함수를 사용해야하는 이유!
처리하는 시간 및 메모리 사용이 적어지는 이유가 가장 큽니다. 앞서 본대로 정답을 구하는 방식은 여러가지가 있습니다. 다만 처리하는 시간 및 사용하는 메모리가 한정될 경우 최적의 경로를 통하여 코드를 작성해야하는데 집계함수를 이용하면 최대한 시간 및 메모리를 절약할 수 있습니다.
%% time
을 사용해서 소요시간비교를 해보도록 하겠습니다. %% time
은 jupyter notebook에서만 사용가능합니다.
for 문
%%time
# for 문을 이용해서 합을 구하거나
arr = np.arange(100000, dtype = np.float64)
result = 0
for tmp in arr:
result += tmp
print(result)
# 4999950000.0
# CPU times: user 28.6 ms, sys: 1.27 ms, total: 29.9 ms
# Wall time: 29.1 ms
집계함수
%%time
# 집계함수를 이용해서 구할 수 있어요!!
arr = np.arange(100000, dtype = np.float64)
print(arr.sum())
# 4999950000.0
# CPU times: user 485 µs, sys: 219 µs, total: 704 µs
# Wall time: 379 µs
ndarray 정렬
numpy array는 axis를 기준으로 정렬하는 sort()함수를 제공합니다. 만약 axis를 지정하지 않으면 -1값으로 지정하며 마지막 axis를 지정합니다.
정렬하는 방법은 두 가지 방법이 있습니다.
- np.sort() : 정렬된 결과 ndarray를 리턴
- arr.sort() : 원본을 정렬 return값은 None
import numpy as np
arr = np.arange(10)
arr = np.arange(10)
arr2 = arr.sort()
arr3 = np.sort(arr)
print(arr2) # None
print(arr3) # [0 1 2 3 4 5 6 7 8 9]
print(arr)
np.random.shuffle(arr)
print(arr)
print(np.sort(arr)) #오름 차순으로 정렬 (default 가 오름차순)
# ndarray는 특수한 indexing 을 제공 > 역순으로 정렬하기 위한 indexing 을 제공
print(np.sort(arr)[::-1])
arr = np.arange(1,17)
np.random.shuffle(arr)
arr = arr.reshape(4,4).copy()
print(arr)
'''
[[ 4 13 7 6]
[10 2 5 11]
[12 3 8 1]
[14 16 15 9]]
'''
print(np.sort(arr, axis = 0))
'''
[[ 4 2 5 1]
[10 3 7 6]
[12 13 8 9]
[14 16 15 11]]
'''
print(np.sort(arr, axis = 1))
'''
[[ 3 7 10 14]
[ 4 5 12 13]
[ 1 2 6 16]
[ 8 9 11 15]]
'''
ndarray 행렬 추가 및 제거
오늘은 행렬의 요소를 추가 및 제거하는concatenate
와 delete
에 대하여 알아보겠습니다.
예제를 보면서 쉽게 이해해보도록 하겠습니다.
concatenate()
#ndarray에 row(s) 혹은 column(s)을 추가하기 위한 함수
#concatenate()
import numpy as np
arr = np.array([[1,2,3],[4,5,6]]) # 2X3 ndarray
new_row = np.array([7,8,9])
# arr에 new_row vector를 하단에 붙일거에요!!
# 결과적으로 3 X 3 matrix를 생성할꺼에요!!
# matrix끼리만 서로 붙습니다.
# result = np.concatenate(어떤것을 서로 붙일지 , 행으로 붙일지 열로 붙일지..)
result = np.concatenate((arr, new_row.reshape(1,3)) , axis = 0)
print(result)
'''
[[1 2 3]
[4 5 6]
[7 8 9]]
'''
delete()
# delete() 함수
# axis를 기준으로 행과 열을 삭제할 수 있어요 !!
# 만약 axis를 지정하지 않으면 1차원 배열로 변환 후 삭제
# 원본은 변경하지 않고 처리가 된 새로운 배열을 return
import numpy as np
np.random.seed(1)
arr = np.random.randint(0, 10, (3,4))
print(arr)
'''
[[5 8 9 5]
[0 0 1 7]
[6 9 2 4]]
'''
result = np.delete(arr, 1)
# axis가 설정되지 않았기 때문에 1차배열고 자동 변경된후 인덱스를 삭제
print(result) #[5 9 5 0 0 1 7 6 9 2 4]
result = np.delete(arr, 1, axis = 0)
print(result)
'''
[[5 8 9 5]
[6 9 2 4]]
'''
오늘은 Numpy
에 대하여 자세하게 알아보았습니다. 질문이 있으시면 아래 댓글에 남겨주세요!
Leave a comment