데이터 분석 - 넘파이 (1)

2026. 5. 23. 22:37AI/Python

 

Python의 대표적인 데이터 분석 라이브러리로써, Python에서 수치 계산과 데이터 분석을 효율적으로 수행하기 위해 사용한다.

 

특히 다차원 배열(ndArray) 객체를 중심으로 동작하며 대용량 데이터를 빠르고, 메모리 효율적으로 처리할 수 있다.

 

일반 Python 리스트보다 훨씬 빠른 연산 속도를 제공하며, 벡터 연산, 행렬 연산, 통계 처리, 선형 대수, 난수 생성 등

 

다양한 수학 기능을 지원한다.

 

다차원 배열(ndArray)

 

넘파이의 핵심 자료 구조이다.

 

동일한 Data Type을 가지는 데이터를 다차원 형태로 저장하고 빠르게 연산할 수 있도록 만든 배열 객체이다.

 

일반 Python 리스트보다 메모리 사용량이 적고 연산 속도가 매우 빠르며, 벡터 연산과 브로드캐스팅 기능을 통해

 

반복문 없이도 대량의 데이터를 효율적으로 처리할 수 있다.

import numpy as np

ndArray1 = np.array([1, 2, 3, 4]) # 안에 있는 리스트를 ndArray에 삽입한다.
print(type(ndArray1)) # numpy.ndarray

 

위의 다차원 배열 데이터에서 첫번째 있는 항목을 찍어보고 싶다.

print(ndArray[0]) # 1

 

즉, 리스트처럼 인덱싱도 가능한 특징을 가지고 있다.

 

단, 요소의 타입은 int64 타입으로써, 내부적으로 들어가있는 요소의 타입이 다르다는 것이다.

 

이번에는 2차원 리스트를 집어넣어보자.

ndArray2 = np.array([[1, 2, 3],[4, 5, 6]])

print(type(ndArray2)) # numpy.ndarray
print(ndArray[0]) # [1, 2, 3]
print(type(ndArray[0]) # numpy.ndarray

 

즉, 다차원 배열 안에 다차원 배열이 있는 구조로 이루어져 있는 것이다.

 

이번엔 리스트를 다차원 배열로 변환하는 메소드에 대해 알아보자.

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

# numpy.ndarray

 

 그리고, 다차원 배열을 다시 리스트로 변환하는 메소드도 있다.

list2 = ndArray1.toList()
print(type(list2)) # class 'list'

 

이번엔 요소 중 하나의 타입을 float 요소로 넣어서 테스트해보자.

ndArr2 = np.array([1, 2, 3.14, 4])
print(ndArr2) # [1. 2. 3.14 4. ]
print(ndArr2[0]) # float
print(ndArr2[1]) # float
print(ndArr2[2]) # float
print(ndArr2[3]) # float

 

이렇게 되면 큰 타입쪽으로 캐스팅되어 저장되게 되었다.

 

다른 예를 살펴보자.

ndArr3 = np.array([1, 2, 3.14, True])
print(ndArr3) # [1. 2. 3.14 1.]
ndArr4 = np.array(['1', 2, 3.14, True])
print(ndArr4) # ['1' '2' '3.14' 'True']

 

이번엔 dType 속성을 사용하여 통일되는 자료형을 강제해보자.

ndArr3 = np.array([1, 2, 3.14, True], dType=int)
print(ndArr3) # [1 2 3 1]

 

인덱싱과 슬라이싱

 

넘파이의 ndArray는 리스트와 유사하게 인덱싱과 슬라이싱을 지원한다.

ndArray1 = np.array(['1', '2', '3', '4'])
print(ndArray1) # ['1' '2' '3' '4']
print(ndArray1.shape) # (4,) 데이터를 4개 가지고 있는 1차원 배열
# 인덱싱
ndArray1[0] # '1'
ndArray1[-1] # '4'

# 슬라이싱 
ndArray1[0:3] # ['1' '2' '3']
ndArray1[2:] # ['3','4']
ndArray1[:3] # ['1' '2' '3']

 

 이번엔 2차원 배열을 살펴보자.

# 2차원 배열
ndarr2d = np.array([[1, 2, 3, 4],
                    [5, 6, 7, 8],
                    [9, 10, 11, 12]])
print(ndarr2d) 
print(ndarr2d.shape) # (3,4)

# 0행 가져오기 (0번 행의 모든 열을 가져오라.)
print(ndarr2d[0, :]) # [1 2 3 4]
print(ndarr2d[0,]) # [1 2 3 4]
print(ndarr2d[0]) # [1 2 3 4]

# 0열 가져오기 (모든 행의 데이터를 가져오고, 0번째 열인것만)
print(ndarr2d[:, 0]) # [1 5 9]

 

팬시 인덱싱은 리스트로 묶인 인덱스 안에다가 한번 더 []로 묶는 것을 의미한다.

ndarr1 = np.array([10, 15, 2, 8, 20, 90, 85, 44, 23, 32])
idx = [2, 5, 9]
print(ndarr1[idx]) # ndarr1[[2, 5, 9]]

ndarr2d = np.array([[1, 2, 3, 4], 
                    [5, 6, 7, 8], 
                    [9, 10, 11, 12]])
print(ndarr2d[[0, 1], :]) # 0번, 1번행을 선택하고, 모든 열을 가져와라
# [[1 2 3 4] [5 6 7 8]]

 

로지컬 인덱싱은 인덱스에 논리형을 넣어 True인 경우만 뽑아내는 것을 의미한다.

 

불린 데이터와 실제 데이터는 맞아야 비교가 가능하다.

# logical indexing
ndarr1 = np.array(['🍓', '🍉', '🍌', '🍒', '🍑'])
sel = [True, False, True, True, False]
ndarr1[sel] # ['🍓' '🍌' '🍒']

ndarr2d = np.array([[1, 2, 3, 4],
                    [5, 6, 7, 8],
                    [9, 10, 11, 12]])

print(ndarr2d > 7) # [[False, False, False, False],[False, False, False, True]
                   #  [True, True, True, True]]
print(ndarr2d[ndarr2d > 7]) # [8 9 10 11 12]

 

행렬 연산

 

다차원 배열을 사용하여 행렬 연산을 수행할 수 있는데 선형 대수와 관련이 깊어, 데이터 과학, 머신 러닝, 통계 등에서 이용된다.

 

선형 대수

 

벡터와 행렬을 사용해 공간과 변환을 다루는 수학의 한 분야로, 여러 숫자를 체계적으로 배열한 벡터와 행렬을 이용해

 

데이터를 표현하고 조작하는 방법이다. 선형 대수는 컴퓨터 그래픽스, 머신러닝, 물리학, 공학 등 다양한 분야에서 사용된다.

 

예를 들어, 사진에서 색상을 조절하거나, 로봇이 움직일 경로를 계산하거나, AI가 데이터를 분석하는데도 이용된다.

 

스칼라

 

하나의 숫자만으로 이루어진 가장 기본적인 데이터 형태로써, 방향이나 구조는 없고 오직 크기만 가지며

 

일반적인 정수나 실수가 모두 스칼라에 해당되는 것이다.

 

벡터

 

여러 개의 숫자가 1차원으로 나열된 구조이며, 크기와 방향을 함께 표현하는 데이터이다.

 

수학에서는 화살표 개념으로 사용되며, 프로그래밍에서는 1차원 배열 형태로 표현된다.

 

예를 들어, [1, 2, 3]은 3차원 벡터이다.

 

넘파이에서는 보통 1차원 ndArray 형태로 다루며, 벡터 간에는 덧셈, 내적, 크기 계산의 연산을 수행한다.

 

행렬

 

숫자를 표 형태로 표현한 것이다. 가로를 열(Column)라고 하고, 세로를 행(Row)이라고 한다.

 

1. 덧셈 : 같은 포지션끼리 더해서 합친다.

 

 

a = [[1, 2], [3, 4]]
b = [[5, 6], [7, 8]]
print(a + b)

 

2. 뺄셈 : 같은 포지션끼리 빼서 합친다.

 

a = [[1, 2], [3, 4]]
b = [[5, 6], [7, 8]]
print(a - b)

 

 

3. 스칼라 곱 : 행렬 전체에 숫자를 곱한다 (n배)

 

 

a = [[1, 2], [3, 4]]
b = [[5, 6], [7, 8]]
print(2 * a)

 

 

4. 곱셈 : 행과 열을 곱해서 계산한다.

 

 

a = [[1, 2], [3, 4]]
b = [[5, 6], [7, 8]]
print(a @ b)
np.dot(a, b)

 

단, 행렬의 곱셈에서는 변수를 np.array 방식으로 저장하고 연산을 수행해야 한다.

 

정렬

 

np.sort() 함수는 배열을 정렬하는데 사용되며, 기본적으로 원래 배열을 변경하지 않고 복사본을 만든다.

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

print(np.sort(ndArray1)) # 오름차순 정렬 (복사본 반환)
print(ndArray1) # ndArray1은 변경되지 않는다.

print(np.sort(ndArray1)[::-1]) # 내림차순 정렬

ndarr2d = np.array([[11, 10, 12, 9],
                    [3, 1, 4, 2],
                    [5, 6, 7, 8]])
                    
np.sort(ndarr2d, axis=0) # axis=0는 행기준
np.sort(ndarr2d, axis=1) # axis=1는 열기준
# axis=-1은 마지막 축을 의미