AI(ML & DL)

[기계학습] Python NumPy 란 ?? ( 3 )

ch010104 2025. 3. 28. 15:36

1️⃣ Iterating( ndarray 반복 )

 c = np.arange(24).reshape(2, 3, 4)  # A 3D array (composed of two 3x4 matrices)
 c
 
 # [[[ 0,  1,  2,  3],
 #   [ 4,  5,  6,  7],
 #   [ 8,  9, 10, 11]],
  
 #  [[12, 13, 14, 15],
 #   [16, 17, 18, 19],
 #   [20, 21, 22, 23]]]

# 다차원 배열의 반복
for m in c:
	print("Item:")
    print(m)  # 3x4 배열 2개 출력
    
 # Item:   
 # [[ 0  1  2  3]
 #  [ 4  5  6  7]
 #  [ 8  9 10 11]]
 # Item:
 # [[12 13 14 15]
 #  [16 17 18 19]
 #  [20 21 22 23]]    
    
# 인덱스 반복    
for i in range(len(c)):  # Note that len(c) == c.shape[0]
	print("Item:")
    print(c[i])

 # Item:   
 # [[ 0  1  2  3]
 #  [ 4  5  6  7]
 #  [ 8  9 10 11]]
 # Item:
 # [[12 13 14 15]
 #  [16 17 18 19]
 #  [20 21 22 23]] 

# 모든 요소 순회
for i in c.flat: # c.flat: 3차원 배열을 1차원 배열로 변환
    print(i)  # 모든 요소 0~23 출력
    
# Item: 0
# Item: 1
# Item: 2
# Item: .
# Item: .
# Item: .
# Item: 23
  • for m in c: 의 경우, 배열 c에 대해서 가장 바깥쪽 차원(3차원일 경우 z, 2차원일 경우 y)을 기준으로 m[0], ... 이 반환됨.
    - 위의 예시는 3차원이기 때문에 z축, 즉 axis 0 을 기준으로 쪼개서 반환됨.

  • for i in range(len(c)): 의 경우, len(c) 값 2는, c.shape[0] 과 같기 때문에 for i in range(c.shape[0]): 과 동일.
    - c.shape = (2, 3, 4) 이기 때문에 c.shape[0] = 2, c.shape[1] = 3, c.shape[2] = 4 임.
    - 따라서, 위의 예시는 z축 방향으로 순회하여 반환하는 것
    - 인덱스 반복 방식으로 y축 방향으로 짜르게 위해서 이런 방식을 사용.
for i in range(c.shape[1]):
    print("Item:")
    print(c[:, i, :])
    
# Item:
# [[ 0  1  2  3]
#  [12 13 14 15]]

# Item:
# [[ 4  5  6  7]
#  [16 17 18 19]]

# Item:
# [[ 8  9 10 11]
#  [20 21 22 23]]

2️⃣ 배열 쌓기 (Stacking Arrays)

q1 = np.full((3, 4), 1.0)
q2 = np.full((4, 4), 2.0)
q3 = np.full((3, 4), 3.0)

# q1 (3, 4)
# [[1. 1. 1. 1.]
#  [1. 1. 1. 1.]
#  [1. 1. 1. 1.]]

# q2 (4, 4)
# [[2. 2. 2. 2.]
#  [2. 2. 2. 2.]
#  [2. 2. 2. 2.]
#  [2. 2. 2. 2.]]

# q3 (3, 4)
# [[3. 3. 3. 3.]
#  [3. 3. 3. 3.]
#  [3. 3. 3. 3.]]

 

vstack

q4 = np.vstack((q1, q2, q3))
print(q4.shape)
print(q4)

# (10, 4)
# [[1. 1. 1. 1.]
#  [1. 1. 1. 1.]
#  [1. 1. 1. 1.]
#  [2. 2. 2. 2.]
#  [2. 2. 2. 2.]
#  [2. 2. 2. 2.]
#  [2. 2. 2. 2.]
#  [3. 3. 3. 3.]
#  [3. 3. 3. 3.]
#  [3. 3. 3. 3.]]
  • vstack은 매개변수로 들어온 배열 q1, q2, q3 를 y축 새로 방향으로 합침.(2차원 배열에 대해서만 가능)
  • 때문에 합쳐지는 배열들의 x축의 길이가 모두 같아야 함. (q1, q2, q3 는 x축의 길이가 4로 모두 같음)
  • x축의 길이가 다른 배열을 vstack하려고 하면 오류가 발생
  • vstack은 copy 방식이기 때문에, q1, q2, q3와 메모리를 공유하지 않음(q1, q2, q3가 바뀌어도 q4는 반영 x)

hstack

q5 = np.hstack((q1, q3))
print(q5.shape)
print(q5)

# (3, 8)
# [[1. 1. 1. 1. 3. 3. 3. 3.]
#  [1. 1. 1. 1. 3. 3. 3. 3.]
#  [1. 1. 1. 1. 3. 3. 3. 3.]]
  • hstack은 매개변수로 들어온 배열 q1, q3 를 x축 새로 방향으로 합침. (2차원 배열에 대해서만 가능)
  • 때문에 합쳐지는 배열들의 y축의 길이가 모두 같아야 함. (q1, q3 는 y축의 길이가 3으로 모두 같음)
  • y축의 길이가 다른 배열을 hstack하려고 하면 오류가 발생
  • hstack은 copy 방식이기 때문에, q1, q3와 메모리를 공유하지 않음(q1, q3가 바뀌어도 q5는 반영 x)

concatenate

q7 = np.concatenate((q1, q2, q3), axis=0) # np.vstack(q1, q2, q3)과 동일
print(q7.shape)
print(q7)

# (10, 4)
# [[1. 1. 1. 1.]
#  [1. 1. 1. 1.]
#  [1. 1. 1. 1.]
#  [2. 2. 2. 2.]
#  [2. 2. 2. 2.]
#  [2. 2. 2. 2.]
#  [2. 2. 2. 2.]
#  [3. 3. 3. 3.]
#  [3. 3. 3. 3.]
#  [3. 3. 3. 3.]]

# 실습 문제 
# concatenate 함수를 사용해서 ndarray q1과 q3을 수평 방향으로 붙이기

q_con = np.concatenate((q1, q3), axis=1) # np.hstack(q1, q3)과 동일
print(q_con.shape)
print(q_con)

# (3, 8) 
# [[1. 1. 1. 1. 3. 3. 3. 3.]
#  [1. 1. 1. 1. 3. 3. 3. 3.]
#  [1. 1. 1. 1. 3. 3. 3. 3.]]
  • concatenate는 매개변수로 들어온 배열 q1, ,q2, q3 을 주어진 축에 합침. (모든 차원에 대해서 가능)
  • q1, q2, q3이 2차원 배열이기 때문에, axis=0은 y축임. -> (np.vstack(q1, q2, q3) 와 기능이 같음)
  • 때문에 합쳐지는 배열들의 조건이 vstack이나 hstack의 조건이 만족해야함
  • 조건이 맞지 않으면 오류 발생
  • concatenate는 vstack과 hstack과 같은 기능을 하기 때문에, 메모리 공유 x

 

stack

q8 = np.stack((q1, q3)) # 새로운 축 z를 만들면서 q1, q3를 합치면서 q8를 생성
print(q8.shape)
print(q8)

# (2, 3, 4)
# [[[1. 1. 1. 1.]
#   [1. 1. 1. 1.]
#   [1. 1. 1. 1.]]
#
#  [[3. 3. 3. 3.]
#   [3. 3. 3. 3.]
#   [3. 3. 3. 3.]]]
  • q1, q3이 2차원 배열이기 때문에 stack 시에 z축을 만들면서 3차원 배열 q8을 생성
  • z축의 0번째 인덱스에 q1, 1번째 인덱스에 q3이 들어가 합쳐짐
  • 합쳐지는 배열 q1, q3의 shape이 완전히 일치해야지만 stack 가능
  • 배열의 shape가 다를 경우 오류 발생
  • stack은 copy 방식이기 때문에, q1, q3와 메모리를 공유하지 않음(q1, q3가 바뀌어도 q8는 반영 x)

3️⃣ 배열 분할( Splitting arrays )

 r = np.arange(24).reshape(2, 3, 4)
 r
 
 # [[[ 0,  1,  2,  3],
 #   [ 4,  5,  6,  7],
 #   [ 8,  9, 10, 11]],
  
 #  [[12, 13, 14, 15],
 #   [16, 17, 18, 19],
 #   [20, 21, 22, 23]]]

 

vsplit & hsplit

r1, r2, r3 = np.vsplit(r, 3)

r4, r5 = np.hsplit(r, 2)

# r1
# [[0, 1, 2, 3], 
#  [4, 5, 6, 7]]
# r2
# [[ 8,  9, 10, 11], 
#  [12, 13, 14, 15]]
# r3
# [[16, 17, 18, 19], 
#  [20, 21, 22, 23]]

# r4 
# [[ 0,  1], 
#  [ 4,  5], 
#  [ 8,  9], 
#  [12, 13], 
#  [16, 17], 
#  [20, 21]]
# r5
# [[ 2,  3], 
#  [ 6,  7], 
#  [10, 11], 
#  [14, 15],
#  [18, 19],
#  [22, 23]]
  • vsplit과 hsplit은 vstack과 hstack과 반대로 하나의 배열을 쪼개는 것

  • vsplit은 y축 방향으로 매개변수로 주어진 크기만큼으로 n등분 쪼개는것! 
  • r1, r2, r3 = np.vsplit(r, 3) 이면 r을 y축 방향으로 3등분해서 r1, r2, r3에 저장.

  • hsplit은 x축 방향으로 매개변수로 주어진 크기만큼으로 n등분 쪼개는것! 
  • r4, r5 = np.hsplit(r, 2) 이면 r을 x축 방향으로23등분해서 r3, r4에 저장.

4️⃣ 전치 ( Transposing arrays )

 t = np.arange(24).reshape(4, 2, 3)
 t
 
# [[[ 0,  1,  2],
#  [ 3,  4,  5]],
#
#  [[ 6,  7,  8],
#  [ 9, 10, 11]],
#
#  [[12, 13, 14],
#  [15, 16, 17]],
#
#  [[18, 19, 20],
#  [21, 22, 23]]]

 

transpose & swapaxes

# t는 (4, 2, 3) -> (z, y, x) 이기 때문에 z(0) = 4, y(1) = 2, x(2) =3 임
# transpose는 (0, 1, 2) 의 배열을 매개변수로 넘겨 받은 방향으로 변환 

t1 = t.transpose((1, 2, 0))      # (0, 1, 2) -> (1, 2, 0) shape (2, 3, 4) 가 반환

# t1 (2, 3, 4)
# [[[ 0  6 12 18]
#   [ 1  7 13 19]
#   [ 2  8 14 20]]
#
#  [[ 3  9 15 21]
#   [ 4 10 16 22]
#   [ 5 11 17 23]]]
  
t2 = t.transpose()              # 기본: (0, 1, 2) -> (2, 1, 0) shape (3, 2, 4) 반환

# t2 (3, 2, 4)
# [[[ 0  6 12 18]
#   [ 3  9 15 21]]
#
# [[ 1  7 13 19]
#   [ 4 10 16 22]]
#
#  [[ 2  8 14 20]
#   [ 5 11 17 23]]]

t3 = t.swapaxes(0, 1)           # (0, 1, 2) -> (1, 0, 2) shape (2, 4, 3) 반환

# t3 (2, 4, 3)
# [[[ 0  1  2]
#   [ 6  7  8]
#   [12 13 14]
#   [18 19 20]]
#
#  [[ 3  4  5]
#   [ 9 10 11]
#   [15 16 17]
#   [21 22 23]]]

# 실습 문제
# ndarray t에 대해서 기존 y-axis가 x-axis로, z-axis가 y-axis로, x-axis가 z-axis로 transpose
t4 = t.transepose(2, 0 ,1)
# shape (3, 4, 2) 반환

 

  • 3차원 배열 (z, y, x) 의 경우 axis 0 = z, axis 1 = y, axis 2 = x 임.
  • (0, 1, 2) 인 3차원 배열을 바꾸는 것을 transpose 함수.

  • t1. = t.transpose(1, 2, 0) 의 경우, (0, 1, 2) -> (1, 2, 0) 으로 변환.(즉, (4, 2, 3) -> (2, 3, 4) 으로 shape이 바뀜)
  • 변환된 배열의 요소가 어떻게 들어가는지 헷갈리면, 반환되는 shape을 적어놓고, axis = 1의 축을 기준으로 가로로 보는 걸 추천!!

  • t2 = t.transpose() 는 t2 = t.transpose(2, 1, 0) 과 동일.
  • 즉, 이전 배열을 완전히 반전하는 것!

  • t3 = t.swapaxes(0, 1) 의 경우, axis 0과 axis 1의 위치를 바꾸는 것.
  • 즉, t3 = t.swapaxes(0, 1) 는 t3 = t.transpose(1, 0, 2)

**transepose와 swapaxes는 t와 t1, t2, t3, t4가 메모리를 공유함.(즉, t1, t2, t3, t4 가 바뀌면 t도 같이 바뀜)**


5️⃣ 1차원 배열 전치( m.T )

m1 = np.arange(10).reshape(2,5)
m1
 
# shape (2, 5) 
# [[0, 1, 2, 3, 4],
#  [5, 6, 7, 8, 9]]

m1.T # m1.transpose() 와 동일

# shape (5, 2)
# [[0, 5],
#  [1, 6],
#  [2, 7],
#  [3, 8],
#  [4, 9]]

m2 = np.arange(5)
m2
 
# shape (5,) 
# [0, 1, 2, 3, 4]

m2.T

# shape(5,)
# [0, 1, 2, 3, 4] (1차원 배열의 경우, 변화 없음)

 m2r = m2.reshape(1,5)
 m2r
 
 # shape(5,1)
 # [[0],
 #  [1],
 #  [2],
 #  [3],
 #  [4]]
  • m.T 의 경우, 대칭으로 변환 (모든 차원에 대해서 가능)
  • m.transpose() 와 동일함.
  • 1차원 배열에 대해서는 T는 변화가 없음.