코딩하는 타코야끼

[Numpy] 2강_배열 원소 조회 / 배열 형태 변경 본문

[T.I.L] : Today I Learned/Numpy

[Numpy] 2강_배열 원소 조회 / 배열 형태 변경

가스오부시 2023. 5. 19. 12:11
728x90
반응형

1. 인덱싱과 슬라이싱을 이용한 배열의 원소 조회 및 변경


📍 배열 인덱싱(Indexing)

  • index
    • 배열내의 원소의 식별번호
    • 0부터 시작
  • indexing
    • index를 이용해 원소 조회
    • [ ] 표기법 사용
  • 구문
    • ndarray[index]
    • 양수는 지정한 index의 값을 조회한다.
    • 음수는 뒤부터 조회한다.
      • 마지막 index가 -1
    • 2차원배열의 경우
      • arr[0축 index, 1축 index]
      • 파이썬 리스트와 차이점
    • N차원 배열의 경우
      • arr[0축 index, 1축 index, ..., n축 index]
  • 팬시(fancy) 인덱싱
    • 여러개의 원소를 한번에 조회할 경우 리스트에 담아 전달한다.
    • 다차원 배열의 경우 각 축별로 list로 지정
    •  arr[[1,2,3,4,5]]
      • 1차원 배열(vector): 1,2,3,4,5 번 index의 원소들 한번에 조회
    •   arr[[0,3], [1,4]]  
      • [0,3] - 1번축 index list, [1,4] - 2번축 index list
      • 2차원 배열(matrix): [0,1], [3,4] 의 원소들 조회
import numpy as np
a = np.arange(30)
a.shape
>>>
(30,)

🌓  1차원

🌓  2차원

🌓  3차원


📍 슬라이싱

  • 배열의 원소들을 범위로 조회한다.
  • ndarry[start : stop : step ]
    • start : 시작 인덱스. 기본값 0
    • stop : 끝 index. stop은 포함하지 않는다. 기본값 마지막 index
    • step : 증감 간격. 기본값 1

🌓  다차원 배열 슬라이싱

  • 각 축에 slicing 문법 적용
  • 2차원의 경우
    • arr [0축 slicing, 1축 slicing]
      •  arr[:3, :] 
    •  ,  로 축을 구분한 다중 슬라이싱 사용
  • 다차원의 경우
    • arr[0축 slicing, 1축 slicing, ..., n축 slicing]
  • slicing과 indexing 문법은 같이 쓸 수 있다.

🌓  슬라이싱은 원본에 대한 View

  • slicing한 결과는 새로운 배열을 생성하는 것이 아니라 기존 배열을 참조한다.
  • slicing한 배열의 원소를 변경하면 원본 배열의 것도 바뀐다.
  • 배열.copy()
    • 배열을 복사한 새로운 배열 생성
    • 복사후 처리하면 원본이 바뀌지 않는다.
a = np.range(30).reshape(5, 6)
a
>>>
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]])
a[:2, 1]
>>>
array([1, 7])
----------------------------------------------------------------
a[[1, -1], 1:5]
>>>
array([[ 7,  8,  9, 10],
       [25, 26, 27, 28]])
----------------------------------------------------------------
a[:, [0, 4]]
>>>
array([[ 0,  4],
       [ 6, 10],
       [12, 16],
       [18, 22],
       [24, 28]])
----------------------------------------------------------------
a[:3, 1:5]
>>>
array([[ 1,  2,  3,  4],
       [ 7,  8,  9, 10],
       [13, 14, 15, 16]])

📍 boolean indexing

  • Index 연산자에 같은 형태(shape)의 Boolean 배열을 넣으면 True인 index의 값만 조회 (False가 있는 index는 조회하지 않는다.)
  • ndarray내의 원소 중에서 원하는 조건의 값들만 조회할 때 사용
    • ndarray는 element-wise 연산을 지원한다. 이를 이용해 boolean indexing으로 원하는 조건의 값들을 조회할 수 있다.
  • boolean indexing을 masking이라고도 한다.

📍 넘파이 비교연산자

  • 파이썬의 and, or, not은 사용할 수 없다.
  •  & : and연산
  •  | : or 연산
  •  ~ : not 연산
  • 피연산자는  ( ) 로 묶어야 한다.
np.random.seed(0)
# 0 ~ 99 사이의 임의 정수 20개.
a = np.random.randint(100, size = 20)
a  
>>>
array([44, 47, 64, 67, 67,  9, 83, 21, 36, 87, 70, 88, 88, 12, 58, 65, 39,
       87, 46, 88])
# a 에서 50 이상인 값들만 조회
a[a > 50]   # 원소별로 연산
>>>
array([64, 67, 67, 83, 87, 70, 88, 88, 58, 65, 87, 88])
----------------------------------------------------------------
a[(a > 30) & (a < 60)]
>>>
array([44, 47, 36, 58, 39, 46])
----------------------------------------------------------------
a[(a < 30 | (a > 60))]
>>>
rray([ 9, 21, 12])
a2 = np.random.randint(100, size = (7, 8))
a2
>>>
array([[14, 99, 53, 12, 42, 84, 75, 68],
       [ 6, 68, 47,  3, 76, 52, 78, 15],
       [20, 99, 58, 23, 79, 13, 85, 48],
       [49, 69, 41, 35, 64, 95, 69, 94],
       [ 0, 50, 36, 34, 48, 93,  3, 98],
       [42, 77, 21, 73,  0, 10, 43, 58],
       [23, 59,  2, 98, 62, 35, 94, 67]]
----------------------------------------------------------------
a2[a2 > 60] # 결과는 1차원으로 반환.)
>>>
array([99, 84, 75, 68, 68, 76, 78, 99, 79, 85, 69, 64, 95, 69, 94, 93, 98,
       77, 73, 98, 62, 94, 67])

🌓  np.where( )

  • True의 index 조회
    • np.where(boolean 배열) - True인 index를 반환
      • 반환타입: Tuple . True인 index들을 담은 ndarray를 축별로 Tuple에 묶어서 반환한다.
    • boolean연산과 같이사용하여 배열내에 특정 조건을 만족하는 값들을 index(위치)를 조회할 때 사용한다.
  • True와 False를 다른 값으로 변환
    • np.where(boolean 배열, True를 대체할 값, False를 대체할 값)
      • 배열내의 True를 True를 대체할 값으로 False를 False를 대체할 값 으로 변환한다.
r = np.where([True, False, False])
print(type(r), type(r[0]))
r
>>> 
<class 'tuple'> <class 'numpy.ndarray'>
(array([0]),)
----------------------------------------------------------------
r = np.where([True, False, False], "참", "거짓")
r
>>>
array(['참', '거짓', '거짓'], dtype='<U2')
----------------------------------------------------------------
l = [[True, False, True], [False, False, True]]
r3 = np.where(l)
r3  # [0,0], [0,2], [1, 2]
>>>
(array([0, 0, 1]), array([0, 2, 2]))
----------------------------------------------------------------
np.random.seed(0)
r1 = np.random.randint(100, size = (5, 2, 3))
r1.shape
>>>
(5, 2, 3)
r1
>>>
array([[[44, 47, 64],
        [67, 67,  9]],

       [[83, 21, 36],
        [87, 70, 88]],

       [[88, 12, 58],
        [65, 39, 87]],

       [[46, 88, 81],
        [37, 25, 77]],

       [[72,  9, 20],
        [80, 69, 79]]])
axis1, axis2, axis3 = np.where(r1 >= 70)
print(axis1)
print(axis2)
print(axis3)
# [1, 0, 0], [1, 1, 0], [1, 1, 1], [1, 1, 2]....
>>>
[1 1 1 1 2 2 3 3 3 4 4 4]
[0 1 1 1 0 1 0 0 1 0 1 1]
[0 0 1 2 0 2 1 2 2 0 0 2]
----------------------------------------------------------------
for i, j, k in zip(axis1, axis2, axis3):
    print(r1[1, j, k], end = ", ")
>>>
83, 87, 70, 88, 83, 88, 21, 36, 88, 83, 87, 88,

🌓  기타

  • np.any(boolean 배열)
    • 배열에 True가 하나라도 있으면 True 반환
    • 배열내에 특정조건을 만족하는 값이 하나 이상 있는지 확인할 때 사용
  • np.all(boolean 배열)
    • 배열의 모든 원소가 True이면 True 반환
    • 배열내의 모든 원소가 특정 조건을 만족하는지 확인 할 때 사용\
np.any([True, False, False, False])
np.any([False, False, False, False])
>>>
False
----------------------------------------------------------------
np.any(a2 == 99)
np.any(a2 == 83)
>>>
False
----------------------------------------------------------------
np.all([True, True, False])
np.all([True, True, True])
>>>
True
----------------------------------------------------------------
np.all(a2 > 0)
np.all(a2 > 10)
>>>
False

2. 배열의 형태(shape) 변경

  • 배열의 원소의 개수를 유지하는 상태에서 shape을 변경할 수있다.
    • 예) (16, ) -> (4,4) -> (2,2,4) -> (2,2,2,2), -> (4,4,1) -> (1, 16)

📍 reshape( )을 이용한 차원 변경

  •  numpy.reshape(a, newshape)  또는  ndarray.reshape(newshape) 
    • a: 형태를 변경할 배열
    • newshape : 변경할 형태 설정.
      • 원소의 개수를 유지하는 shape으로만 변환 가능하다.
      • 각 axis(축)의 size를 지정할 때 하나의 축의 size를 -1로 줄 수있다. 그러면  전체 size / 다른 축의 size곱  을 -1로 지정한 axis 의 size로 지정한다.
    • 둘다 원본을 바꾸지 않고 reshape한 새로운 배열을 만들어 반환한다.
a = np.arange(20)
print(a.shape)
a
>>>
(20,)
array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16,
       17, 18, 19])
r1 = np.reshape(a, (2, 10))
print(r1.shape)
r1
>>>
(2, 10)
array([[ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9],
       [10, 11, 12, 13, 14, 15, 16, 17, 18, 19]])
r3 = a.reshape(2, 2, -1)
print(r3.shape)
r3
>>>
(2, 2, 5)
array([[[ 0,  1,  2,  3,  4],
        [ 5,  6,  7,  8,  9]],

       [[10, 11, 12, 13, 14],
        [15, 16, 17, 18, 19]]])

📍 차원 늘리기(확장)

  • Dummy axis(축)을 늘린다.

  • reshape() 을 이용해 늘릴 수 있다.
  • indexer와 np.newaxis 변수를 이용해 늘린다.
    • ndarray[..., np.newaxis] 또는 ndarray[np.newaxis, ...]
      • 맨앞 또는 맨 마지막에 dummy axis(축)을 늘릴때 사용한다.
      • 축을 늘리려는 위치에 np.newaxis를 지정하고  ...  으로 원본 배열의 shape을 유지함을 알려준다.
a.shape
# (20, 1)
r1 = a.reshape(20, 1)
r1 = a.reshape(-1, 1)
# (1, 20)
r1 = a.reshape(1, -1)
r1.shape
>>>
(1, 20)
a2.shape # 다차원
r2 = a2.reshape(1, 5, 2, 3)
r2.shape
>>>
(1, 5, 2, 3)
----------------------------------------------------------------
a = a.reshape(20,)
a.shape
>>>
(20,)
a[..., np.newaxis].shape
>>>
(20, 1)
----------------------------------------------------------------
a[np.newaxis, ...].shape
>>>
(1, 20)
# a2의 1축에 dummy axis를 추가.
r3 = np.expand_dims(a, axis = 1) # (20,) -> (20, 1)
r3 = np.expand_dims(a, axis = 0) # (20,) -> (1, 20)
r3 = np.expand_dims(a, axis = -1) # (20,) -> (20, 1)

📍 차원 줄이기(축소)

🌓  numpy.squeeze(배열, axis=None), 배열객체.squeeze(axis=None)

  • 배열에서 지정한 축(axis)을 제거하여 차원(rank)를 줄인다.
  • 제거하려는 축의 size는 1이어야 한다.
  • 축을 지정하지 않으면 size가 1인 모든 축을 제거한다.
    • (3,1,1,2) => (3,2)
a = np.arange(12).reshape(1, 2, 1, 2, 3, 1)
a.shape
>>>
(1, 2, 1, 2, 3, 1)
# reshape한 새로운 배열을 생성해서 반환. 
r1 = a.squeeze() # size가 1인 모든 축을 제거한다.
r1.shape
>>>
(2, 2, 3)
r2 = a.squeeze(axis = 2)
r2.shape
>>>
(1, 2, 2, 3, 1)

🌓  배열객체.flatten( )

  • 다차원 배열을 1차원으로 만든다.
a.shape
(5, 6)
----------------------------------------------------------------
r = a.flatten()
r.shape
>>>
(30,)
반응형