0910 k-nearest Neighbor (KNN) 'K - 최근접 이웃'
상당히 간단한 machine learning 알고리즘
NN 앞에 K(숫자)로 몇 개의 이웃이 있는지 정해줘요.
그림에서 지정된 범위의 이웃 중 어떤 색이 더 많은지 분류해서 색을 결정.
KNN은 학습과정이 없어요→ model based learning이 아니에요.
KNN → instance based learning(lazy model)
그러면 regression 경우(모델이 연속적인 값을 예측) 예측할 수 있나요?? 이것도 가능해요!!
단점(어려운 점)
1. K값을 어떻게 설정?
최적의 k값이 어떤 값인지 구할 계산식이 없어서 몰라요 → 찾아야 해요
2. 거리측정은 어떻게 할까?
1) 최단거리 직선 → 유클리디안 거리(Euclidean Distance)
2) 직선(사선은 x) → 맨해튼 거리(Manhattan distance)
3) 분산과 공분산 이용 → 마할라노비스 거리(Mahalanobis distance)
알아내기 위해 노동집약적 작업이 필요!
KNN의 약점
모든 점에 대한 거리를 다 계산해야 해요. → 계산량이 많아요(속도가 느려요)
현업에서 쓰나요?? 많이 써요!!
k=1 인경우 성능이 좋아요.
코드로 알아보아요!
import numpy as np
import pandas as pd
from scipy import stats # zscore을 이용한 이상치 검출 작업을 위해 사용
from sklearn.neighbors import KNeighborsRegressor # ozone량의 NaN값을 예측하기 위해서
from sklearn.preprocessing import MinMaxScaler # Normalization 처리를 위해
import warnings
warnings.filterwarnings(action='ignore') # warning 출력되지 않게 설정
# from sklearn.model_selection import train_test_split
# keras로 구현하기 때문에 keras의 train, validation 분리 기능을 이용해서 학습할 거예요!
# 1.raw data loading
df =pd.read_csv('/content/drive/MyDrive/ozone/ozone.csv')
# display(df)
x_data = df[['Solar.R', 'Wind', 'Temp']] #df
t_data = df['Ozone'] #Series
# 2. 독립변수에 대한 결측치를 찾아내서 각 column의 median 값으로 대체
# x_data.columns 리스트 형태로 나와요
# nanmedian 결치를 제거하고 나머지 값에 대한 중윗값을 알려줘요!
# [x_data[col].isnull()],해당 칼럼에 대한 인덱싱
for col in x_data.columns: #모든 칼럼에 대해 반복 처리
col_median = np.nanmedian(x_data[col]) # 각 column의 NaN을 제외한 중윗값을 알아내요!
x_data[col].loc[x_data[col].isnull()] = col_median # column에 대한 nan column만 뽑아요, 거기의 값을 중윗값으로 세팅
# 3. 독립변수에 이상치를 검출해서 mean으로 처리할 거예요!
zscore_threshold=1.8
# outlier 빼고 나머지 값들의 평균을 구해 outlier 대체
for col in x_data.columns:
outlier=x_data[col][np.abs(stats.zscore(x_data[col])) > zscore_threshold]
col_mean = np.mean(x_data.loc[~x_data[col].isin(outlier), col])
# print(col_mean)
x_data.loc[x_data[col].isin(outlier), col] = col_mean
# 4. 종속변수에 대한 이상치는 mean으로 처리할 거예요!
# => 오존 예제에서 종속변수에 대한 이상치는 없어요!
# 5. 정규화 처리를 먼저 진행
scaler_x = MinMaxScaler()
scaler_t = MinMaxScaler()
scaler_x.fit(x_data.values)
scaler_t.fit(t_data.values.reshape(-1,1)) #fit() 함수는 인자로 2차원 데이터가 들어가야 해요!
x_data_norm = scaler_x.transform(x_data)
t_data_norm = scaler_t.transform(t_data.values.reshape(-1,1)).ravel()
#label은 1차원이기 때문에 정규화를 위해 차원 변환, 정규화 끝나고 다시 1차원으로
# 6. 종속변수에 대한 결측치 처리를 KNN을 이용한 Imputation으로 처리해요.
# KNN을 학습해야 하니까 train data와 label data에서 nan을 제외하고 가져와야 해요!
# np.isnan(t_data_norm) NaN만 true로 나와요 우리는 NaN이 아닌 게 필요. 종속변수에 NaN을 뺄 거예요! ~
# 행에 대해 boolean indexing을 하니까 NaN이 아닌 학습용 데이터만 나와요.
train_x_data_norm = x_data_norm[~np.isnan(t_data_norm)]
train_t_data_norm = t_data_norm[~np.isnan(t_data_norm)]
knn_regressor = KNeighborsRegressor(n_neighbors=2) # Regressor이니 때문에 홀수 짝수 상관없어요.
knn_regressor.fit(train_x_data_norm,train_t_data_norm) # KNN 모델 완성
# NNN을 이용해서 prediction(종속변수가 NaN인 것들에 대해)
knn_predict = knn_regressor.predict(x_data_norm[np.isnan(t_data_norm)])
t_data_norm[np.isnan(t_data_norm)] = knn_predict
x_data_norm
t_data_norm
array([0.23952096, 0.20958084, 0.06586826, 0.10179641, 0.08383234,
...
0.07784431, 0.10179641, 0.11377246])
# 기존에도 ozone data를 이용해서 python구현, sklearn구현, tensorflow구현을 다 했었어요!
# sklearn의 결과와 약간 다른 예측치를 보인 걸로 기억해요!
from sklearn.linear_model import LinearRegression
from tensorflow.keras import Sequential
from tensorflow.keras.layers import Flatten, Dense
from tensorflow.keras.optimizers import SGD
test_data = [[310, 15, 80]] # Solar.R, Wind, Temp
# sklearn 구현
model = LinearRegression()
model.fit(x_data_norm,t_data_norm)
result = model.predict(scaler_x.transform(test_data)) # 1차원
print(scaler_t.inverse_transform(result.reshape(-1,1))) # 2차원 변형
#[[38.75927452]]
# tensorflow 2.x 구현
keras_model = Sequential()
#input_shape=() 들어오는 독립변수 입력
keras_model.add(Flatten(input_shape=(3,)))
keras_model.add(Dense(1, activation='linear')) #output layer
keras_model.compile(optimizer=SGD(learning_rate=1e-2),
loss ='mse') #설정
keras_model.fit(x_data_norm,
t_data_norm,
epochs=5000,
verbose=0)
keras_result = keras_model.predict(scaler_x.transform(test_data))
print(scaler_t.inverse_transform(keras_result.reshape(-1,1)))
#[[38.598263]] sklearn과 거의 비슷해요.
'머신러닝 딥러닝' 카테고리의 다른 글
0914 MNIST_ keras (0) | 2021.09.14 |
---|---|
0914 titanic_keras (0) | 2021.09.14 |
0910 Regression 정리 (0) | 2021.09.10 |
0909 Tensor flow 2.x, keras in tensor 2.x (0) | 2021.09.09 |
0909 multinomial classification - MNIST (0) | 2021.09.09 |
댓글