Python/데이터 분석(전처리, 시각화)

파이썬(5)-Numpy, 행렬 연산

두설날 2024. 5. 24. 12:25

*이 글을 읽기전에 작성자 개인의견이 있으니, 다른 블로그와 교차로 읽는것을 권장합니다.*

1. 넘파이(Numpy)

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

  1. 다차원 배열 객체 (ndarray): NumPy의 핵심은 다차원 배열을 효율적으로 다루기 위한 ndarray 객체입니다. 이는 수학적으로 수학 행렬이나 텐서를 나타낼 수 있으며, 숫자 데이터의 대규모 집합을 효과적으로 저장하고 조작할 수 있습니다.
  2. 다양한 수학 함수: NumPy는 배열 간의 산술 연산, 통계적 계산, 선형 대수학, 푸리에 변환 등 다양한 수학 함수를 제공합니다. 이를 통해 복잡한 수학 연산을 간단하게 수행할 수 있습니다.
  3. 고성능: NumPy는 C 언어로 구현되어 있어, 일반적인 파이썬 코드보다 빠른 연산 속도를 제공합니다. 이는 대규모 데이터 처리가 필요한 과학 계산에서 매우 중요합니다.
  4. 브로드캐스팅: NumPy는 서로 다른 크기의 배열 간의 연산을 자동으로 처리하는 브로드캐스팅 기능을 지원합니다. 이를 통해 코드가 보다 간결하고 직관적으로 작성될 수 있습니다.
  5. 다양한 데이터 처리 기능: 배열 조작, 정렬, 색인, 슬라이싱 등의 다양한 데이터 처리 기능을 제공합니다.
!pip install numpy

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

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

  • 넘파이의 핵심은 다차원 배열 ndarray
  • ndarray는 동일한 자료형을 가지는 원소들로 이루어져 있습니다.
list1 = [1,2,3,4] #1차원
list2 = [[1,2,3,4,], [5,6,7,8]] #2차원
print(list1)
print(list2)
print(type(list1))
print(type(list2))
print(type(list1[0]))
print(type(list2[0]))

  • 넘파이 모듈 연결
import numpy as np
ndarr1 = np.array([1,2,3,4])
print(ndarr1)
print(type(ndarr1)) # <class 'numpy.ndarray'>
print(type(ndarr1[0])) # <class 'numpy.int64'>

ndarr2 = np.array([[1,2,3], [4,5,6]])
print(ndarr2)
print(type(ndarr2))
print(type(ndarr2[0]))

2-2. 리스트와 ndarray 변환

# 리스트를 ndarray로 변환, ndarray는 원소사이에 ,(콤마)가 없네
list1 = [1,2,3,4]
ndarr1 = np.array(list1)
print(ndarr1)
print(type(ndarr1))

# ndarray를 리스트로 변환
list2 = ndarr1.tolist()
print(list2)
print(type(list2))

2-3. ndarray의 데이터 타입

  • 넘파이의 ndarray는 동일한 자료형을 가지는 원소들로 이루어져 있으며, 다양한 데이터 타입을 지원합니다.
list1 = [1, 3.14, 'Python', '😁', True]
print(list1)
print(type(list1[0]))
print(type(list1[1]))
print(type(list1[2]))
print(type(list1[3]))
print(type(list1[4]))

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

ndarr2 = np.array([1,2,3.14,4])
print(ndarr2)
print(type(ndarr2))
print(type(ndarr2[0])) # ndarray는 타입중에 큰것만 저장, 정수<실수 -> numpy.float64 타입만 저장
print(type(ndarr2[2]))

ndarr3 = np.array([1,2,3.14,True]) # Ture값 = 1 변환
print(ndarr3)
print(type(ndarr3))
print(type(ndarr3[0]))
print(type(ndarr3[2]))

ndarr4 = np.array(['1',2,3.14,True]) # 실수형<문자형
print(ndarr4)
print(type(ndarr4))
print(type(ndarr4[0]))
print(type(ndarr4[2]))

ndarr4 = np.array([1,2,3.14,True], dtype=int) # 실수형을 정수형으로 바꾸고싶어
print(ndarr4)
print(type(ndarr4))
print(type(ndarr4[0]))
print(type(ndarr4[2]))
print(type(ndarr4[3]))

ndarr4 = np.array(['1',2,3.14,True], dtype=int) # 문자형 값이 숫자일때만 변환가능, 문자형 값이 str이면 변환불가
print(ndarr4)
print(type(ndarr4))
print(type(ndarr4[0]))
print(type(ndarr4[2]))

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

ndarr1 = np.array(['🍉','🍓','🍌','🍎','🍍'])
print(ndarr1)
print(ndarr1.shape) #shape속성: 차원알기, (5,): 1차원에 원소5개

# 인덱싱
print(ndarr1[0])
print(ndarr1[4])
print(ndarr1[-1])
print(ndarr1[-2])

# 슬라이싱
# ['🍉','🍓','🍌','🍎','🍍']
print(ndarr1[0:3])
print(ndarr1[2:])
print(ndarr1[:3])

# 2차원 배열, 3행4열 -> 행렬에서 행은 demension(차원), 열은 element(원소)
ndarr2d = np.array([[1,2,3,4], [5,6,7,8], [9,10,11,12]])
print(ndarr2d)
print(ndarr2d.shape)

# 0행 가져오기
print(ndarr2d[0])
print(ndarr2d[0,]) #행렬방법
print(ndarr2d[0,:])

# 0열 가져오기
print(ndarr2d[:,0]) #0,1,2행에서 0열

2-5. Fancy Indexing

  • 정수 배열이나 불리언 배열을 사용하여 배열의 일부를 선택하는 방법입니다.
  • 여러 개의 요소를 한번에 선택하거나 조건에 맞게 선택할 수 있습니다.
ndarr1 = np.array([10, 15, 2, 8, 20, 90, 85, 44, 23, 32])
idx = [2,5,9]
print(ndarr1[idx]) #index중 2,5,9번째 뽑기

ndarr2d = np.array([[1,2,3,4], [5,6,7,8], [9,10,11,12]])
print(ndarr2d[[0,1], :]) # 0,1행과 모든 열

2-6. Boolean Indexing

Boolean값으로 이루어진 배열을 사용하여, Boolean의 True값 조건을 충족하는 원소만 선택하는 방법입니다.

ndarr1 = np.array(['🍉','🍓','🍌','🍎','🍍'])
sel = [True, False, True, True, False]
print(ndarr1[sel])

sel = [True, False, True]
# print(ndarr1[sel])
# IndexError: boolean index did not match
ndarr2d = np.array([[1,2,3,4], [5,6,7,8], [9,10,11,12]])
# 비교상의 2차원 원소를 출력
print(ndarr2d[ndarr2d > 7])

# 불리언값 출력
print(ndarr2d > 7)


3. 행렬 연산

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

ndarr1 = np.array([[1,2,3], [2,3,4]])
ndarr2 = np.array([[3,4,5], [1,2,3]])
print(ndarr1.shape) # .shape속성은 행렬 표기
print(ndarr2.shape)

# 행렬 덧셈: 원리는 1행1열+1행1열, 1행2열+1행2열, ...
# 1:1 대응
print(ndarr1 + ndarr2)

# 행렬 뺄셈
print(ndarr1 - ndarr2)

# 행렬 원소별 곱셈 / 행렬곱(dot product)와는 다름
# 1:1 대응 곱셈
print(ndarr1 * ndarr2)

# 행렬곱(Dot Product): =내적 연산, 벡터계산, 벡터각도, 두 벡터의 유사성 계산
# 행렬곱의 조건 맞닿는 shape가 같아야함. 떨어져 있는 shape가 결과 행렬 됨
# 예) (2,3) @ (3,2) = (2,2) -> 앞의 열과 뒤의 행이 같아야함.
# 예) (3,3) @ (3,2) = (3,2)
# print(ndarr1 @ ndarr2)
# ValueError: matmul: Input operand 1 has a mismatch
ndarr3 = np.array([[1,2,3], [1,2,3], [2,3,4]])
ndarr4 = np.array([[1,2], [3,4], [5,6]])
print(ndarr3.shape) # (3, 3)
print(ndarr4.shape) # (3, 2)

# (3,3) @ (3,2) = (3,2)
# 1행*1열=1행1열, 1행*2열=1행2열, ... 3행*2열=3행2열
# 22, 28, ..., 40
print(ndarr3 @ ndarr4)

print(np.dot(ndarr3, ndarr4))

# 전치 행렬(transform): 행 / 열 뒤집기, 행->열 / 열->행
print(ndarr1)
print(ndarr1.T)

# 역행렬(reverse): 정사각 행렬에 대한 곱셈 연산으로 단위 행렬을 얻을 수 있는 행렬
# 역행렬 그림참고
# 단위 행렬: 정방행렬에 대각선이 1인 행렬
arr = np.array([[1,2], [3,4]])
print(np.linalg.inv(arr))


4. 순차적인 값 생성

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

for i in arr1:
    print(i, end='')

# range와 달리 np.arrange로 출력시 ndarray형태로 반환
arr1 = np.arange(1,11)
print(arr1)

for i in arr1:
    print(i, end='')

 


5. 정렬

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

print(np.sort(ndarr1)) #오름차순 정렬

print(ndarr1)

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

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

print(np.sort(ndarr2d, axis = 0)) #행정렬: 1열 기준으로 행순서 정렬

print(np.sort(ndarr2d, axis = 1)) #열정렬: 기존행렬에서 행안의 열만 정렬
print(np.sort(ndarr2d, axis=1)[::-1]) #열정렬 내림차순

print(np.sort(ndarr2d, axis=-1)) # axis는 축의 마지막 방향을 뜻함