본문 바로가기

파이썬 python/파이썬 기초 basic

NumPy 예제

MAE와 RMSE 함수 구현하기

  • 다음과 같이 실제 값과, 모델이 예측한 값이 각각 100개가 있다
  • 실제값과 예측값 사이에 평균 오차를 구하는 함수 두개를 구현하자

 

>>> np.random.seed(42)

# 정답값
>>> target = np.random.randint(50, 91,100) 

# 예측값
>>> pred = np.random.randint(40, 100,100) 
>>> target , pred

(array([88, 78, 64, 57, 70, 88, 68, 72, 60, 60, 73, 85, 89, 73, 52, 71, 51,
        73, 79, 87, 51, 70, 82, 61, 71, 74, 76, 77, 65, 64, 52, 86, 56, 70,
        58, 88, 67, 53, 74, 63, 58, 75, 51, 69, 77, 56, 57, 84, 63, 66, 85,
        89, 53, 51, 55, 53, 78, 67, 75, 83, 59, 85, 63, 80, 64, 57, 63, 72,
        89, 70, 65, 67, 73, 75, 74, 90, 78, 64, 50, 74, 56, 58, 73, 50, 57,
        73, 60, 66, 57, 84, 84, 82, 54, 88, 90, 77, 56, 58, 57, 61]),
 array([73, 72, 87, 94, 62, 63, 76, 74, 83, 79, 61, 66, 74, 40, 74, 76, 86,
        53, 42, 40, 44, 65, 94, 53, 78, 66, 48, 54, 54, 65, 81, 99, 52, 90,
        71, 78, 88, 91, 71, 43, 69, 76, 62, 78, 84, 54, 82, 68, 75, 52, 71,
        46, 98, 90, 61, 67, 41, 81, 84, 96, 92, 45, 67, 67, 83, 83, 59, 69,
        50, 97, 94, 67, 64, 78, 72, 40, 96, 66, 96, 91, 52, 80, 42, 78, 45,
        47, 66, 48, 76, 72, 90, 81, 83, 63, 54, 98, 93, 71, 71, 63]))

 

MAE(Mean Absolute Error)

  • 실제 값과 예측 값의 차이를 절댓값으로 변환해 평균화 하는 것

 

>>> def mae(target,pred):

# 절대값을 구하고 감싸줘서 전체 평균 구해주기
>>>     return np.mean(np.abs(target-pred))
>>> mae(target,pred)

17.8

 

절대값을 구하는 함수: np.abs(x)

 

 

RMSE(Root Mean Squared Error)

  • 실제 값과 예측 값의 차이를 제곱한 뒤 평균화 후 루트

 

>>> def rmse(target,pred):
>>>     return np.sqrt(np.mean(np.square(target-pred)))
>>> rmse(target,pred)
21.829796151132516

 

시그모이드 함수 구현하기

  • S와 같은 형태로 미분 가능한 0~1 사이의 값을 반환
  • 이진 분류에 출력 함수로 사용

 

# x 변수에 있는 배열의 요소들을 시그모이드 함수에 넣어 0 ~ 1 사이 값들로 변경하시오.

>>> np.random.seed(42)
>>> x = np.random.randint(-10,10,10)
>>> x
array([-4,  9,  4,  0, -3, -4,  8,  0,  0, -7])


>>> def sigmoid(x):
>>>     return 1 / (1 + np.exp(-x))
>>> sigmoid(x)
array([1.79862100e-02, 9.99876605e-01, 9.82013790e-01, 5.00000000e-01,
       4.74258732e-02, 1.79862100e-02, 9.99664650e-01, 5.00000000e-01,
       5.00000000e-01, 9.11051194e-04])

 

 

Q.

3행 2열형태의 배열에서 두개 열 위치를 바꾸시오

>>> np.random.seed(42)
>>> arr = np.random.randint(50,100,[3,2])
>>> arr
array([[88, 78],
       [64, 92],
       [57, 70]])​

 

>>> arr[:,::-1]
array([[78, 88],
       [92, 64],
       [70, 57]])
       
       
>>> arr[:,[1,0]]
array([[78, 88],
       [92, 64],
       [70, 57]])

 

 

Q.

다음의 배열에서 각행의 평균을 구하시오.

>>> np.random.seed(42) 
>>> arr = np.random.randint(50, 101, (4, 3))
>>> arr
array([[88, 78, 64],
       [92, 57, 70],
       [88, 68, 72],
       [60, 60, 73]])​

 

>>> arr.mean(axis=1)
array([76.66666667, 73.        , 76.        , 64.33333333])

 

 

데이터 설명

  • 시계열 학습이 가능한 형태로 변환되 있다
  • 행마다 10일치의 시작가 ,상한가 , 하한가, 종가 에 대한 행렬이 들어가 있다

 

>>> samsung_stock_3d = np.load("samsung_stock_2021_3d.npy")
>>> samsung_stock_3d.shape
(234, 10, 4)

 

 

 

어떻게 생겼나 분석해보자

  • 한행을 보면 2차원 행렬 형태
  • 행은 일자
  • 열은 시작가, 상한가, 하한가, 종가 순이다

 

>>> samsung_stock_3d[0]
array([[81000, 84400, 80200, 83000],
       [81600, 83900, 81600, 83900],
       [83300, 84500, 82100, 82200],
       [82800, 84200, 82700, 82900],
       [83300, 90000, 83000, 88800],
       [90000, 96800, 89500, 91000],
       [90300, 91400, 87800, 90600],
       [89800, 91200, 89100, 89700],
       [88700, 90000, 88700, 89700],
       [89800, 91800, 88000, 88000]])

 

 

 

samsung_stock_3d 변수의 3차원 데이터에 각 행의 행렬을 벡터 형태로 변환하여 데이터셋을 2차원형태로 변경하여 samsung_stock_2d 라는 변수에 담으세요.

 

>>> samsung_stock_avg = samsung_stock_3d.mean(axis=1) 
>>> samsung_stock_avg.shape
(234, 40)

 

 

 

 

samsung_stock_3d 변수의 3차원 데이터에 각 행의 시작가 ,상한가 , 하한가, 종가별로 평균을 구해 2차원 형태로 변경하여 samsung_stock_avg 라는 변수에 담으세요

 

>>> samsung_stock_avg = samsung_stock_3d.mean(axis=1) 
>>> samsung_stock_avg.shape
(234, 4)

 

 

 

5번과 6번에서 생성한 변수들의 데이터를 옆으로 합쳐서 x_train 변수에 넣어주세요.

 

>>> x_train = np.concatenate([
>>>     samsung_stock_2d,
>>>     samsung_stock_avg
>>> ],axis=1)
>>> x_train.shape

 

배열 결합 (np.concatenate)
  • 선택한 축(axis)의 방향으로 배열을 연결해주는 메소드
  • concatenate: '사슬 같이 연결하다'
  • axis 값을 조절하여 어떤 축을 기준으로 배열을 합칠지 정할 수 있음
  • numpy.vstack() : axis=0으로 한 numpy.concatenate()와 동일

 

# ones는 zeros와 마찬가지로 1로 가득찬 array 생성
>>> a1 = np.ones((2, 3), int)
>>> print(a1)
[[1 1 1]
 [1 1 1]]
 
 
# np.full((행,열),출력되는 값)
>>> a2 = np.full((2, 3),2)
>>> print(a2)
[[2 2 2]
 [2 2 2]]
 


# 둘이 값 동일
>>> print(np.vstack([a1, a2]))
[[1 1 1]
 [1 1 1]
 [2 2 2]
 [2 2 2]]
 
>>> print(np.concatenate([a1, a2], 0))
[[1 1 1]
 [1 1 1]
 [2 2 2]
 [2 2 2]]
 
 
 
# 부록: 가로로 출력하기
>>> print(np.concatenate([a1, a2], 1))
[[1 1 1 2 2 2]
 [1 1 1 2 2 2]]

 

 

 

x_train변수의 각 특성(열)들에 최대값과 최소값들 구하시오

 

>>> mins, maxs = np.quantile(x_train,[0,1],axis=0)
>>> mins , maxs

(array([68700., 69600., 68300., 68800., 68700., 69600., 68300., 68800.,
        68700., 69600., 68300., 68800., 68700., 69600., 68300., 68800.,
        68700., 69600., 68300., 68800., 68700., 69600., 68300., 68800.,
        68700., 69600., 68300., 68800., 68700., 69600., 68300., 68800.,
        68700., 69600., 68300., 68800., 68700., 69600., 68300., 68800.,
        70040., 70550., 69510., 69920.]),
 array([90300., 96800., 89500., 91000., 90300., 96800., 89500., 91000.,
        90300., 96800., 89500., 91000., 90300., 96800., 89500., 91000.,
        90300., 96800., 89500., 91000., 90300., 96800., 89500., 91000.,
        90300., 91800., 89100., 90600., 89800., 91800., 89100., 89700.,
        89800., 91800., 88700., 89700., 89800., 91800., 88000., 89400.,
        88520., 90410., 87060., 88510.]))

 

 

np.quantile

quantile은 4분위수, percentile은 100분위수를 의미

 

 

 

 

 

x_train변수의 각 특성(열)들에 분위수기준으로 5% 지점값들과 95% 지점값들을 구하시오

 

>>> q05 , q95 = np.quantile(x_train,[0.05,0.95],axis=0)
>>> q05 , q95

(array([70300. , 70965. , 70000. , 70200. , 70300. , 70965. , 70000. ,
        70200. , 70300. , 70965. , 70000. , 70200. , 70300. , 70965. ,
        70000. , 70200. , 70300. , 70965. , 70000. , 70200. , 70300. ,
        70965. , 70000. , 70200. , 70300. , 70965. , 70000. , 70200. ,
        70300. , 70965. , 70000. , 70200. , 70300. , 70965. , 70000. ,
        70200. , 70300. , 70965. , 70000. , 70200. , 70666.5, 71169.5,
        70043. , 70430. ]),
 array([86340. , 87805. , 85205. , 86245. , 86340. , 87805. , 85205. ,
        86245. , 86340. , 87805. , 85205. , 86245. , 86340. , 87805. ,
        85205. , 86245. , 86340. , 87805. , 85205. , 86245. , 86340. ,
        87440. , 85205. , 85740. , 86135. , 86715. , 84905. , 85600. ,
        85905. , 86270. , 84410. , 85470. , 85735. , 86200. , 84135. ,
        85335. , 85310. , 86070. , 84100. , 85105. , 86088. , 87506. ,
        84803.5, 85781. ]))

 

 

 

이상치를 제거해보기
- x_train변수의 특성(열)들에 분위수 기준 5% 지점의 미만값들을 5% 지점값으로 변경하고
- 95% 지점을 초과하는 값들을 95% 지점값으로 변경해보세요.

 

>>> x_train = np.clip(x_train, q05 , q95)
>>> x_train

array([[81000. , 84400. , 80200. , ..., 87506. , 84803.5, 85781. ],
       [81600. , 83900. , 81600. , ..., 87506. , 84803.5, 85781. ],
       [83300. , 84500. , 82100. , ..., 87506. , 84803.5, 85781. ],
       ...,
       [78300. , 78600. , 77100. , ..., 78010. , 76840. , 77490. ],
       [77400. , 78200. , 77000. , ..., 78090. , 77010. , 77690. ],
       [77400. , 77600. , 76800. , ..., 78270. , 77240. , 77860. ]])

 

 

여기서부터 모르겠는데 그냥 적어 놓겠음

 

 

 

x_train 데이터셋에서 20%의 데이터의 인덱스들을 리스트에 담아 5번 랜덤하게 반환하는 제너레이터(리스트 형태로 반환 가능) 함수를 만들어주세요

- 단, 5번 랜덤하게 반환하는 과정에서 동일한 행의 인덱스가 나오면 안됨
- 한번 나온 행의 인덱스는 다시 나오면 안된다는 의미   
- 모든 행의 인덱스가 한번씩은 무조건 나와야한다.
- 234행 나누기 5를 할경우 나머지가 생기기 때문에 5번째 나오는 인덱스들이 담긴 리스트는 앞서 나온 크기와 차이가 나도 된다.  
- 제너레이터가 어려우신 분들은 그냥 인덱스들을 담고 있는 리스트들을 새로운 리스트에 담아서 return 해도 된다

 

>>> 234 // 5
46

 

yield 이용

# yield 를 이용한 방식
>>> def split_dataset(dataset):
    # 나중에 파라미터로 받을수도 있으니 지역변수 선언
>>>     n_split = 5
>>>     seed = 42

>>>     n_row = len(dataset) # 총 개수
>>>     index_arr = np.arange(n_row) # 인덱스

>>>     np.random.seed(seed)
>>>     np.random.shuffle(index_arr) # 랜덤하게 뽑기위해 섞기
>>>     n_samples = n_row // n_split 
>>>     for i in range(n_split): 
>>>         start = i*n_samples
>>>         end = start + n_samples  
>>>         if i+1 == n_split: 
>>>             end =  n_row 
>>>         yield index_arr[start:end]

 

# 함수 실행 결과를 검증하는 부분

>>> index_list = split_dataset(x_train)
>>> lst = [] # 크기가 데이터셋 크기와 같은지 확인하기 위한 리스트
>>> for idx in index_list:

# 중복 인덱스가 있으면 안되기 때문에 제거하기 위한 코드 
>>>     idx = list(set(idx)) 


# 리스트에 담기
>>>     lst.extend(idx) 

# 중복 제거
>>> lst = list(set(lst)) 


# 크기가 데이터셋 크기와 같고(즉 234개면 성공), 인덱스 최대값이 233 이고, 최소값이 0 이면 성공!!

>>> print(f"리스트 크기: {len(lst)}")
>>> print(f"최대값: {max(lst)}")
>>> print(f"최소값: {min(lst)}")

리스트 크기: 234
최대값: 233
최소값: 0

 

 

yield from 이용

# yield from 을 이용한 방식
>>> def split_dataset(dataset):
    # 나중에 파라미터로 받을수도 있으니 지역변수 선언
>>>     n_split = 5
>>>     seed = 42

>>>     n_row = len(dataset) # 총 개수
>>>     index_arr = np.arange(n_row) # 인덱스

>>>     np.random.seed(seed)  
>>>     np.random.shuffle(index_arr) # 랜덤하게 뽑기위해 섞기
>>>     n_samples = n_row // n_split # 20% 의 데이터셋 개수
>>>     n_sub = n_row - n_samples * n_split # 나머지 개수
>>>     index_list = index_arr[:n_row-n_sub].reshape(n_split,-1).tolist()

>>>     if n_sub > 0: # 남는개수가 있다면..


    # 마지막 인덱스 리스트에 추가 확장
>>>         index_list[-1].extend(list(index_arr[n_row-n_sub:])) 
>>>     yield from index_list

 

>>> index_list = split_dataset(x_train)
>>> lst = [] # 크기가 데이터셋 크기와 같은지 확인하기 위한 리스트
>>> for idx in index_list:

# 중복 인덱스가 있으면 안되기 때문에 제거하기 위한 코드 
>>>     idx = list(set(idx)) 
>>>     lst.extend(idx) # 리스트에 담기


# 중복 제거
>>> lst = list(set(lst)) 

# 크기가 데이터셋 크기와 같고(즉 234개면 성공), 인덱스 최대값이 233 이고, 최소값이 0 이면 성공!!

>>> print(f"리스트 크기: {len(lst)}")
>>> print(f"최대값: {max(lst)}")
>>> print(f"최소값: {min(lst)}")

리스트 크기: 234
최대값: 233
최소값: 0

 

 

 

시계열 학습데이터 만들기

- 다음의 데이터는 2021년도 삼성 주식 데이터이다.
- 열부분은 시작가 ,상한가 , 하한가, 종가 순으로 되어있다.
- 행은 2021년도 거래 일자이다.

 

>>> samsung_stock = np.load("samsung_stock_2021.npy")
>>> samsung_stock.shape
(248, 4)

# 뒤에 5행만 확인해보기
>>> samsung_stock[-5:]

array([[80200, 80800, 80200, 80500],
       [80600, 80600, 79800, 80200],
       [80200, 80400, 79700, 80300],
       [80200, 80200, 78500, 78800],
       [78900, 79500, 78100, 78300]])

 

 

 

시계열 학습데이터 형태로 반환하는 함수를 만드시오.

- samsung_stock 변수의 데이터는 2차원 데이터이다.
- 학습데이터는 행별로 10일치의 행과 4열(시작가 ,상한가 , 하한가, 종가) 형태의 행렬을 담고 있는 3차원 형태의 데이터셋으로 변경하시오.
- 정답데이터는 미래의 5일치의 종가를 예측해야 한다는 가정하에 행별로 미래의 5일치의 종가가 담긴 2차원 형태의 데이터셋으로 변경하시오.
- 1일씩 이동하면서 데이터셋을 구성하시오.

 

# 일반적인 방법
>>> def transform_data(samsung_stock,seq_len=10,pred_len=5):
>>>     x_train = []
>>>     y_train = []
>>>     for i in range(seq_len,samsung_stock.shape[0] + 1  - pred_len): #  마지막 하나가 빠짐... 1 더해주기
>>>         x = samsung_stock[i-seq_len:i] 
>>>         y = samsung_stock[i:i+pred_len,3] 
>>>         x_train.append(x)
>>>         y_train.append(y)

>>>     x_train = np.array(x_train)
>>>     y_train = np.array(y_train)

>>>     return x_train , y_train

 

 

# 실행 결과 검증
>>> x_train , y_train = transform_data(samsung_stock)
>>> x_train.shape, y_train.shape
((234, 10, 4), (234, 5))

>>> x_samsung_stock = np.load("samsung_stock_2021_3d.npy")
>>> y_samsung_stock = np.load("y_train.npy")
>>> np.all(x_samsung_stock == x_train) , np.all(y_samsung_stock == y_train) 

# 둘다 True 가 나와야 성공!!
(True, True)

 

 

 

 

강사님 스타일

 

# 강사님 스타일
>>> def transform_data(samsung_stock,seq_len=10,pred_len=5):
>>>     window_size = seq_len + pred_len
>>>     window_arr = [
>>>         samsung_stock[i-window_size:i]
>>>         for i in range(window_size ,samsung_stock.shape[0] + 1) 
        #  마지막 하나가 빠짐... 1 더해주기
>>>     ]

>>>     window_arr = np.array(window_arr)
>>>     x_train = window_arr[:,:seq_len]
>>>     y_train = window_arr[:,seq_len:,3]

>>>     return x_train , y_train
    

>>> x_train , y_train = transform_data(samsung_stock)
>>> x_train.shape, y_train.shape
((234, 10, 4), (234, 5))


>>> x_samsung_stock = np.load("samsung_stock_2021_3d.npy")
>>> y_samsung_stock = np.load("y_train.npy")
>>> np.all(x_samsung_stock == x_train) , np.all(y_samsung_stock == y_train)
(True, True)

'파이썬 python > 파이썬 기초 basic' 카테고리의 다른 글

NumPy  (0) 2023.05.23
03 문자열  (0) 2023.05.01
02 컬렉션  (0) 2023.05.01
01 객체와 변수, 기본자료형 연산자  (0) 2023.04.26