NumPy - 2. 배열 연산

2025. 1. 20. 21:04프로그래밍 (확장)/Python-NumPy

1. 기본 배열 연산

배열 간 산술 연산

NumPy에서는 배열 간의 산술 연산을 간단하게 수행할 수 있습니다. 기본적인 산술 연산(+, -, *, /, **)은 배열의 각 요소에 대해 개별적으로 적용됩니다.

주요 특징:

  • 요소별 연산(Element-wise Operation): 배열의 같은 위치에 있는 요소들 간에 연산 수행.
  • 같은 크기의 배열: 연산 대상 배열의 크기가 같아야 함.
  • 스칼라 값 연산: 배열의 모든 요소에 동일하게 적용.

예제:

import numpy as np

# 배열 생성
arr1 = np.array([1, 2, 3])
arr2 = np.array([4, 5, 6])

# 산술 연산
print(arr1 + arr2)  # [5 7 9]
print(arr1 - arr2)  # [-3 -3 -3]
print(arr1 * arr2)  # [4 10 18]
print(arr1 / arr2)  # [0.25 0.4  0.5]
print(arr1 ** 2)    # [1 4 9]

배열 간 비교 연산

NumPy는 배열 간의 비교 연산을 지원하며, 각 요소별로 결과를 반환합니다. 비교 연산의 결과는 불리언 배열로 제공됩니다.

주요 연산:

  • >: 크다
  • <: 작다
  • >=: 크거나 같다
  • <=: 작거나 같다
  • ==: 같다
  • !=: 같지 않다

예제:

# 배열 생성
arr1 = np.array([1, 2, 3])
arr2 = np.array([3, 2, 1])

# 비교 연산
print(arr1 > arr2)  # [False False  True]
print(arr1 < arr2)  # [ True False False]
print(arr1 == arr2) # [False  True False]
print(arr1 != arr2) # [ True False  True]

브로드캐스팅(Broadcasting)

브로드캐스팅은 서로 크기가 다른 배열 간에도 산술 연산을 가능하게 하는 NumPy의 강력한 기능입니다. 작은 배열의 크기를 자동으로 확장하여 크기를 맞춘 후 연산을 수행합니다.

브로드캐스팅 규칙:

  1. 배열의 차원이 다르면 더 작은 배열의 앞부분에 1이 추가됩니다.
  2. 두 배열의 각 차원에서 크기가 같거나 하나가 1이라면 호환됩니다.
  3. 크기가 맞지 않으면 오류가 발생합니다.

예제:

# 배열과 스칼라 간 연산
arr = np.array([1, 2, 3])
print(arr + 10)  # [11 12 13]

# 2차원 배열과 1차원 배열 간 연산
matrix = np.array([[1, 2, 3], [4, 5, 6]])
vector = np.array([1, 2, 3])
print(matrix + vector)
# [[ 2  4  6]
#  [ 5  7  9]]

# 브로드캐스팅 실패 예시
A = np.array([[1, 2], [3, 4]])  # (2, 2)
B = np.array([1, 2, 3])         # (3,)
try:
    C = A + B
except ValueError as e:
    print(f"오류: {e}")

2. 유용한 NumPy 함수

통계 함수

NumPy는 데이터를 분석하기 위한 다양한 통계 함수를 제공합니다.

주요 함수:

  • np.sum: 합계 계산
  • np.mean: 평균 계산
  • np.std: 표준편차 계산
  • np.min, np.max: 최소값, 최대값 계산
  • np.argmin, np.argmax: 최소값, 최대값의 인덱스 반환

축(axis)을 기준으로 연산 수행:

  • 다차원 배열의 경우 axis 옵션을 통해 특정 축을 기준으로 연산할 수 있습니다.

예제:

# 배열 생성
arr = np.array([[1, 2, 3], [4, 5, 6]])

# 통계 함수 예제
print(np.sum(arr))       # 21
print(np.mean(arr))      # 3.5
print(np.std(arr))       # 1.707...
print(np.min(arr))       # 1
print(np.argmax(arr))    # 5 (6의 인덱스)

# 축 기준 연산
print(np.sum(arr, axis=0))  # [5 7 9] (열 합)
print(np.sum(arr, axis=1))  # [6 15] (행 합)

3. 행렬 연산

행렬 곱셈

NumPy에서는 dot, matmul, 또는 @ 연산자를 사용해 행렬 곱셈을 수행할 수 있습니다.

예제:

# 배열 생성
A = np.array([[1, 2], [3, 4]])
B = np.array([[5, 6], [7, 8]])

# 행렬 곱셈
print(np.dot(A, B))
# [[19 22]
#  [43 50]]

print(np.matmul(A, B))
# [[19 22]
#  [43 50]]

# @ 연산자를 사용한 행렬 곱셈
C = A @ B
print(C)
# [[19 22]
#  [43 50]]

전치 행렬과 변형

  • transpose: 행과 열을 뒤바꿈.
  • reshape: 배열의 크기를 변경.

예제:

print(A.T)  # [[1 3]
             #  [2 4]]

print(A.reshape(4, 1))  # [[1]
                        #  [2]
                        #  [3]
                        #  [4]]

역행렬과 선형 방정식 풀이

  • linalg.inv: 역행렬 계산
  • linalg.solve: 선형 방정식 풀이

예제:

# 역행렬 계산
print(np.linalg.inv(A))
# [[-2.   1. ]
#  [ 1.5 -0.5]]

# 선형 방정식 풀이 (Ax = b)
b = np.array([1, 2])
x = np.linalg.solve(A, b)
print(x)  # [-1.  1.5]

4. 유니버설 함수 (ufuncs)

내장 유니버설 함수

NumPy는 빠르고 효율적인 계산을 위해 다양한 수학 함수를 제공합니다.

주요 함수:

  • np.exp: 지수 함수
  • np.log: 자연 로그
  • np.sqrt: 제곱근 계산

예제:

arr = np.array([1, 2, 3])

print(np.exp(arr))  # [ 2.718  7.389 20.085]
print(np.log(arr))  # [0.        0.693147 1.098612]
print(np.sqrt(arr)) # [1. 1.414213 1.732051]

사용자 정의 유니버설 함수 작성

np.frompyfunc를 사용해 사용자 정의 함수를 NumPy 배열에 적용할 수 있습니다.

예제:

# 사용자 정의 함수
def square(x):
    return x ** 2

# 유니버설 함수로 변환
square_ufunc = np.frompyfunc(square, 1, 1)

arr = np.array([1, 2, 3])
print(square_ufunc(arr))  # [1 4 9]