본문 바로가기
Python Basics

Numpy

by Nowkeeh Ahc

 간단한 분석과 데이터 처리를 위해 가장 많이 사용하는 NumPy 라이브러리에 대해 간략히 살펴보도록 하자. NumPy는 파이썬에서 데이터 연산을 쉽고 빠르게 할 수 있도록 다차원 배열 데이터를 효과적으로 처리할 수 있는 라이브러리로서 기존의 파이썬 내장 함수를 이용하는 것보다 훨씬 효과적으로 데이터 연산을 처리할 수 있도록 지원한다. 아나콘다 파이썬에는 NumPy 라이브러리가 포함되어 있으므로 별도의 설치 없이 사용할 수 있다.

 NumPy에서는 주로 데이터를 배열 (Array) 단위로 관리하는데, 배열은 순서가 있는 데이터가 저장된 구조를 의미하며, 일차원 배열부터 우리가 흔히 아는 이차원 배열인 행렬 (Matrix) 또는 그 이상의 다차원 배열을 만들 수 있다. NumPy의 가장 큰 장점은 배열 간의 연산을 반복문 사용 없이 빠르고 정확하게 계산해준다는 것이다. 

 한편, NumPy 배열의 구조를 ‘Shape’이라고 표현하는데, Shape은 파이썬 튜플 자료형을 이용하여 배열의 구조를 정의한다. 예를 들어 아래 [그림 2-1] 같이 3개의 array가 있을 때, 1차원 배열의 Shape은 (3, )이고, 2차원 배열의 Shape은 (2, 3), 그리고 3차원 배열의 Shape은 (2, 2, 2)라고 할 수 있다. 여기에서 주의할 점은 2차원 배열일 때 자료의 구조가 (행 개수, 열 개수) 이지만, 1차원 배열일 때는 단지 요소의 수만을 카운트하여 (요소의 수, ) 방식으로 표현된다는 점이다. 

[그림 2-1] array 구조

 

1) 배열 생성하기 

 NumPy를 이용하여 간단한 배열을 만들어보자. 우선 NumPy 라이브러리를 불러온다. 파이썬에서는 NumPy를 사용할 때 일반으로 명칭을 np라고 변경하여 사용한다.

import numpy as np

 이제 NumPy 라이브러리의 array( ) 함수를 이용하여 1차원 배열을 만들 수 있다. 라이브러리 혹은 라이브러리 내에 포함된 함수나 클래스에 접근하기 위해서는 라이브러리명 뒤에 점(.)을 붙인 뒤 필요한 함수나 클래스명을 기재하면 된다. 가령, 아래 예제의 경우 Numpy의 np.array( )를 함수를 이용하기 위해 np.array( )라고 입력하였다.

data1 = [0, 1, 2, 3, 4 ,5]
a1 = np.array(data1) 
a1

 배열을 만드는 또 다른 방법으로 arange( ) 함수를 사용할 수 있다.

#1. 1부터 10까지 범위 안에서 간격 2를 갖는 배열 생성
a1 = np.arange(start=1, stop=10, step=2)
print(a1)

#2. 0부터 10까지 범위 안에서 간격 1을 갖는 배열 생성
a2= np.arange(10)
print(a2)

 

2) 배열 연산하기 

 NumPy 배열은 배열의 형태 (Shape)가 같다면 배열 간의 연산을 매우 쉽게 할 수 있다. 아래의 예제는 형태가 같은 두 개의 1차원 배열을 생성하고, 이 배열을 이용해 사칙연산을 수행한 것이다.

arr1 = np.array([10, 15, 20, 30]) 
arr2 = np.array([1, 1, 2, 3])

print('----------덧셈----------')
print(arr1+arr2)
print('----------뺄셈----------')
print(arr1-arr2)
print('----------곱셈----------')
print(arr1*arr2)
print('----------나눗셈--------')
print(arr1/arr2)

 

3) 배열의 인덱싱과 슬라이싱 

 배열을 다루다 보면 배열의 각 원소를 선택하여 이용해야 할 때가 있다. NumPy에서는 배열의 위치, 조건 또는 범위를 지정해서 필요한 원소를 선택할 수 있다. 여기서 배열의 위치나 조건을 지정하여 배열의 원소를 선택하는 것을 인덱싱 (Indexing)이라고 하고 범위를 지정해서 배열의 원소를 선택하는 것을 슬라이싱 (Slicing)이라고 한다.


인덱싱 (Indexing)

 인덱싱 기능을 알아보기 위해 우선 리스트를 이용해 a1이라는 1차원 배열을 생성해보자.

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

 다른 여러 프로그래밍 언어와 마찬가지로 파이썬에서도 원소 위치는 0부터 시작된다. 따라서, 상기 a1 배열의 각 원소의 위치와 해당 값을 딕셔너리 형태로 표현하면 {0:0, 1:10, 2:20, 3:30, 4:40, 5:50}과 같이 표현할 수 있다

a1[4]

▶ a1 배열에서 인덱스 4에 해당하는 값을 출력한다.

40

☞ 코드 실행 결과, a1[4]는 0부터 시작하여 5번째 원소를 찾게 되므로 40이 출력된다.

또한, 특정 원소 위치의 값을 변환하고 싶을 때는 a1[5]와 같이 원소를 선택한 후에 변경할 값을 입력한다.

a1[5] = 70 
a1
array([0, 10, 20, 30, 40, 70])

☞ 코드 실행 결과, 값이 50에서 70으로 변환된 것을 확인할 수 있다.

또한 두 개 이상의 원소를 선택할 때는 [[원소1, 원소2, 원소3]]과 같이 대괄호 두 개를 이용하여 지정하면 된다.

a1[[1, 3, 4]]
array([10, 30, 40])

☞ 코드 실행 결과, 10, 30, 40이 출력됨을 확인할 수 있다.

 

슬라이싱 (Slicing)

 슬라이싱 기능을 살펴보기 위해 먼저 리스트를 이용해 b1이라는 1차원 배열을 생성하자.

b1 = np.array([0, 1, 2, 3, 4, 5])
b1
array([0, 1, 2, 3, 4, 5])

 슬라이싱은 ‘배열[시작 위치:끝위치]’ 형식을 통해 범위를 지정할 수 있다. 여기서 반환되는 원소의 실제 범위는 ‘시작위치~끝위치-1’이 된다.

b1[1:4]
array([1, 2, 3])

☞ 코드 실행 결과, 1, 2, 3이 출력됨을 확인할 수 있다.

 또한 끝 위치를 생략할 경우 해당 배열이 가지는 가장 마지막 원소까지 출력이 된다. 

b1[2:]
array([2, 3, 4, 5])

☞ 인덱스 2에 위치하는 값부터 마지막 값까지 출력되었다.

 슬라이싱 또한 인덱싱과 마찬가지로 원소를 지정한 후 값을 입력해 변환할 수 있다.

b1[2:5] = np.array([25, 35, 45])
b1

▶ b1에서 [2:5]에 해당하는 값을 25, 35, 45로 변경한다.

array([0, 1, 25, 35, 45, 5])

☞ 코드 실행 결과, [2:5] 위치에 해당하는 3개의 원소 값이 각각 25, 35, 45로 변환된 것을 확인할 수 있다. 만약 ‘b1[2:5]=25’와 같이 특정 범위에 대해 단일값만 사용했다면 3개의 원소값이 모두 25로 변경된다.

 

4) 배열의 차원 변경하기

 1차원 배열, 즉 벡터의 연산이나 인덱싱 및 슬라이싱을 다루었다. 그러나 실제 데이터 분석에서는 2차원 배열, 즉 행렬 형태의 데이터를 다루는 경우가 더 많다. 따라서, 1차원 배열 벡터를 2차원 배열 행렬 형태로 바꾸는 방법을 살펴보자.

Vector = np.arange(10)
Matrix = Vector.reshape(2, 5)
Matrix

▶ 우선 0부터 9까지 간격 1을 갖는 배열을 객체 Vector에 저장하고, Vector에 배열의 구조를 재정의하는 함수 reshape( )를 적용하여 1차원 배열을 행렬로 변환한다. reshape( ) 함수는 reshape(행, 열)과 같은 형태로 쓰이며, reshape(2, 5)는 배열을 2행 5열의 구조로 만든다는 의미이다.

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

☞ 코드 수행 결과, 0~9까지의 1차원 배열은 2차원 배열, 즉 행렬 형태로 바뀐 것을 확인할 수 있다.

 reshape( ) 함수의 행 인자를 ‘–1’로 지정하면, 열 인자로 지정한 원소 수로 자동으로 행의 수가 결정된다.

Vector = np.arange(10)
Matrix = Vector.reshape(-1, 5)
Matrix

▶ reshape( ) 함수의 행 자리에 -1을 넣고, 열 자리에는 각 배열의 원소 수를 기재하면 해당 원소 수를 갖는 다수의 배열 형태의 행렬 구조로 변환시켜 준다.

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

 마찬가지로 25 형태의 행렬 구조로 변환된 것을 확인할 수 있다. 여기에서 주의할 점은 지정할 원소 수는 나누어질 행 마다 동일한 원소 개수로 분리되도록 지정해야 한다는 점이다. 가령 10개의 원소를 갖는 배열은 reshape (-1, 2)는 가능하지만, reshape(-1, 3) 또는 reshape(-1, 4)는 불가능하다.

 


 

This post was written based on what I read and studied the book below.

http://www.kyobobook.co.kr/product/detailViewKor.laf?mallGb=KOR&ejkGb=KOR&barcode=9791195511747

댓글