Numpy 정의
- 수학적 함수 모음 제공
- 배열 조작, 수학 연산, 선형 대수, 난수 생성 등을 위한 다양한 기능과 기능을 제공
Numpy 배열(행렬) 생성
# numpy 불러오기
import numpy as np
# np.array([]): 배열 생성
a = np.array([1,2,3])
# np.arange(): 특정 범위 배열 생성
a = np.arange(3)
print(a) #[0,1,2]
# 3차원일 때 arange로 배열 생성
org = (1,2,3)
nb = org[0]*org[1]*org[2]
a = np.arange(nb).reshape(org)
# 0, 1 배열 생성
a = np.zeros(3) # np.zeros(): 0으로 구성된 배열 생성
b = np.zeros((2,3,5)) # 2차원 이상일 경우 괄호 하나 더 추가
c = np.ones(3) # np.ones(): 1로 구성된 배열 생성
d = np.ones((3,5,6))
# a.size: 배열 내 총 원소 수(배열 차원의 곱과 동일 → shape가 (n,m)일 때 size는 n*m)
# a.ndim: 배열의 차원 수(1차원 → 1, 2차원 → 2)
# a.shape: 배열의 차원 크기(n개의 행과 m개의 열 → (n,m))
# a.nbytes: 메모리 크기(데이터타입과 배열 요소 갯수에 따라 결정)
# shape 활용 (여러 변수 사용 시 유용)
a = np.array([[1,2],[2,1]])
n, m = a.shape
b = np.zeros((n+2,m+2))
b[1:n+1,1:m+1] = a
print(b)
# reshape(): 구조 재배열(차원 변환)
a = np.arange(4).reshape(2,2)
print(a) #[[0,1],[2,3]]
# identity matrix 생성
# np.identity(n): nxn 행렬
# np.eye(n, k=0, dtype=int):n은 nxn 행렬을 의미, k 값에 따라 대각행렬이 좌/우측으로 이동
# 패딩 생성
# np.pad(a, 패딩 크기, mode='constant', constant_values=패딩 숫자)
# 대각 행렬 생성
# np.diag(array, k=0): 대각요소 array를 k의 값에 따라 위치
array = [1,2,3,4]
print(np.diag(array,k=-1))
# concatenate: 선택한 축(axis) 방향으로 배열 연결
# 1차원에서는 방향이 하나이므로 axis=0만 가능
# 2차원에서는 상하, 좌우가 있으므로 axis=0과 1이 가능
# 2차원에서 axis=0은 위→아래, axis=1은 좌→우를 의미
a = np.arange(0,8).reshape(2,4)
b = np.arange(0,8).reshape(2,4)
c = np.concatenate([a,b], axis=0)
print(a) #[[0,1,2,3],[4,5,6,7]]
print(c) #[[0,1,2,3],[4,5,6,7],[0,1,2,3],[4,5,6,7]]
Numpy 값 접근
# 값 접근
a = np.arange(10)
a[2:5] *= 3 # 배열 내 인덱스로 접근하기
print(a)
# 요소 출력
# a.flat[n]: 해당 배열을 1차원으로 변환하여 n+1번째 요소 출력
a = np.arange(10)
print(a.flat[5]) # 6(인덱스 0부터 시작하므로)
Numpy 연산
# 사칙연산
a = np.array([1,2,3])
print(a+2) #[3,4,5]
b = np.array([10,20,30])
print(a*2) #[20,40,60]
# 브로드캐스트: 형태가 다른 배열을 연산 가능하도록 배열의 형태를 동적으로 변환
# 다만, 차원 수가 다르면 호환 불가능하기에 브로드캐스팅 실패
# 제곱: 두 배열의 동일 위치에 있는 요소끼리 제곱연산
a = np.arange(3)
print(a**a) #[0,1,4]
# 제곱근
# np.sqrt(): 실수 범위 내에서 제곱근 계산(음수일 경우 NaN 반환)
# np.emath.sqrt(): 복소수에 대한 제곱근 반환
print(np.sqrt(-1) == np.emath.sqrt(-1)) # False
# 사칙연산 함수
# np.add(a,b): 두 배열(또는 스칼라) 간 덧셈
# np.subtract(a,b): 두 배열(또는 스칼라) 간 뺄셈
# np.multiply(a,b): 두 배열(또는 스칼라) 간 곱셈(요소별)
# np.divide(a,b): 두 배열(또는 스칼라) 간 나눗셈
# np.dot(a,b): 두 배열(또는 스칼라) 간 행렬 곱(내적), 아래에서 자세히 설명
# out 매개변수 활용
np.add(a,b,out=c) # a와 b 더하고 결과를 c에 저장
np.multiply(a,b,out=a) #a와 b 곱하고 결과를 a에 저장
# 집계함수
a = np.arange(16).reshape(4,4)
print("최댓값: ", np.max(array1))
print("최솟값: ", np.min(array1))
print("합계: ", np.sum(array1)), 아래에서 자세히 설명
print("평균값: ", np.mean(array1))
print("열별 합계: ", np.sum(array1, axis=0))
# 랜덤값
# np.random.rand(size): 0~1 사이 무작위 값 추출
# np.random.randint(min,max,size): 임의의 정수값 추출
a = np.random.rand(3)
print(a) #[0.08680729,0.11093471,0.53995457]
b = np.random.randint(0,10,3)
print(b) #[6,3,1]
# np.allclose(): 두 배열이 거의 동일한지 비교
a = np.array([1.0, 2.0, 3.0])
b = np.array([1.01, 2.02, 2.99])
result = np.allclose(array1, array2, atol=0.05, rtol=0.05) #atol: 절대오차, rtol: 상대오차
print(result) #True (절대 및 상대 오차 범위 내에 있음)
# 삼각함수
np.arctan2(a,b) #tan-1(b/a)로 계산됨
Numpy sort
# np.sort(a, axis=-1): 순서 정렬
a = np.array([[1,2],[3,1]])
print(np.sort(a)) #[[1,2],[1,3]]
print(np.sort(a, axis=None)) #[[1,1,2,3]]
print(np.sort(a, axis=0)) #[[1,1],[2,3]]
print(np.sort(a, axis=1)) #[[1,2],[1,3]]
print(np.sort(a, axis=None)[::-1]) #[3,2,1,1]
# 배열 뒤집기
# np.sort(a, axis=None)[::-1]
# np.flip(a)
Numpy where
# np.where(condition,x,y): 조건 만족하는 값 반환(True이면 x, False이면 y)
# x,y 명시하지 않으면 조건 만족하는 요소의 인덱스 반환
a = np.array([5,6,8,0,1,0,7])
b = np.where(a != 0) # 0이 아닌 요소의 인덱스 반환
print(b) # array([0,1,2,4,6], dtype=int64),)
a = np.array([1,3,1])
b = np.where(a == 1, np.random.rand(*a.shape), a) # *a.shape는 튜플의 각 요소를 개별 인자로 전달
prind(b) # [0.0623~,3,0.6409~]
Numpy Slicing
# 리스트의 인덱스를 이용하여 일부 또는 전부 추출
# 1차원 배열에서 array[start:end:step]
# 2차원 배열에서 array[행_start:end:step,열_start:end:step] → 결과는 1차원 배열로 출력
a = np.zeros((4, 4))
print(a) #[[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0]]
a[::2,::2] = 1 #홀수행, 홀수열 선택
a[1::2,1::2] = 1 #짝수행, 짝수열 선택
a = 1 - a #0과 1을 뒤바꾸기
print(a) #[[0,1,0,1],[1,0,1,0],[0,1,0,1],[1,0,1,0]]
b = np.array([[1,2,3,4,5],[6,7,8,9,10]])
print(b[0:2,2]) #[3,8]
Numpy tile
# np.tile(a,count): 해당 축을 따라서 count만큼 a를 반복
# 축을 결정하는 것은 count
# 1차원 배열에서 첫번째 축은 좌→우, 2차원 배열에서 첫번째 축은 위→아래
a = np.array([[1,2],[3,4]])
b = np.tile(a,2) # 2이므로 첫번째 축은 좌→우
c = np.tile(a,(2,1)) #(2,1)이므로 첫번째 축은 위→아래
print(b) #[[1,2,1,2],[3,4,3,4]]
print(c) #[[1,2],[3,4],[1,2],[3,4]]
Numpy 마스킹
# 마스킹 연산: 각 원소에 대해 체크
a = np.arange(16).reshape(4,4)
b = a < 10
print(a) #[[0,1,2,3],[4,5,6,7],[8,9,10,11],[12,13,14,15]]
print(b) #[[T,T,T,T],[T,T,T,T],[T,T,F,F],[F,F,F,F]]
a[b] = 100 #10보다 작은 원소는 100으로 값 변경
print(a) #[[100,100,100,100],[100,100,100,100],[100,100,10,11],[12,13,14,15]]
c = (5 < a) & (a < 10) #여러 조건 마스킹 방법
Numpy newaxis
# np.newaxis: 기존 배열에 새로운 차원 추가
arr = np.array([1,2,3,4])
b = arr[np.newaxis]
c = arr[:,np.newaxis]
print(b) #[[1,2,3,4]]
print(c) #[[1],[2],[3],[4]]
print(arr.shape, b.shape, c.shape) #(4,) (1,4) (4,1)
arr2 = np.array([[1,2],[3,4]])
b2 = arr2[np.newaxis]
c2 = arr2[:,np.newaxis]
d2 = arr2[:,:,np.newaxis]
print(b2) #[[[1,2],[3,4]]]
print(c2) #[[[1,2]],[[3,4]]]
print(d2) #[[[1],[2]],[[3],[4]]]
print(arr2.shape, b2.shape, c2.shape, d2.shape) #(2,2) (1,2,2) (2,1,2) (2,2,1)
# 3차원 배열 설명
# 첫번째 차원은 데이터 그룹 갯수를 의미
# 두번째 차원은 각 데이터 그룹 내 행 수를 의미
# 세번째 차원은 각 데이터 그룹 내 열 수를 의미
Numpy sum 이해하기
# 파이썬에서의 sum(a,b)는 두 요소의 합만을 계산, numpy에서는 축을 고려
print(sum(range(3),-1) # 4
print(np.sum(range(3),-1) # 5
# np.sum(a,n): a 배열의 요소 합계
# 1차원 배열의 경우, n=None: 모든 요소의 합계 / 하나의 축만 가지므로 n 설정 불가능
# 2차원 배열의 경우, n=None: 모든 요소의 합계 / n=0: 열 방향을 따라 행 합계 반환 / n=1: 행 방향을 따라 열 합계 반환 / n=-1: 마지막 축을 따라 합계(n=1과 동일)
# 3차원 배열의 경우, 예시로 이해하는게 편함
a = np.array([[[1, 2, 3],
[4, 5, 6]],
[[7, 8, 9],
[10, 11, 12]]])
# np.sum(a,n=0)
array([[ 8, 10, 12],
[14, 16, 18]])
# np.sum(a,n=1)
array([[ 5, 7, 9],
[17, 19, 21]])
# np.sum(a,n=2)
array([[ 6, 15],
[24, 33]])
Numpy dot 이해하기
# np.dot 허용 조건: a행렬의 열 수와 b행렬의 행 수가 일치하는 경우 dot 가능
# 1차원 배열 간 dot
# c = sum(a[k]*b[k]) for k in range(n)
a = np.array([1,2,3])
b = np.array([4,5,6])
c = np.dot(a,b)
print(c) # 1*4+2*5+3*6=4+10+18=32, 결과는 스칼라
# n차원과 1차원 배열 간 dot
# c[i] = sum(a[i, k] * b[k]) for k in range(n)
a = np.array([[1,2,3],[4,5,6]]) # (2,3)
b = np.array([7,8,9]) #(3,)
c = np.dot(a,b)
print(c) # [50,122], 결과는 1차원 배열
# 2차원 배열 간 dot
# c[i,j] = sum(a[i,k]*b[k,j]) for k in range(n)
a = np.array([[1,2],[3,4]]) # (2,2)
b = np.array([[5,6,7],[8,9,10]]) #(2,3)
c = np.dot(a,b)
print(c) # [[21 24 27],[47 54 61]], 결과는 2차원 배열
기타 Numpy function
# np.nan, np.isnan
print(np.nan == np.nan) # False, nan은 자신과도 동일하지 않음
print(np.nan == None) # False, nan은 None과도 당연히 동일하지 않음
print(np.nan is None) # False
print(np.isnan(np.nan)) # True, isnan을 사용하면 nan값을 테스트 가능
# np.intersect1d(a,b): a와 b 배열 간의 공통 값만을 반환
a = np.array([1,2,3,4,5])
b = np.array([3,4,5,6,7])
print(np.intersect1d(a,b)) # [3,4,5]
# np.seterr(all='ignore'): 모든 numpy 경고 무시 설정, all='warn': 경고 활성화
np.seterr(all='ignore')
a = np.divide(0,0)
np.seterr(all='warn')
b = np.divide(0,0)
import datetime
# np.datetime64(datetime.date.today()): 오늘 날짜
# np.timedelta64(value,unit): 시간 간격을 나타냄(value: 시간 간격 크기, unit:'D','h','m')
np.datetime64(datetime.date.today()) - np.timedelta64(1,'D') # 어제
np.timedelta64(1,'h') # 1시간
np.timedelta64(1,'m') # 1분
# 간격 내 날짜 데이터 얻기
a = np.datetime64(datetime.date(2022,10,1))
b = np.datetime64(datetime.date(2022.11.1))
gap = np.arange(a,b,dtype='datetime64[D]') # dtype='datetime64[D]': 날짜 데이터 지정
print(gap) # 2022년 10월 데이터 획득