#테크 

파이썬 Numpy정의와 특징 프로그래밍 기초함수 끝장내기

파이썬을 통해 머신러닝, 딥러닝, 데이터분석 등을 공부하다보면 필연적으로 마주하게 되는 NumPy! 그 중요하다는 NumPy를 많이 사용하는 이유, 배열을 생성하는 방법들, 기본 연산 그리고 인덱싱, 브로드케스팅 등에 대해 알아봅시다.

2022-10-21 | 김강태

Numpy란 (정의와 특징)

파이썬을 통해 머신러닝, 딥러닝, 데이터분석 등을 공부하다 보면 필연적으로 마주하게 되는 NumPy!
NumPy를 많이 사용하는 이유, 배열을 생성하는 방법들, 기본 연산 그리고 인덱싱, 브로드케스팅 등에 대해 알아봅시다.

Numerical Python의 줄임말 이기도 한 NumPy는 파이썬의 고성능 수치계산을 위한 라이브러리입니다.
여러 형태의 벡터 및 행렬연산과 나아가 여러 수학적인 기능들을 빠르고 간편하게 사용할 수 있는 기능들을 제공합니다.

NumPy 공식 사이트에 소개된 NumPy의 장점은 아래와 같습니다.

  • POWERFUL N-DIMENSIONAL ARRAY
    • NumPy에서 배열 및 벡터를 표현하는 핵심 구조인 ndarray를 사용하여 빠르고 메모리를 효율적으로 사용할 수 있게 합니다.
  • NUMERICAL COMPUTING TOOLS
    • 반복문을 작성할 필요 없이 전체 데이터 배열에 대해 빠른 연산을 제공하는 다양한 표준 수학 함수를 제공한다.
  • PERFORMANT
    • 잘 최적화하여 컴파일된 C/C++ 코드를 사용하여 빠른 연산을 가능하게 합니다.

 

Numpy 프로그래밍 기초 정복

import numpy as np

행렬 및 벡터 연산을 위해선 다차원 array를 사용해야 합니다. NumPy에선 이러한 다차원 array형태인 핵심적인 객체를 ndarray라고 부르며 파이썬의 기본 내장 객체인 array와는 다르게 아래와 같은 속성들을 가지고 있습니다.

  • ndarray.ndim
  • ndarray.shape
  • ndarray.size
  • ndarray.dtype
  • ndarray.itemsize
  • ndarray.data

 

기본 배열 생성

NumPy의 배열 생성은 기본적으로 np.array() 함수를 통해 파이썬 list를 인자로 받아 아래와 같이 생성할 수 있습니다.

a = np.array([0, 1, 2])
b = np.array([(1.5, 2, 3)NumPy, (4, 5, 6)])
print(a)
print(b)

# 실행결과
# array([0, 1, 2])
# array([[1.5, 2. , 3. ],
#        [4. , 5. , 6. ]])

이 외에도 아래와 같이  np.zeors(), np.ones(), np.empty(), np.arange() 등을 통해 배열을 생성 할 수 있습니다.

np.zeros(2)
np.ones(2)
np.arange(4)

# 실행결과
# array([0., 0.]) 
# array([1., 1.]) 
# array([0, 1, 2, 3])

zero() 함수는 0으로 가득 찬 배열을 만들고, ones() 함수는 1로 가득 찬 배열을 만들고, arange() 함수는 특정 수열을 나타내는 배열을 만듭니다. 기본적으로 생성된 배열의 dtype은 float64이지만 아래처럼 키워드 인수 dtype을 통해 지정할 수 있습니다.

np.ones(2, dtype=np.int64)

# 실행결과
# array([1, 1])

 

기본 연산

배열의 기본 산술연산은 element-wise하게 적용이 됩니다.

a = np.array([1, 2, 3])
b = np.array([10, 20, 30])
print(2 * a + b)
 
# 실행 결과 # array([12, 24, 36])

NumPy에선 * 연산은 element-wise하게 곱셈을 하고, 행렬 product 연산을 하기위해선 아래와같이 @ 연산자 혹은 dot()함수를 사용합니다.

A = np.array([[1, 1],
              [0, 1]])
B = np.array([[2, 0],
              [3, 4]])

print(A * B)
print(A @ B)
print(A.dot(B))

# 실행 결과
# array([[2, 0],
#        [0, 4]])
# array([[5, 4],
#        [3, 4]])
# array([[5, 4],
#        [3, 4]])

기본 연산자 외에도 아래처럼 sum(), min(), max()와 같은 함수를 통해 연산할 수 있으며, axis 파라미터를 지정해주면 해당 축에 대하여 연산을 적용 합니다.

a = np.arange(12).reshape(3, 4)
print(a)
print(a.max())
print(a.sum(axis=0))
print(a.min(axis=1))

# 실행 결과
# array([[ 0,  1,  2,  3],
#       [ 4,  5,  6,  7],
#        [ 8,  9, 10, 11]]) 
# 11
# array([12, 15, 18, 21])
# array([0, 4, 8])

인덱싱, 슬라이싱

NumPy 1차원 배열에대한 인덱싱 및 슬라이싱은 아래처럼 파이썬 시본 시퀀스 객체와 동일하게 적용됩니다.

data = np.array([1, 2, 3])
print(data[1])
print(data[0:2])
print(data[1:])
print(data[-2:])

# 실행 결과
# 2
# array([1, 2])
# array([2, 3])
# array([2, 3])

또한 아래처럼 특정 조건을 적용시키는 boolean 인덱싱도 사용 할 수 있습니다.

a = np.array([[1 , 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]])
print(a[a < 5]) print(a[(a > 2) & (a < 11)])

# 실행 결과
# [1 2 3 4]
# [ 3  4  5  6  7  8  9 10]

브로드캐스팅

기본적으로 NumPy 연산들은 element-wise하게 연산이 되기에 벡터 혹은 행렬 간 shape가 맞아야 할 것 같지만  배열과 스칼라 또는 두 개의 서로 다른 크기의 배열 간에 작업을 수행할 수 있습니다. 이 broadcasting 기능은 Numpy가 파이썬 내장 리스트와 구별되는 큰 특징 중 하나 입니다.

a = np.array([1.0, 2.0, 3.0])
b = 2.0
print(a * b)

# 실행 결과
# array([2.,  4.,  6.])

아래의 그림처럼 a와 b의 크기가 다르지만 NumPy는 한 벡터(여기선 a)로 크기를 맞추어 연산을 해줍니다.

지금까지 넘파이의 특징과 넘파이 관련 간단 예제 (슬라이싱/인덱싱),배열,연산에 대해 살펴 보았습니다.
파이썬을 활용해서 데이터 분석과 인공지능과 연계된 프로젝트를 해보고 싶으신 분은 모두의 AI 학교 아이펠 (www.aiffel.io)를 참고하세요!

참고자료
https://numpy.org/devdocs/index.html