본문 바로가기
인공지능/데이터분석

넘파이 - 기초

by hyunji00pj 2025. 1. 16.

1. 넘파이(Numpy)

넘파이(Numpy)는 파이썬에서 사용되는 과학 및 수학 연산을 위한 강력한 라이브러리입니다. 주로 다차원 배열을 다루는 데에 특화되어 있어, 데이터 분석, 머신러닝, 과학 계산 등 다양한 분야에서 널리 사용됩니다. 넘파이 배열은 C 언어로 구현되어 있어 연산이 빠르고 효율적입니다. 특히 큰 데이터셋에서 수치 연산을 수행할 때 뛰어난 성능을 보입니다. 또한 메모리 사용을 최적화하고 효율적으로 관리합니다.

 

pip install numpy
#코랩에서는 기본적으로 제공
import numpy as np

2. 넘파이의 주요 특징과 기능

2-1. 다차원 배열(N-dimensional array)

넘파이의 핵심은 다차원 배열인 ndarray입니다. ndarray는 동일한 자료형을 가지는 원소들로 이루어져 있습니다. 다차원 배열은 1차원, 2차원, 3차원 등 다양한 차원을 가질 수 있습니다.

list1 = [1,2,3,4]
print(list1)
print(type(list1))
print(list1[0])
print(type(list1[0]))

#출력
#[1, 2, 3, 4]
#<class 'list'>
#1
#<class 'int'>

 

list2 = [[1,2,3,4],[5,6,7,8]] #vector
print(list2)
print(type(list2))
print(list2[0])
print(type(list2[0]))
print(list2[0][0])
print(type(list2[0][0]))

#출력
#[[1, 2, 3, 4], [5, 6, 7, 8]]
# <class 'list'>
# [1, 2, 3, 4]
# <class 'list'>
# 1
# <class 'int'>

 

ndarr1 = np.array([1,2,3,4])
print(ndarr1)
print(type(ndarr1))
print(ndarr1[0])
print(type(ndarr1[0])) #<class 'numpy.int64'> 64bit int

#출력
# [1 2 3 4]
# <class 'numpy.ndarray'>
# 1
# <class 'numpy.int64'>
ndarr2 = np.array([[1,2,3,4],[4,5,6,7]])
print(ndarr2)
print(type(ndarr2))
print(ndarr2[0])
print(type(ndarr2[0]))
print(ndarr2[0][0])
print(type(ndarr2[0][0]))

#출력
# [[1 2 3 4]
#  [4 5 6 7]]
# <class 'numpy.ndarray'>
# [1 2 3 4]
# <class 'numpy.ndarray'>
# 1
# <class 'numpy.int64'>

2-2. 리스트와 ndarray 변환

데이터 타입을 다른 데이터 타입으로 변환할 수 있습니다. 리스트에서 배열로의 변환은 np.array() 함수를 사용하고, 배열에서 리스트로의 변환은 tolist() 메서드를 사용합니다.

list1 = [1,2,3,4]
ndarr1 = np.array(list1)
print(ndarr1)
print(type(ndarr1))

#출력
# [1 2 3 4]
# <class 'numpy.ndarray'>
list2 = ndarr1.tolist()
print(list2)
print(type(list2))

# 출력
# [1, 2, 3, 4]
# <class 'list'>

2-3. ndarray의 데이터 타입

넘파이의 ndarray는 동일한 자료형을 가지는 원소들로 이루어져 있으며, 다양한 데이터 타입을 지원합니다.

list1 = [1, 3.14, 'Python', '😊', True]
print(list1)
print(type(list1))
print(type(list1[0]))
print(type(list1[1]))
print(type(list1[2]))
print(type(list1[3]))
print(type(list1[4]))

# 출력
# [1, 3.14, 'Python', '😊', True]
# <class 'list'>
# <class 'int'>
# <class 'float'>
# <class 'str'>
# <class 'str'>
# <class 'bool'>
ndarr1 = np.array([1, 2, 3, 4])
print(ndarr1)
print(type(ndarr1))
print(type(ndarr1[0]))
print(type(ndarr1[1]))
print(type(ndarr1[2]))
print(type(ndarr1[3]))

# 출력
# [1 2 3 4]
# <class 'numpy.ndarray'>
# <class 'numpy.int64'>
# <class 'numpy.int64'>
# <class 'numpy.int64'>
# <class 'numpy.int64'>
ndarr2 = np.array([1, 2, 3.14, 4])
print(ndarr2)
print(type(ndarr2))
print(type(ndarr2[0]))
print(type(ndarr2[1]))
print(type(ndarr2[2]))
print(type(ndarr2[3]))

# 출력
# [1.   2.   3.14 4.  ]
# <class 'numpy.ndarray'>
# <class 'numpy.float64'>
# <class 'numpy.float64'>
# <class 'numpy.float64'>
# <class 'numpy.float64'>
ndarr3 = np.array([1, 2, 3.14, True])
print(ndarr3)
print(type(ndarr3))
print(type(ndarr3[0]))
print(type(ndarr3[1]))
print(type(ndarr3[2]))
print(type(ndarr3[3]))

# 출력
# [1.   2.   3.14 1.  ]
# <class 'numpy.ndarray'>
# <class 'numpy.float64'>
# <class 'numpy.float64'>
# <class 'numpy.float64'>
# <class 'numpy.float64'>
ndarr4 = np.array(['1', 2, 3.14, True])
print(ndarr4)
print(type(ndarr4))
print(type(ndarr4[0]))
print(type(ndarr4[1]))
print(type(ndarr4[2]))
print(type(ndarr4[3]))

# 출력
# ['1' '2' '3.14' 'True']
# <class 'numpy.ndarray'>
# <class 'numpy.str_'>
# <class 'numpy.str_'>
# <class 'numpy.str_'>
# <class 'numpy.str_'>
ndarr3 = np.array([1, 2, 3.14, True], dtype=int)
print(ndarr3)
print(type(ndarr3))
print(type(ndarr3[0]))
print(type(ndarr3[1]))
print(type(ndarr3[2]))
print(type(ndarr3[3]))

# 출력
# [1 2 3 1]
# <class 'numpy.ndarray'>
# <class 'numpy.int64'>
# <class 'numpy.int64'>
# <class 'numpy.int64'>
# <class 'numpy.int64'>
ndarr4 = np.array(['1', 2, 3.14, True],dtype=int)
print(ndarr4)
print(type(ndarr4))
print(type(ndarr4[0]))
print(type(ndarr4[1]))
print(type(ndarr4[2]))
print(type(ndarr4[3]))

# 출력
# [1 2 3 1]
# <class 'numpy.ndarray'>
# <class 'numpy.int64'>
# <class 'numpy.int64'>
# <class 'numpy.int64'>
# <class 'numpy.int64'>
ndarr4 = np.array(['일', 2, 3.14, True],dtype=int)
print(ndarr4)
print(type(ndarr4))
print(type(ndarr4[0]))
print(type(ndarr4[1]))
print(type(ndarr4[2]))
print(type(ndarr4[3]))

# ValueError: invalid literal for int() with base 10: '일'

2-4. ndarray 인덱싱과 슬라이싱

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

ndarr1 = np.array(['🍓', '🍉', '🍌', '🍒', '🍑'])
print(ndarr1)
print(ndarr1.shape) #튜플형 리턴

#출력
#['🍓' '🍉' '🍌' '🍒' '🍑']
#(5,)
# 인덱싱
print(ndarr1[0]) #스칼라 데이터로 하나씩 뽑힘 차원이 하나 줄었음
print(ndarr1[1])
print(ndarr1[2])
print(ndarr1[3])
print(ndarr1[4])
print(ndarr1[-1])
print(ndarr1[-2])
print(ndarr1[-3])
print(ndarr1[-4])
print(ndarr1[-5])

# 출력
# 🍓
# 🍉
# 🍌
# 🍒
# 🍑
# 🍑
# 🍒
# 🍌
# 🍉
# 🍓
# 슬라이싱
print(ndarr1[0:3]) #차원이 유지됨
print(ndarr1[2:])
print(ndarr1[:3])

# 출력
# ['🍓' '🍉' '🍌']
# ['🍌' '🍒' '🍑']
# ['🍓' '🍉' '🍌']
# 2차원 배열
ndarr2d = np.array([[1, 2, 3, 4],
                    [5, 6, 7, 8],
                    [9, 10, 11, 12]])
print(ndarr2d)
print(ndarr2d.shape)

# 출력
# [[ 1  2  3  4]
#  [ 5  6  7  8]
#  [ 9 10 11 12]]
# (3, 4)
# 0행 가져오기
print(ndarr2d[0, :]) #정식 표기법 0행의 열 다 가져오기(:)
print(ndarr2d[0,]) # 콜론 생략 가능
print(ndarr2d[0]) #콤마뒤에 값이 없기때문에 0으로 써서 가져온것

# 출력
# [1 2 3 4]
# [1 2 3 4]
# [1 2 3 4]
# 0열 가져오기
print(ndarr2d[:, 0]) # 모든 행을 가져오면서 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, 90, 32]] [[2,4,9]]의 인덱스 가져오기

# 출력
# [ 2 90 32]
ndarr2d = np.array([[1, 2, 3, 4],
                    [5, 6, 7, 8],
                    [9, 10, 11, 12]])
print(ndarr2d[[0, 1], :])

# 출력
# [[1 2 3 4]
#  [5 6 7 8]]
ndarr1 = np.array(['🍓', '🍉', '🍌', '🍒', '🍑'])
sel = [True, False, True, True, False] # True False의 갯수는 맞춰줘야함
ndarr1[sel] #True에 해당하는 것만 가져옴

# 출력
# array(['🍓', '🍌', '🍒'], dtype='<U1')
ndarr2d = np.array([[1, 2, 3, 4],
                    [5, 6, 7, 8],
                    [9, 10, 11, 12]])
ndarr2d > 7

# 출력
# array([[False, False, False, False],
#        [False, False, False,  True],
#        [ True,  True,  True,  True]])
ndarr2d[ndarr2d > 7]

# 출력
# array([ 8,  9, 10, 11, 12])

 

3. 행렬 연산

넘파이에서는 다차원 배열인 ndarray를 사용하여 행렬 연산을 수행할 수 있습니다. 행렬 연산은 선형 대수와 관련이 깊어, 데이터 과학, 머신러닝, 통계 등 다양한 분야에서 사용됩니다.

선형 대수는 벡터와 행렬을 사용해 공간과 변환을 다루는 수학의 한 분야입니다. 쉽게 말해, 여러 숫자를 체계적으로 배열한 벡터(리스트 같은 것)와 행렬(숫자가 격자로 배열된 표)을 이용해 데이터를 표현하고 조작하는 방법입니다. 선형 대수는 컴퓨터 그래픽스, 머신러닝, 물리학, 공학 등 다양한 분야에서 사용됩니다. 예를 들어, 사진에서 색상을 조정하거나, 로봇이 움직일 경로를 계산하거나, AI가 데이터를 분석하는 데도 선형 대수가 필요합니다.

a = np.array([[1, 2, 3],
              [2, 3, 4]])
b = np.array([[3, 4, 5],
              [1, 2, 3]])
print(a.shape, b.shape)

# 출력
# (2, 3) (2, 3)
# 행렬의 덧셈
print(a+b)

#행렬의 뺼셈
print(a-b)

# 행렬 원소별 곱셈
print(a * b)

# 행렬 나눗셈
print(a / b)

출력
[[4 6 8]
 [3 5 7]]
[[-2 -2 -2]
 [ 1  1  1]]
[[ 3  8 15]
 [ 2  6 12]]
[[0.33333333 0.5        0.6       ]
 [2.         1.5        1.33333333]]

행렬곱의 규칙

  1. 첫 번째 행렬의 열(가로 숫자 개수)과 두 번째 행렬의 행(세로 숫자 개수)이 같아야 합니다.
    • 예: A가 2×3 행렬이고 B가 3×2 행렬이라면, A와 B를 곱할 수 있습니다.
  2. 결과 행렬은 첫 번째 행렬의 행 개수 × 두 번째 행렬의 열 개수입니다.
    • 예: A(2×3) × B(3×2) → 결과는 2×2 행렬.
  3. 행렬곱은 첫 번째 행렬의 한 행과 두 번째 행렬의 한 열을 각각 곱한 뒤 더해서 계산합니다.

행렬곱은 두 행렬을 곱해서 새로운 행렬을 만드는 연산으로, 데이터의 변환이나 계산에서 많이 사용됩니다. 행렬은 숫자를 격자로 배열한 것으로, 벡터나 데이터를 다루는 데 유용합니다.

ndarr3 = np.array([[1, 2, 3],
                   [1, 2, 3],
                   [2, 3, 4]])
ndarr4 = np.array([[1, 2],
                   [3, 4],
                   [5, 6]])
print(ndarr3.shape)
print(ndarr4.shape)

# 출력
# (3, 3)
# (3, 2)
print((1*1 + 2*3 + 3*5), (1*2 + 2*4 + 3*6))
print((1*1 + 2*3 + 3*5), (1*2 + 2*4 + 3*6))
print((2*1 + 3*3 + 4*5), (2*2 + 3*4 + 4*6))

# 출력
# 22 28
# 22 28
# 31 40
print(ndarr3 @ ndarr4)
# 행렬 곱셈 또는 벡터 내적을 수행
print(np.dot(ndarr3, ndarr4))

# 출력
# [[22 28]
#  [22 28]
#  [31 40]]
# [[22 28]
#  [22 28]
#  [31 40]]

4. 순차적인 값 생성

NumPy에서 np.arange() 함수는 일정한 간격으로 숫자들을 생성하는 데 사용됩니다. 이 함수는 Python의 기본 range() 함수와 유사하지만, NumPy 배열을 반환하므로 수학적인 연산이 가능합니다.

arr1 = range(1, 11)
print(arr1)

# 출력
# range(1, 11)
for i in arr1:
    print(i, end=' ')

# 출력
# 1 2 3 4 5 6 7 8 9 10
arr2 = np.arange(1, 11)
print(arr2)
print(type(arr2))

# 출력
# [ 1  2  3  4  5  6  7  8  9 10]
# <class 'numpy.ndarray'>
for i in arr2:
    print(i, end=' ')

# 출력
# 1 2 3 4 5 6 7 8 9 10

5. 정렬

NumPy의 np.sort() 함수는 배열을 정렬하는 데 사용됩니다. 이 함수는 기본적으로 원래 배열을 변경하지 않고 정렬된 배열의 복사본을 반환합니다.

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

# 출력
# [ 1 10  5  7  2  4  3  6  8  9]
print(np.sort(ndarr1)) # 오름차순 정렬
print(ndarr1)

# 출력
# [ 1  2  3  4  5  6  7  8  9 10]
# [ 1 10  5  7  2  4  3  6  8  9]
print(np.sort(ndarr1)[::-1])

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

# 출력
# (3, 4)
# 열 단위로 정렬. 각 열의 값들을 개별적으로 오름차순으로 정렬하며, 행(row)의 순서는 재배열
np.sort(ndarr2d, axis=0)
# 행(row) 단위로 정렬. 각 행의 원소들이 개별적으로 오름차순으로 정렬
np.sort(ndarr2d, axis=1)
# 행 단위로 정렬한 후, 각 행의 값을 역순으로 정렬하는 동작을 수행
np.sort(ndarr2d, axis=1)[:, ::-1]
# axis=1과 동일하게 동작. -1은 배열의 마지막 축을 기준으로 동작하라는 의미. 2차원 배열에서 마지막 축은 axis=1을 나타냄
np.sort(ndarr2d, axis=-1)

# 출력
# array([[ 9, 10, 11, 12],
#        [ 1,  2,  3,  4],
#        [ 5,  6,  7,  8]])

 

'인공지능 > 데이터분석' 카테고리의 다른 글

판다스-기초2(데이터프레임 합치기,원-핫 인코딩)  (0) 2025.01.17
판다스-기초1  (0) 2025.01.16
텐서(Tensor)  (0) 2025.01.07
파이토치 프레임워크  (0) 2025.01.06
머신러닝  (2) 2025.01.06