[Numpy] Numpy의 제어
indexing & slicing#
python list의 indexing, slicing과 상당히 유사하다.
# indexing
arr = np.arange(10,20,1)
print(arr)
for item in arr:
print(item)
for idx,item in enumerate(arr):
print(idx, item)
# 2차원 ndarray의 indexing
arr = np.array([[1,2,3],
[4,5,6],
[7,8,9],
[10,11,12]])
print(arr)
print(arr[1,2])
print(arr[2,:]) # 1차원의 ndarray가 결과로 나와요(view)
print(arr[1:3,:])
# slicing
arr = np.arange(0,5,1)
print(arr)
tmp = arr[0:3]
print(tmp)
arr[0] = 100
print(arr)
print(tmp)
numpy의 ndarray에 대해서 slicing을 하면 view가 생성된다.
Boolean Indexing#
Boolean Indexing
은 배열의 각 요소의 선택여부를 True
,False
로 구성된 Boolean Mask
를 이용하여 지정하는 방식으로 Boolean Mask
안에서 True
로 지정된 요소만 indexing
하는 방식.
arr = np.arange(0,5,1)
print(arr)
print(arr[3]) # 3 기본 indexing
# [0 1 2 3 4 5 6 7 8 9]
b_mask = [True, False, False, False, False, True, False, False, True, True]
print(arr[b_mask]) # [0 5 8 9]
print(arr + 1)
# 만약 ndarray에 사칙연산이 수행되려면 shape이 같아야해요!
# 만약 연산을 할때 shape이 다르면 shape을 자동으로 맞출려고 해요!
arr2 = np.arange(10,13,1)
print(arr2)
print(arr + arr2)
print(arr + 1)
# [0 1 2 3 4]
# [1 1 1 1 1]
arr % 2 == 0
# [0 1 2 3 4]
# [2 2 2 2 2]
# [0 1 0 1 0]
# [0 0 0 0 0]
# [True, False, True, False, True]
arr[arr % 2 == 0]
# array([0, 2, 4])
# ex) 1부터 100까지 3의 배수의 개수는??
arr = np.arange(1,101,1)
print(len(arr[arr % 3 == 0])) # 33
Fancy Indexing#
ndarray에 index 배열(list, ndarray)을 전달해서 indexing하는 방식
arr = np.arange(10,15,1)
print(arr)
print(arr[1]) # 숫자 indexing(기본)
print(arr[[0, 2, 3]]) # index number로 구성된 list 즉, index list를 이용하여 indexing 작업을 하는 것
arr = np.arange(0,12,1).reshape(3,4).copy()
print(arr)
# indexing (기본)
print(arr[2,1])
print(arr[0:2,2]) # [6] 6
print(arr[1:2,2:3]) # [[6]]
print(arr[[0,2],2]) # [2 10]
print(arr[[0,2],2:3]) # [[2]
# [10]]
# print(arr[[0,2],[0,2]]) # numpy 구조상 fancy indexing을 두번 이상 사용할 수 없다
print(arr[np.ix_([0,2],[0,2])]) # 이렇게 작성해야 예상된 shape가 나온다. fancy indexing을 두번 사용하고 싶은 경우 np.ix_ 를 통해서 작업하자
# [[0 2]
# [8 10]]
print(arr[[0,2]][:,[0,2]]) # 혹은 이런식으로 행과 열을 나누어서 연산해도 가능하다
# [[ 0 2]
# [ 8 10]]
사칙연산과 행렬 곱#
arr1 = np.array([[1, 2, 3], [4, 5, 6]])
arr2 = np.arange(10, 16, 1).reshape(2, 3).copy()
print(arr1)
print(arr2)
# 같은 shape인 경우 연산 수행이 가능
print(arr1 + arr2)
a = [1, 2, 3]
b = [4, 5, 6]
print(a+b) # python의 list인 경우 concatenate
# 행렬곱연산 (matrix multiplication)
a = np.array([[1, 2], [3, 4], [5, 6]])
b = np.array([[1, 2, 3], [4, 5, 6]])
print(np.matmul(a, b))
Broadcasting#
arr1 = np.array([[1, 2, 3], [4, 5, 6]])
arr2 = np.array([1, 2, 3])
# arr1과 arr2에 대해서 사칙연산을 수행하고 싶어요
# shape가 같아야 연산을 수행할 수 있어요
print(arr1 + arr2) # OK
print(arr1 * 3) # scaler(단일 숫자)는 broadcasting이 쉬워요
# np.matmul 연산에서는 broadcasting이 발생하지 않아요
Numpy에서의 반복문을 위한 iterator#
1차원 Data면 그냥 사용하면 되지만, 2, 3차원에서는 많은 Data를 처리하기에는 문제가 발생한다. 그래서 ndarray에 대한 반복 처리를 할 때는 iterator
를 이용하는걸 권장한다. iternext()
와 finished
라는 속성을 이용하여 ndarray의 모든 요소를 반복적으로 access가 가능하다.
# 1차원 ndarray
arr = np.array([1, 2, 3, 4, 5])
# 일반적인 for문을 이용한 ndarray access
for tmp in arr:
print(tmp, end=' ')
# # iterator를 이용한 1차원 ndarray access
# # 지정된 flags의 형태를 가지는 iterator를 추출
it = np.nditer(arr, flags=['c_index']) # c_index = index의 형태가 c언어의 index형태와 같게 추출하세요 (일반적으로 사용함)
# arr[0] 형태이며 index를 가지고 있다
print(arr[it[0]])
while not it.finished:
idx = it.index
print(arr[idx], end=' ')
it.iternext()
# 2차원 이상 ndarray
arr = np.array([[1, 2, 3], [4, 5, 6]]) # shape = (2, 3)
for i in range(arr.shape[0]):
for j in range(arr.shape[1]):
print(arr[i, j], end=' ')
# 가능하긴함 다만, 차수에 따라... 지옥이 되겠지..
it = np.nditer(arr, flags=['multi_index'])
while not it.finished:
idx = it.multi_index # (0,0) 좌표처럼 나타남
print(arr[idx], end=' ')
it.iternext()
단일 차원이 고정된다면.. 단일 for문쓰는게 당연하지만, 동적으로 차수가 변경되거나, 다차원인 경우에는 이런 itorator를 사용하는 것이 훠어어어어얼씬 더 유익하다.
Ndarray에서 사용 가능한 여러 집계 함수#
arr = np.arange(1, 7, 1).reshape(2, 3).copy()
print(arr)
print(arr.sum()) # 모든 요소 총합 출력
print(np.sum(arr)) # 전자는 ndarray가 가지고 있는 자체 함수 호출과 numpy가 가지고 있는 기능을 호출
print(np.mean(arr)) # 모든 요소 평균 값
print(np.max(arr)) # 최대 값
print(np.min(arr)) # 최소 값
print(np.argmax(arr)) # 최대 값을 찾아서 그 값의 index를 return
print(np.std(arr)) # 표준편차
axis#
numpy의 모든 집계함수는 axis(축)를 기준으로 계산한다 위의 예처럼 axis를 명시하지 않으면 axis는 None을 설정되는데 이런 경우 집계함수의 대상은 전체 ndarray로 간주한다.
# 1차원 ndarray인 경우
arr = np.array([1, 2, 3, 4, 5])
print(arr.sum(axis=0)) # 1차원인 경우 축의 번호는 0이고 이때 0의 의미는 열(열방향)
# 2차원 ndarray인 경우
arr = np.array([[1, 2, 3], [4 ,5 ,6]])
print(arr.sum(axis=0)) # 2차원인 경우 축의 번호는 0과 1을 쓸 수 있고 0이 행, 1이 열
# 3차원
arr = np.array([[1, 2, 3], [4 ,5 ,6], [7, 8, 9]])
print(arr.argmax(axis=1)) # 행 방향으로 가장 큰 값의 index이기에 2, 2, 2 가 나온다
np.random.seed(1)
arr = np.random.randint(0, 5, (2, 2, 3))
print(arr)
print(arr.sum(axis=0))
중간에 간단한 문제 하나.#
랜덤으로 정수형 난수(1 ~ 10 모두 포함하여 12개)를 생성하여 3행 4열 2차원 ndarray로 만들고, 이 안에 있는 난수 중 5 이상인 숫자들의 합을 구해서 출력
np.random.seed(1)
arr = np.random.randint(1, 11, (3,4))
print(arr[arr >= 5].sum())
ndarray의 concatenate()#
Numpy 배열을 합치기 위한 함수이며 axis값을 조절하여 어떤 축을 기준으로 배열을 합칠 것인지 정할 수 있다.
arr = np.array([[1, 2, 3],
[4, 5, 6]])
tmp = np.array([7, 8, 9])
result = np.concatenate((arr,tmp.reshape(1,3)), axis=0)
print(result)
# [[1 2 3]
# [4 5 6]
# [7 8 9]]
arr = np.array([[1, 2, 3],
[4, 5, 6]])
tmp = np.array([7,8,9,10])
result = np.concatenate((arr,tmp.reshape(2,2)), axis=1)
print(result)
# [[ 1 2 3 7 8]
# [ 4 5 6 9 10]]
ndarray의 삭제 delete()#
np.random.seed(1)
arr = np.random.randint(0,10,(3,4))
print(arr)
# result = np.delete(arr,1) # 1번 index를 지울꺼예요!
# print(result)
result = np.delete(arr, 3, axis=1)
print(result)