Python/NumPy

NumPy 유니버설 함수 (Universal Functions, ufunc) 알아보기

임베디드 친구 2025. 10. 2. 19:59
반응형

NumPy 유니버설 함수 (Universal Functions, ufunc) 알아보기

안녕하세요! 오늘은 "소프트웨어 공장"에서 NumPy의 강력한 기능 중 하나인 유니버설 함수(Universal Functions, 줄여서 ufunc)에 대해 알아보겠습니다. ufunc는 고성능의 벡터화 연산을 제공하며, NumPy 배열에서 매우 빠르고 효율적인 계산을 가능하게 해줍니다. 본 포스팅에서는 ufunc의 개념, 주요 특징, 활용 사례 및 몇 가지 자주 사용하는 ufunc에 대해 예제와 함께 알아보겠습니다.

유니버설 함수란 무엇인가?

유니버설 함수는 NumPy에서 제공하는 함수로, 배열의 각 요소에 대해 반복적인 계산을 수행합니다. 일반적인 Python 루프를 사용하는 것보다 훨씬 빠르게 계산을 수행할 수 있습니다. 이는 NumPy가 내부적으로 C로 구현되어 있으며, 최적화된 벡터 연산을 지원하기 때문입니다.

ufunc는 다음과 같은 특징을 가집니다:

  • 벡터화 지원: 반복문 없이도 배열 연산을 수행할 수 있습니다.
  • 방대한 함수 제공: 산술 연산, 삼각 함수, 지수 및 로그 함수 등 다양한 함수가 포함되어 있습니다.
  • 브로드캐스팅 지원: 크기가 다른 배열 간의 연산을 지원합니다.
  • 유연한 입력 및 출력: 다중 입력 및 출력 배열을 지원합니다.

유니버설 함수 사용법

ufunc는 기본적으로 NumPy에서 제공하는 함수로, 배열에 대해 연산을 수행합니다. 아래는 ufunc의 기본적인 사용법입니다:

import numpy as np

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

# ufunc 사용 예시
result = np.sqrt(arr)  # 각 요소에 대해 제곱근 계산
print(result)  # [1. 1.41421356 1.73205081 2.]

자주 사용하는 유니버설 함수

1. 산술 연산 함수

NumPy는 기본적인 산술 연산에 대한 ufunc를 제공합니다. 예를 들어, 덧셈, 뺄셈, 곱셈, 나눗셈 등을 수행할 수 있습니다.

# 덧셈
arr1 = np.array([1, 2, 3])
arr2 = np.array([4, 5, 6])
result = np.add(arr1, arr2)
print(result)  # [5 7 9]

# 곱셈
result = np.multiply(arr1, arr2)
print(result)  # [4 10 18]

2. 삼각 함수

삼각 함수는 과학 계산이나 데이터 분석에서 자주 사용됩니다.

angles = np.array([0, np.pi/2, np.pi])
sin_values = np.sin(angles)
print(sin_values)  # [0. 1. 1.2246468e-16]

3. 지수 및 로그 함수

지수와 로그 함수도 NumPy에서 ufunc로 지원됩니다.

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

# 자연로그
log_values = np.log(values)
print(log_values)  # [0. 0.69314718 1.09861229]

# 지수 함수
exp_values = np.exp(values)
print(exp_values)  # [ 2.71828183  7.3890561  20.08553692]

4. 비교 함수

배열의 요소를 비교하여 논리 연산을 수행할 수도 있습니다.

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

# 비교 연산
result = np.greater(arr, 2)
print(result)  # [False False  True  True]

브로드캐스팅 활용

NumPy ufunc는 브로드캐스팅을 통해 크기가 다른 배열 간의 연산도 지원합니다. 이를 통해 더 유연하게 배열을 다룰 수 있습니다.

# 크기가 다른 배열 연산
arr1 = np.array([1, 2, 3])
arr2 = np.array([[1], [2], [3]])
result = np.add(arr1, arr2)
print(result)
# [[2 3 4]
#  [3 4 5]
#  [4 5 6]]

커스텀 ufunc 생성

NumPy에서는 np.frompyfunc를 사용하여 사용자 정의 ufunc를 생성할 수 있습니다. 이를 통해 사용자가 원하는 연산을 손쉽게 벡터화할 수 있습니다.

# 사용자 정의 함수
import numpy as np

def my_func(x, y):
    return x ** y

# ufunc 생성
custom_ufunc = np.frompyfunc(my_func, 2, 1)

# 배열 연산
arr1 = np.array([1, 2, 3])
arr2 = np.array([4, 5, 6])
result = custom_ufunc(arr1, arr2)
print(result)  # [1 32 729]

유니버설 함수의 성능 비교

ufunc는 일반적인 Python 루프를 사용하는 것보다 훨씬 빠릅니다. 아래는 성능 비교 예제입니다:

import numpy as np
import time

# 큰 배열 생성
arr = np.random.rand(1000000)

# ufunc 사용
start = time.time()
result = np.sqrt(arr)
end = time.time()
print("ufunc 시간:", end - start)

# Python 루프 사용
start = time.time()
result = [x**0.5 for x in arr]
end = time.time()
print("루프 시간:", end - start)

마무리

NumPy의 유니버설 함수는 데이터 분석과 과학 계산에서 매우 중요한 도구입니다. 다양한 함수와 브로드캐스팅 지원 덕분에 복잡한 계산을 간단하게 구현할 수 있습니다. 오늘 소개한 내용을 바탕으로 여러분의 프로젝트에서 NumPy ufunc를 적극적으로 활용해 보세요!

반응형