newhaneul

[Advanced Python Programming] Lecture 11. Numpy 본문

4. University Study/Advanced Python Programming

[Advanced Python Programming] Lecture 11. Numpy

뉴하늘 2026. 4. 17. 16:15
728x90

포스팅은 인하대학교 허혜선 교수님의 [202601-EEC3408-001] 고급파이썬프로그래밍을 수강하고 공부한 내용을 정리하기 위한 포스팅입니다.

 

 

1. Numpy

  • 벡터화(Vectorization) 연산: 원소끼리의 연산이 이루어지는 것
  • 브로드캐스팅(Broadcasting): 모든 원소에 대해 같은 연산을 적용하는 것

import numpy as np
a = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
b = np.array((0, 1, 2, 3, 4, 5, 6, 7, 8, 9))
c = np.array(range(0, 10))

print(a)
print(b)
print(c)

[0 1 2 3 4 5 6 7 8 9]
[0 1 2 3 4 5 6 7 8 9]
[0 1 2 3 4 5 6 7 8 9]
import numpy as np
b = np.array(range(0, 10, 2))

print(b)

[0 2 4 6 8]

 

  • np.array(리스트): 1차원 ndarray 배열 생성
  • .max(): 최대 값을 반환
  • .min(): 최소 값을 반환
  • .mean(): 평균 값을 반환
  • .flatten(): ndarray 배열을 1차원 배열로 평탄화

 

  • np.append()
import numpy as np
a = np.array([1, 2, 3])
b = np.array([[4, 5, 6], [7, 8, 9]])
c = np.append(a, b)
print(c)

d = np.append([a], b, axis = 0)
print(d)

[1 2 3 4 5 6 7 8 9]
[[1 2 3]
 [4 5 6]
 [7 8 9]]

 

  • np.random.rand(a, b): (a, b) shape의 난수 생성
import numpy as np
a = np.random.randn(3, 3)

print(a)

[[-0.13769801  1.48710473 -1.09145119]
 [ 0.3524087   0.17045809  0.79123598]
 [-0.48311612 -0.12871156  0.00689848]]

 

  • np.random.randint(a, b, size = c): a에서 b 사이의 c개의 난수 생성
import numpy as np
a = np.random.randint(0, 10, size = 10)
print(a)

[6 8 5 5 1 9 2 9 6 1]

 

import numpy as np
a = np.array([23, 45, 67, 7, 2, 30, 34, 82])

print(f"최댓값: {a.max()}")
print(f"최솟값: {a.min()}")
print(f"평균: {a.mean()}")

최댓값: 82
최솟값: 2
평균: 36.25
import numpy as np
b = np.random.randint(0, 100, size = 10)

print(f"b = {b}")
print(f"최댓값: {b.max()}")
print(f"최솟값: {b.min()}")
print(f"평균: {b.mean()}")
import numpy as np
a = np.array([23, 45, 67, 7, 2, 30, 34, 82])
b = np.random.randint(0, 100, size = 10)
c = np.append(a, b)

print(c)

[23 45 67  7  2 30 34 82 61 96 62 66 88 49 39 83 93 11]

 

  • 행렬 곱 연산
    • np.matmul(a, b)
    • np.dot(a, b)
    • a @ b

import numpy as np
a = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
b = np.array([[2, 2, 2], [2, 2, 2], [2, 2, 2]])

print(a+b) # [[3 4 5] [6 7 8] [9 10 11]]
print(a-b) # [[-1 0 1] [2 3 4] [5 46 7]]
print(a*b) # [[2 4 6] [8 10 12] [1 16 18]]
print(a/b) # [[0.5 1 1.5] [2 2.5 3] [3.5 4 4.5]]
print(a@b) # [[12 12 12] [30 30 30] [48 48 48]]
print(a**2) # [[1 4 9] [16 25 36] [49 64 81]]

[[ 3  4  5]
 [ 6  7  8]
 [ 9 10 11]]
 
[[-1  0  1]
 [ 2  3  4]
 [ 5  6  7]]
 
[[ 2  4  6]
 [ 8 10 12]
 [14 16 18]]
 
[[0.5 1.  1.5]
 [2.  2.5 3. ]
 [3.5 4.  4.5]]
 
[[12 12 12]
 [30 30 30]
 [48 48 48]]
 
[[ 1  4  9]
 [16 25 36]
 [49 64 81]]

 

  • np.zeros((n, m)): 모든 값이 0인 n x m 행렬
  • np.ones((n, m)): 모든 값이 1인 n x m 행렬
  • np.full((n, m), x): 초기 값이 x인 n x m 행렬
  • np.eye(n): n x n 크기의 단위 행렬
import numpy as np
a = np.zeros((2, 3))
b = np.ones((2, 3))
c = np.full((2, 3), 100)
d = np.eye(2)

print(a)
print(b)
print(c)
print(d)

[[0. 0. 0.]
 [0. 0. 0.]]
 
[[1. 1. 1.]
 [1. 1. 1.]]

[[100 100 100]
 [100 100 100]]

[[1. 0.]
 [0. 1.]]

 

  • np.linspace(start, stop, num): start에서 stop 사이의 간격을 균등하게 num으로 나눈다.
  • np.logspace(start, stop, num): start에서 stop 사이의 간격을 로그 스케일로 num 개 만큼 나누어 생성한다.

 

 

 

import numpy as np

a1 = np.full((3, 3), 2)
a2 = np.arange(1, 13)
a3 = np.arange(0, 50, 3)
a4 = np.linspace(0, 20, 5)

print(a1)
print(a2)
print(a3)
print(a4)

[[2 2 2]
 [2 2 2]
 [2 2 2]]
 
[ 1  2  3  4  5  6  7  8  9 10 11 12]

[ 0  3  6  9 12 15 18 21 24 27 30 33 36 39 42 45 48]

[ 0.  5. 10. 15. 20.]

 

  • np.arange(0, 10): 0에서 9까지의 1차원 행렬 생성
  • np.arange(0, 10).reshape(2, 5): 0에서 9까지의 원소 값을 가지며, shape이 (2, 5)인 행렬 생성

import numpy as np

a1 = np.arange(1, 13).reshape(2, 6)
a2 = np.arange(1, 31).reshape(3, 10)
print(a1)
print(a2)

[[ 1  2  3  4  5  6]
 [ 7  8  9 10 11 12]]
 
[[ 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]]
import numpy as np

a2 = np.arange(1, 31).reshape(3, 10)
a3 = a2.reshape(6, 5)
a4 = a3.transpose()

print(a2)
print(a3)
print(a4)

[[ 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]]

[[ 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]]
 
[[ 1  6 11 16 21 26]
 [ 2  7 12 17 22 27]
 [ 3  8 13 18 23 28]
 [ 4  9 14 19 24 29]
 [ 5 10 15 20 25 30]]

 

 

2. Numpy axis

  • 2차원 배열에서 axis 0은 행의 방향이며, axis 1은 열의 방향을 의미한다.

 

  • np.insert(arr, obj, values, axis=None)
    • arr: 값을 추가할 원본 배열
    • obj: 값이 삽입될 기준 인덱스
    • values: 추가할 값
    • axis: 값을 추가할 축(방향)
      • axis = 0: 행(Row) 단위로 삽입
      • axis = 1: 열(Column) 단위로 삽입
import numpy as np

a = np.array([1, 3, 4])
print(np.insert(a, 1, 2))

b = np.array([[1, 1], [2, 2], [3, 3]])
print(np.insert(b, 1, 4, axis=0))
print(np.insert(b, 1, 4, axis=1))

[1 2 3 4]

[[1 1]
 [4 4]
 [2 2]
 [3 3]]
 
[[1 4 1]
 [2 4 2]
 [3 4 3]]

 

import numpy as np

a = np.random.randint(1, 101, size=15).reshape(3, 5)
print(a)

print(f"a의 열방향 최댓값: {a.max(axis=0)}")
print(f"a의 열방향 최솟값: {a.min(axis=0)}")
print(f"a의 열방향 평균: {a.mean(axis=0)}")

print(f"a의 행방향 최댓값: {a.max(axis=1)}")
print(f"a의 행방향 최솟값: {a.min(axis=1)}")
print(f"a의 행방향 평균: {a.mean(axis=1)}")

[[23 31 14 69 47]
 [70 82 75 13 57]
 [27 39 64 81 33]]
a의 열방향 최댓값: [70 82 75 81 57]
a의 열방향 최솟값: [23 31 14 13 33]
a의 열방향 평균: [40.         50.66666667 51.         54.33333333 45.66666667]
a의 행방향 최댓값: [69 82 81]
a의 행방향 최솟값: [14 13 27]
a의 행방향 평균: [36.8 59.4 48.8]

 

 

3. Numpy Indexing, Slicing

import numpy as np

a = np.arange(1, 11)
b = a[[1, 3, 5, 7]]
print(b)

[2 4 6 8]
import numpy as np

a = np.arange(1, 11)
print(a[5:])
print(a[6:])
print(a[:3])
print(a[::2])
print(a[::-2])

[ 6  7  8  9 10]
[ 7  8  9 10]
[1 2 3]
[1 3 5 7 9]
[10  8  6  4  2]

 

import numpy as np

a = np.arange(0, 16).reshape(4, 4)
print(a[:, 1])
print(a[2, 1:])
print(a[:2, :2])
print(a[1:3, 1:3])

[ 1  5  9 13]

[ 9 10 11]

[[0 1]
 [4 5]]
 
[[ 5  6]
 [ 9 10]]
import numpy as np

a = np.arange(0, 16).reshape(4, 4)
print(a[:2, :3].flatten())
print(a[2:, :].flatten())
print(a[[1, 3], 1:].flatten())

[0 1 2 4 5 6]
[ 8  9 10 11 12 13 14 15]
[ 5  6  7 13 14 15]

 

 

4. 선형 방정식 풀이

  • np.linalg.solve(a, b)
  • np.linalg.det(A)

import numpy as np

a = np.array([[1, 1, -1], [2, -1, 3], [1, 2, 1]])
b = np.array([0, 9, 8])
c = np.linalg.solve(a, b)
print(f"x = {c[0]}, y = {c[1]}, z = {c[2]}")

x = 1.0, y = 2.0, z = 3.0
import numpy as np

A = np.array([[1, 1, -1], [2, -1, 3], [1, 2, 1]], dtype ='int32')
print(np.linalg.det(A))
print(A[0, 0] * np.linalg.det(A[1:, 1:]) - A[0, 1] * np.linalg.det(A[1:, [0, 2]])
    + A[0, 2] * np.linalg.det(A[1:, :2]))


-11.000000000000002
-11.000000000000002

 

 

예제:

import numpy as np

print("난수 정수 행렬 생성:")
a = np.random.randint(1, 101, size = (5, 3))
print(a)
b = a[:, 1] >= 60
print(b)
c = np.array(a[b])
print(c)

난수 정수 행렬 생성:
[[23 39 90]
 [49 51 39]
 [44 90  4]
 [60 26 10]
 [ 8 83 28]]
 
[False False  True False  True]

[[44 90  4]
 [ 8 83 28]]

import numpy as np

p1 = np.array([1, 5, 10])
p2 = np.array([2, 4, 6])

d = np.sqrt(np.sum(np.pow(p1 - p2, 2)))
print(d)

4.242640687119285

 

  • slice를 사용하면 해당 행이 살아 있음
    • array2[1, 1:]: [5 6] ... (2, )
    • array2[1:2, 1:] [[5 6]] ... (1, 2)
array2 = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])

print(array2[1, 1:])
print(array2[1, 1:].shape)
print(array2[1:2, 1:])
print(array2[1:2, 1:].shape)

print(array2[:2, :2])  # 첫 두 행, 첫 두 열 슬라이싱
print(array2[:2, :2].shape)

[5 6]
(2,)
[[5 6]]
(1, 2)
[[1 2]
 [4 5]]
(2, 2)

 

  • array > 25: 벡터화(Vectorization): numpy 원소끼리 연산
import numpy as np

array = np.array([10, 20, 30, 40, 50])

result = array[array>25] # 25보다 큰 값 추출
print(result)
array2 = np.array([[10, 20, 30], [40, 50, 60]])

result = array2[array2 > 35] # 35보다 큰 값 추출
print(result)  

result = array2[array2 > 25] # 25보다 큰 값 추출
print(result)  

[40 50 60]
[30 40 50 60]

 

  • np.where(condition):  조건을 만족하는 요소들의 인덱스를 튜플 형태로 반환
indices = np.where(array > 30) # 30보다 큰 인덱스 추출
print(indices)  

print(array[indices])  # 인덱스를 사용하여 값 추출

(array([3, 4]),)
[40 50]

 

  • np.delete(arr, obj, axis=None): 배열에서 특정 위치(인덱스)의 요소를 삭제할 때 사용
array2 = np.array([[1, 2], [3, 4], [5, 6]])
result2 = np.delete(array2, 1, axis=0)  # 1번 행(2행) 삭제 -> [[1, 2], [5, 6]]
result3 = np.delete(array2, 0, axis=1)  # 0번 열(1열) 삭제 -> [[2], [4], [6]]
print(result2)
print(result3)

[[1 2]
 [5 6]]
[[2]
 [4]
 [6]]

 

  • np.isin(arr, elements): 배열의 각 요소가 특정 값들의 집합에 포함되어 있는지 한 번에 확인할 때 사용하는 함수
array = np.array([10, 20, 30, 40, 50])

result = np.isin(array, [10, 30]) # 10 또는 30이 포함된 값 찾기
print(result)

filtered = array[result] # 조건 만족하는 값만 추출
print(filtered)

[ True False  True False False]
[10 30]

 

  • 행렬 곱 연산
    • np.matmul(vector1, vector2)
    • vector1 @ vector2
    • np.dot(vector1, vector2)
import numpy as np

# 두 벡터 정의
vector1 = np.array([[1, 2], [3, 4]])
vector2 = np.array([[4, 5], [5, 6]])

# 벡터 내적 계산
dot_product = np.matmul(vector1, vector2) 
print("벡터 내적:", dot_product) # 1*4 + 2*5 + 3*6
dot_product = vector1 @ vector2 
print("벡터 내적:", dot_product) # 1*4 + 2*5 + 3*6
dot_product = np.dot(vector1, vector2) 
print("벡터 내적:", dot_product) # 1*4 + 2*5 + 3*6

벡터 내적: [[14 17]
 [32 39]]
벡터 내적: [[14 17]
 [32 39]]
벡터 내적: [[14 17]
 [32 39]]

 

 

추가:

import numpy as np

v2 = np.arange(1, 16)

# 아래 빈칸을 채워 배열 [14, 11,  8,  5,  2] 가 출력되도록 만들기
result = v2[???]

print(result)
# 1. 양수 인덱스를 활용한 정답
result = v2[13::-3]

# 2. 음수 인덱스를 활용한 정답
result = v2[-2::-3]

 

 

문제 1: 체스판 패턴 만들기 (고급 슬라이싱)

 크기가 8x8이고 모든 요소가 0인 2차원 배열을 생성한 뒤, 슬라이싱 연산만을 사용하여 체스판처럼 0과 1이 교차하는 패턴을 만들어라. 단, [0, 0] 위치의 값은 0이어야 한다.

import numpy as np

mat = np.zeros((8, 8))
print(mat)

mat[::2, ::2] = 1
mat[1::2, 1::2] = 1
print(mat)

[[0. 0. 0. 0. 0. 0. 0. 0.]
 [0. 0. 0. 0. 0. 0. 0. 0.]
 [0. 0. 0. 0. 0. 0. 0. 0.]
 [0. 0. 0. 0. 0. 0. 0. 0.]
 [0. 0. 0. 0. 0. 0. 0. 0.]
 [0. 0. 0. 0. 0. 0. 0. 0.]
 [0. 0. 0. 0. 0. 0. 0. 0.]
 [0. 0. 0. 0. 0. 0. 0. 0.]]
 
[[1. 0. 1. 0. 1. 0. 1. 0.]
 [0. 1. 0. 1. 0. 1. 0. 1.]
 [1. 0. 1. 0. 1. 0. 1. 0.]
 [0. 1. 0. 1. 0. 1. 0. 1.]
 [1. 0. 1. 0. 1. 0. 1. 0.]
 [0. 1. 0. 1. 0. 1. 0. 1.]
 [1. 0. 1. 0. 1. 0. 1. 0.]
 [0. 1. 0. 1. 0. 1. 0. 1.]]

 

문제 2: 다중 조건부 데이터 변경 (불리언 인덱싱 & np.where)

 1부터 20까지의 연속된 정수로 이루어진 1차원 배열을 생성하라. 그다음, 15의 배수는 -3, 5의 배수는 -2, 3의 배수는 -1로 원본 배열의 값을 변경하라. (단, 15는 3과 5의 공배수이므로 반드시 -3으로 변경되어야 한다.)

import numpy as np

array = np.arange(1, 21)
print(array)

a = np.where(array % 5 == 0) 
b = np.where(array % 3 == 0)
c = np.where(array % 15 == 0)

array[a] = -2
print(array)

array[b] = -1
print(array)

array[c] = -3
print(array)

[ 1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20]
[ 1  2  3  4 -2  6  7  8  9 -2 11 12 13 14 -2 16 17 18 19 -2]
[ 1  2 -1  4 -2 -1  7  8 -1 -2 11 -1 13 14 -1 16 17 -1 19 -2]
[ 1  2 -1  4 -2 -1  7  8 -1 -2 11 -1 13 14 -3 16 17 -1 19 -2]

 

 

문제 1: 배열 생성과 재구성 (reshape, transpose)

 np.arange를 사용하여 2부터 24까지의 짝수로 이루어진 1차원 배열을 생성하라. 그 후, 이 배열을 3행 4열(3x4)의 2차원 배열로 재구성(reshape)하고, 만들어진 행렬의 전치(transpose) 행렬을 생성하여 출력하라.

import numpy as np

array = np.arange(2, 25, 2).reshape(3, 4)
print(array)
print(np.transpose(array))

[[ 2  4  6  8]
 [10 12 14 16]
 [18 20 22 24]]
 
[[ 2 10 18]
 [ 4 12 20]
 [ 6 14 22]
 [ 8 16 24]]

 

문제 2: 조건부 데이터 추출 및 변경 (Boolean Indexing)

 10부터 100까지 10 단위의 값으로 이루어진 1차원 배열을 생성하라.

  1. 배열에서 40 이상 80 이하인 값들만 논리 연산자를 사용해 추출하여 출력하라.
  2. 원본 배열에서 30 이하이거나 90 이상인 값들을 모두 0으로 덮어씌워 변경하라.
import numpy as np

array = np.arange(10, 101, 10)
print(array[(array >= 40) & (array <= 80)])

array[(array <= 30) | (array >= 90)] = 0
print(array)

[40 50 60 70 80]
[ 0  0  0 40 50 60 70 80  0  0]

 

문제 3: 다차원 배열의 삭제와 슬라이싱 (np.delete, Slicing)

 다음과 같은 3x3 크기의 배열을 생성하라. arr = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) 이 배열에서 2행(인덱스 1 위치의 행)을 np.delete 함수와 axis를 지정하여 삭제한 뒤 새로운 변수에 저장하라. 그 다음, 행이 삭제되고 남은 새 배열에서 두 번째 열(인덱스 1) 전체를 슬라이싱하여 출력하라.

import numpy as np

arr = np.array([[1, 2, 3], 
                [4, 5, 6], 
                [7, 8, 9]])

res = np.delete(arr, 1, axis=0)
print(res[:, 1])

[2 8]

 

문제 4: 축(axis)을 활용한 통계 연산

 np.random.randint(1, 50, size=15)를 사용하여 1부터 49 사이의 난수 15개를 생성하고, 이를 3행 5열(3x5) 크기의 배열로 변환하라.

  1. 이 배열의 열 방향(세로 방향, axis=0)의 합계(sum)를 구하라.
  2. 이 배열의 행 방향(가로 방향, axis=1)의 최댓값(max)을 구하라.
import numpy as np

arr = np.random.randint(1, 50, size=15).reshape(3, 5)

print(arr)
print(arr.sum(axis=0))
print(arr.max(axis=1))

[[43 22  4 23 32]
 [10 35 20 25 21]
 [18 28  3 34 15]]
 
[71 85 27 82 68]

[43 35 34]

 

문제 5: 선형 연립방정식 풀이와 행렬식 (np.linalg)

다음과 같은 선형 연립방정식이 주어졌다.

$3x + 2y = 12$

$x - y = -1$

  1. 위 방정식의 계수 행렬 A와 상수 벡터 b를 넘파이 배열로 선언하고, np.linalg.solve 함수를 사용하여 해(x, y)를 구하라.
  2. 계수 행렬 A의 행렬식(determinant)을 np.linalg.det 함수를 사용하여 구하라.
import numpy as np

a = np.array([[3, 2], [1, -1]])
b = np.array([12, -1])

c = np.linalg.solve(a, b)
print(f"x = {c[0]:.2f}, y = {c[1]:.2f}")
print(f"determinant: {np.linalg.det(a):.2f}")

x = 2.00, y = 3.00
determinant: -5.00
728x90