본문 바로가기
머신러닝 딥러닝

0831 정규화(Normalization)

by 대금부는개발자 2021. 8. 31.
SMALL

 

정규화(Normalization) - 데이터(training data set)가 가진 sacle이 심하게 차이가 나는 경우 학습이 잘 이루어지지 않아요! → scale을 맞추어주는 작업이 필요 → Normalization(있는 그대로의 숫자를 가지고 판단을 하는 게 아닌 의미를 가지고 판단, 척도, 중요도를 비율적으로 잡아줌)

 

집의 가격  방의 개수 1~ 20                     1 ~ 10

집의 월별 연식 1~ 240                           1~ 240 (20년)

 

Normalization의 2가지 방식

 

Min Max Normalization

 

Z-score Normalization(표준화, standardization )

 

 

가장 일반화된 Normalization 방식은 Min Max Normalization이에요.

모든 특성(feature, ex) 온도, 습도, 태양광 등등)에 대해 최솟값 0과 최댓값 1 사이의 값으로 변환(scaling) 시켜주는 것이에요

 

.

 

편하고 쉬운 대표적 정규화 방법이에요. 하지만 기본적으로 최대 최솟값을 사용하기 때문에 이상치가 들어가 있으면 전체 데이터가 망가져요. →  이상치에 상당히 민감해서 이상치 처리가 선행되어야 해요.

 

 

Z-score Normalization

 

 

변환시킨 값은 평균을 빼기 때문에 음수, -값이 나올 수 있어요. 표준편차는 분산의 제곱 근이기에 양수예요.
그리고 동일한 척도가 아니기 때문에 0~ 1 사이 값이 아니에요!

평균과 표준편차를 이용하기 때문에 이상치에 덜 민감해요.  → 이상치에 상대적으로 관대해요.

 

 

sklearn은 자체적으로 Normalization 작업이 진행돼요! 그래서 python 코드랑 동일한 결과를 내지 못했어요!

 

위의 두 가지 방식을 python 코드로 알아보아요!!

 

일단 reset

 

 

 

 

 

 

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn import linear_model
from scipy import stats   #z scoe 값 계산해주는 함수
from sklearn.preprocessing import MinMaxScaler  # preprocessing 전처리 관련 모듈 중에 MinMaxScaler 호출

## 그래프##
fig = plt.figure() # 도화지를 나눠요

fig_python = fig.add_subplot(1,2,1) # 1행 2열 첫 번째 subplot 영역 추가
fig_sklearn = fig.add_subplot(1,2,2) # 1행 2열 오른쪽

fig_python.set_title('Using python') # 제목
fig_sklearn.set_title('Using sklearn')
###

# 1. 수치 미분을 수행할 함수
def numerical_derivative(f, x):
    # f : 미분을 하려고 하는 함수
    # x : 모든 독립변수의 값을 포함하고 있는 ndarray(차원에 무관하게 처리할 수 있어야 해요!)
    
    delta_x = 1e-4
    derivative_x = np.zeros_like(x)  
    
    it = np.nditer(x, flags=['multi_index'])
    
    while not it.finished:
        
        idx = it.multi_index
        
        tmp = x[idx]    
        
        # 중앙 차분으로 수치 미분하는 식 : (f(x + delta_x) - f(x-delta_x)) / 2 * delta_x
        
        x[idx] = tmp + delta_x   
        fx_plus_deltax = f(x)
        
        x[idx] = tmp - delta_x   
        fx_minus_deltax = f(x)
        
        derivative_x[idx] = (fx_plus_deltax - fx_minus_deltax) / (2 * delta_x)
        
        x[idx] = tmp     
        
        it.iternext()

    return derivative_x

############################

# Raw Data Loading (정제되지 않는 수집한 데이터 불러오기)
df = pd.read_csv('./data/ozone/ozone.csv', sep=',')


training_data_set = df[['Temp','Ozone']]   #fancy indexing, # 독립변수가 1개 'Temp' 종속변수 'Ozone'

# display(training_data_set.head())

# 1. 결치값부터 처리해야 해요!
# 상대적으로 데이터가 적고 데이터가 많을 때는 지우는 게 최적이지만 그 외에는 데이터의 손실이 발생해요!
# 그다음 대안은 다른 값으로 대치, 보정해줘요! 일단은 지우고 진행할게요.

training_data  = training_data_set.dropna(how='any') # any는 NaN 포함된 행 다 지워요.
display(training_data)   # 116 rows × 2 columns

# 2. 이상치를 처리해야 해요. 지대점(온도) 날리고 outlier(오존) 날릴 거예요.

# 일반적으로 이상치라고 하는 것은 Label(종속변수)에 대한 이상치를 outlier라고 해요.

# 입력데이터, 독립변수에도 이상치(지대점)가 개념이 존재해요

#지대점 - 독립변수의 이상치를 지대점이라고 합니다.
# 현재 데이터 기준으로 이상치를 판단, 전체를 보고 이상치를 판단하는 거랑 하나가 띄어진 상태에서 이상치 처리하는 것은 다른 결과가 나와요.
# 지대점(x축) 포함? 불포함 이상치에 대한 기준점 handling 선택

# 이상치 처리  2.0으로 잡으면 정규분포로 봤을 때 97.7% 이상의 극단이기에 1.8 정도로 잡을게요!
# 기준점(threshold)
zscore_threshold = 1.8

# Temp(온도)에 대한 이상치(지대점) 처리

# np.abs(stats.zscore(training_data['Temp'])) > zscore_threshold
# 절대값 abs로 바꿔 1.8에 대한 비교 연산을 해서 Mask 생성
# False 는 크지 않기 때문에 지대 값이 아니에요!

outlier = training_data['Temp'][np.abs(stats.zscore(training_data['Temp'])) > zscore_threshold]
#True 부분만 찾아내요

print(outlier) # 지대점

 

#7      59
#14     58
#17     57
#20     59
#119    97
#121    96
#Name: Temp, dtype: int64

 

#training_data.loc[~(training_data['Temp'].isin(outlier))]

 # ~ 은 not의 의미 각각의 isin 값이 안에 있니? 논리 값을 역으로 False 지대점

 

 

 

 

 

training_data = training_data.loc[~(training_data['Temp'].isin(outlier))]

 

 

#Ozone에 대한 이상치(outlier) 처리
outlier = training_data['Ozone'][np.abs(stats.zscore(training_data['Ozone'])) > zscore_threshold]
training_data = training_data.loc[~(training_data['Ozone'].isin(outlier))] 
display(training_data) # 103 rows × 2 columns

 

 

# 3. 정규화(Normalization) -  Min Max Normalization
temp_max =  training_data['Temp'].max()
print(temp_max) # 94
temp_min =  training_data['Temp'].min()
print(temp_min) # 61
tmp = temp_max - temp_min  # 분모

(training_data['Temp']- temp_min) / tmp

 

#0      0.181818
#1      0.333333
#2      0.393939
#3      0.030303
#5      0.151515
         ...   
#147    0.060606
#148    0.272727
#150    0.424242
#151    0.454545
#152    0.212121
#Name: Temp, Length: 103, dtype: float64

 

 

이렇게 해도 돼요! 

하지만 학습용 Data Set을 만들어 봐요.

 

# 3. 정규화(Normalization) -  Min Max Normalization

# scaling 작업을 수행하는 객체를 하나 생성(입력값 처리 , Label처리 총 두 개 생성)
scaler_x = MinMaxScaler()  #입력값('Temp'에 대한 min max scaling class객체 
scaler_y = MinMaxScaler()

scaler_x.fit(training_data['Temp'].values.reshape(-1,1)) #데이터 개수, 최대, 최소 같은 값들이 scaler에 저장
#온도에대한 data를 2차원 형태로 fit 해줘요.아직은 정보가 없어요.
# 컬럼이 정해져 있기때문에 행을 세지 않고 -1을 써요.

scaler_y.fit(training_data['Ozone'].values.reshape(-1,1)) # scaler_y에도 적용

# scaling 할때는 transform 함수를 이용해요
training_data['Temp'] = scaler_x.transform(training_data['Temp'].values.reshape(-1,1))
#원래 데이터 날리고 변환된 데이터 가져요 
training_data['Ozone'] = scaler_y.transform(training_data['Ozone'].values.reshape(-1,1))

display(training_data)

 

 

#Training Data Set


x_data = training_data['Temp'].values.reshape(-1,1)
t_data = training_data['Ozone'].values.reshape(-1,1)

# Weight & bias를 정의
W = np.random.rand(1,1)
b = np.random.rand(1)

def predict(x):     #python 으로 구현한 linear모델 예측함수
    
    return np.dot(x,W) + b    # y = Wx + b


def loss_func(input_obj):  # 편미분 함수 [W의 값, b의 값], 1행1열 1차원 ndarray 
    
    input_w = input_obj[0].reshape(-1,1)   # 행렬곱연산을 수행해야 하니까 2차원으로 표현
    input_b = input_obj[1]
    
   # 평균제곱오차를 구해야 해요! => loss함수의 값.
    
    y = np.dot(x_data,input_w) + input_b  # 입력값에 대해 현재 W와 b를 이용한 예측치 계산
    
    return np.mean(np.power((t_data-y),2))


learning_rate = 1e-4#ㅣoss값을 보고 조절해야하는 값

# 반복학습을 진행해야해요.

for step in range(300000):
    
    input_param = np.concatenate((W.ravel(), b.ravel()), axis=0)
    # def loss_func(input_obj)로 들어가야하기때문에 1차원으로 연결
    result_derivative = learning_rate * numerical_derivative(loss_func,input_param)
    
    W = W - result_derivative[0].reshape(-1,1)
    b = b - result_derivative[1]
    
    if step % 30000 == 0:
        print('loss : {}'.format(loss_func(input_param))  # loss : 0.028423382676837344

 

# 학습이 끝났으니 Prediction을 해 보아요!

# print(predict([[62]]))    # [[48.74690939]]   ???? 많이 이상해요!!! ㅡㅜ 당연히 이상한거예요!
scaled_predict_data = scaler_x.transform([[62]])
print(scaled_predict_data)
scaled_result = predict(scaled_predict_data)    ## [[-0.02019973]]  ?? 이게 최종 예측값인가요??

# y에 대해서 원래값으로 복구해야해요!
print(scaler_y.inverse_transform(scaled_result))   ##[[2.12142534]]

# sklearn을 이용한 구현

df = pd.read_csv('./data/ozone/ozone.csv', sep=',')

training_data_set = df[['Temp', 'Ozone']]
# display(training_data_set.head())

# 1. 결치값부터 처리해야 해요!
training_data = training_data_set.dropna(how='any')

# 2. 이상치를 처리해야 해요!
zscore_threshold = 1.8

# Temp에 대한 이상치(지대점) 처리 - 지대점 : 독립변수의 이상치를 지대점이라고 합니다.

outlier = training_data['Temp'][np.abs(stats.zscore(training_data['Temp'])) > zscore_threshold]
# print(outlier)  #  지대점

training_data = training_data.loc[~(training_data['Temp'].isin(outlier))]   # 110 rows × 2 columns

# Ozone에 대한 이상치(outlier) 처리
outlier = training_data['Ozone'][np.abs(stats.zscore(training_data['Ozone'])) > zscore_threshold]
training_data = training_data.loc[~(training_data['Ozone'].isin(outlier))]   

model = linear_model.LinearRegression()

model.fit(training_data['Temp'].values.reshape(-1,1), 
          training_data['Ozone'].values.reshape(-1,1))

result = model.predict([[62]])   # [[3.58411393]]


print(result)

## 그래프를 그려보아요!
#################################
fig = plt.figure()

fig_python = fig.add_subplot(1,2,1)
fig_sklearn = fig.add_subplot(1,2,2)

fig_python.set_title('Using Python')
fig_sklearn.set_title('Using sklearn')
#################################

fig_python.scatter(x_data,t_data)
fig_python.plot(x_data, x_data*W.ravel() + b, color='r')

fig_sklearn.scatter(training_data['Temp'].values, 
                    training_data['Ozone'].values)
fig_sklearn.plot(training_data['Temp'].values, 
                 training_data['Temp'].values*model.coef_.ravel() + model.intercept_, color='g') 

                                                       #coef_  가중치 , intercept_ 편향

fig.tight_layout()
plt.show()

 

 

 

LIST

'머신러닝 딥러닝' 카테고리의 다른 글

0901 TensorFlow  (0) 2021.09.01
0831 MultipleLlinear Regression  (0) 2021.08.31
0830 linear regression 데이터 전처리  (0) 2021.08.30
0827Machine Learning에서Linear Regression  (0) 2021.08.27
0826 회귀(regression )  (0) 2021.08.26

댓글