데이터 정의
[R/머신러닝/실습] 로지스틱 회귀 분석
데이터 정의 사용 데이터: weather.csv 기상 관측 자료를 날짜별, 항목별로 기록한 자료이다. 각 항목에 따라 다른 자료형과 단위를 포함한다. 독립변수는 RainTomorrow 이며, 종속변수는 Date부터 RainToda
robinlovesyeon.tistory.com
위 링크 참고
로지스틱 회귀 분석
1) 데이터 호출 및 전처리
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.preprocessing import LabelEncoder
raw_data = pd.read_csv('weather.csv',encoding='cp949')
raw_data.drop(['Date'],axis=1,inplace=True)
le = LabelEncoder()
cat_cols = ['WindGustDir', 'WindDir', 'RainToday','RainTomorrow']
raw_data[cat_cols] = raw_data[cat_cols].apply(le.fit_transform)
from sklearn.preprocessing import MinMaxScaler
scaler = MinMaxScaler()
cols = ['MinTemp', 'MaxTemp', 'Rainfall', 'Sunshine', 'WindGustDir',
'WindGustSpeed', 'WindDir', 'WindSpeed', 'Humidity', 'Pressure',
'Cloud', 'Temp', 'RainToday', 'RainTomorrow']
raw_data[cols] = scaler.fit_transform(raw_data[cols])
v=list(range(1,len(raw_data)+1))
s=SyncRNG(seed=42)
ord=s.shuffle(v)
idx=ord[:round(len(raw_data)*0.7)]
for i in range(0,len(idx)):
idx[i]=idx[i]-1
train=raw_data.loc[idx] # 70%
test=raw_data.drop(idx) # 30%
train=raw_data.dropna()
test=raw_data.dropna()
x_train = np.array(train.iloc[:,0:13], dtype=np.float32)
y_train = np.array(train.iloc[:,-1], dtype=np.float32)
x_test = np.array(test.iloc[:,0:13], dtype=np.float32)
y_test = np.array(test.iloc[:,-1], dtype=np.float32)
R에서와 마찬가지로 DATE 변수를 제거했으며, 범주형 변수는 인코딩하고 나머지 변수들은 최소-최대 정규화를 실시했다. syncRNG 함수를 사용하여 R과 같은 seed값으로 정확한 비교를 할 수 있게끔 설정했다. 추가로 로지스틱 회귀모델을 수행하는 클래스에서는 numpy 연산이 사용되므로 학습데이터와 테스트데이터를 array로 변경했다.
2) 모델 생성
class SingleLayer:
def __init__(self):
self.w = None
self.b = None
self.losses = []
def forpass(self, x):
z = np.sum(x * self.w) + self.b # 직선 방정식을 계산합니다
return z
def backprop(self, x, err):
w_grad = x * err # 가중치에 대한 그래디언트를 계산합니다
b_grad = 1 * err # 절편에 대한 그래디언트를 계산합니다
return w_grad, b_grad
__init()__메서드는 추후 입력 데이터의 특성 개수에 맞게 결정하기 위해 가중치를 미리 초기화하지 않았다. 그리고 손실 함수의 결과값이 줄어드는지를 관찰하기 위해 self.losses 리스트를 만들었다.
또한 로지스틱 회귀는 정방향 계산과 가중치를 업데이트하기 위한 역방향 계산(오차 역전파)이 필요하다. 이를 위해 forpass, backprop 메서드를 구현했다. backprop 메서드를 통해 가중치와 절편이 업데이트되어 점차 최적화된 가중치와 절편을 얻을 것이다.
def activation(self, z):
z = np.clip(z, -100, None) # 안전한 np.exp() 계산을 위해
a = 1 / (1 + np.exp(-z)) # 시그모이드 계산
return a
def fit(self, x, y, epochs=500):
self.w = np.ones(x.shape[1]) # 가중치를 초기화합니다.
self.b = 0 # 절편을 초기화합니다.
for i in range(epochs): # epochs만큼 반복합니다
loss = 0
# 인덱스를 섞습니다
indexes = np.random.permutation(np.arange(len(x)))
for i in indexes: # 모든 샘플에 대해 반복합니다
n = len(x)
z = self.forpass(x[i]) # 정방향 계산
a = self.activation(z) # 활성화 함수 적용
err = -(y[i] - a) # 오차 계산
w_grad, b_grad = self.backprop(x[i], err) # 역방향 계산
self.w -= w_grad # 가중치 업데이트
self.b -= b_grad # 절편 업데이트
# 안전한 로그 계산을 위해 클리핑한 후 손실을 누적합니다
a = np.clip(a, 1e-10, 1 - 1e-10)
loss += -(y[i] * np.log(a) + (1 - y[i]) * np.log(1 - a))
# 에포크마다 평균 손실을 저장합니다
self.losses.append(loss / len(y))
activation 메서드는 z를 0~1사이의 확률값으로 변환시키기 위한 시그모이드 함수, 즉 활성화 함수 역할을 한다.
시그모이드 함수는 오즈비를 기반으로 하므로 이에 따라 계산식을 만들었다.
fit은 훈련을 수행하는 메서드로, 먼저 에포크마다 인덱스를 무작위로 섞음으로써 손실 함수를 줄여 성능 향상을 했다. 그리고 로지스틱 회귀분석의 과정에 따라 정방향 계산과 역방향 계산, 가중치와 절편 업데이트, 마지막으로 손실 누적까지의 과정을 모든 샘플에 대해 반복한다.
def predict(self, x):
z = [self.forpass(x_i) for x_i in x] # 정방향 계산
return np.array(z) > 0 # 스텝 함수 적용
def proba(self,x): #ROC 커브용 확률출력 메서드
z = [self.forpass(x_i) for x_i in x]
return np.array(z)
def score(self, x, y):
return np.mean(self.predict(x) == y)
layer = SingleLayer()
layer.fit(x_train, y_train)
layer.score(x_test, y_test)
layer.predict(x_test)
여러 개의 샘플(활성화 함수, 임계 함수)을 적용한 예측값을 얻기 위해 predict 메서드를 만들었다. 선형 함수(z)가 0보다 크면 시그모이드 함수의 출력값이 0.5보다 크므로 시그모이드 함수를 사용하는 대신 선형 함수(z)가 0보다 큰지, 작은지를 비교한다.
ROC curve 시각화를 위해 확률을 출력해주는 porba 메서드를 정의한 후, 정확도를 계산해 주는 score 메서드를 정의했다. 이는 올바르게 예측한 샘플의 비율이 된다.
이렇게 정의한 SingleLayer 클래스를 layer객체로 만들고 훈련 세트로 훈련시켰다.
모델의 정확도는 아래 <모델 평가>에서 확인할 수 있다.
3) 모델 평가
from sklearn.metrics import classification_report
print(classification_report(layer.predict(x_test) , y_test))
precision recall f1-score support
False 0.97 0.91 0.93 316
True 0.54 0.78 0.64 45
accuracy 0.89 361
macro avg 0.75 0.84 0.79 361
weighted avg 0.91 0.89 0.90 36
from sklearn.metrics import roc_auc_score
print('ROC auc value : {}'.format(roc_auc_score(y_test,layer.predict(x_test))))
#ROC auc value : 0.7523388773388773
분류 모델을 리포트한 결과 정확도는 0.89로 출력됐다. 또한 ROC auc value는 0.75이다.
4) 시각화
# 손실 함수 누적값
plt.plot(layer.losses)
plt.xlabel('epoch')
plt.ylabel('loss')
plt.show()
# ROC curve
pro=layer.proba(x_test)
from sklearn.metrics import roc_curve
fprs, tprs, thresholds = roc_curve(y_test, pro,pos_label=1)
precisions, recalls, thresholds = roc_curve(y_test, pro,pos_label=1)
plt.figure(figsize=(5,5))
plt.plot(fprs,tprs,label='ROC')
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.show()
손실 누적 그래프를 보면, 로지스틱 손실 함수의 값(loss)이 에포크가 진행됨에 따라 감소하고 있음을 확인할 수 있다. 25 에포크 전에서 급격히 완만해지므로 25 에포크 이상을 진행하면 과적합이 발생할 수 있으므로 유의해야 한다. 오른쪽 ROC curve 의 모양을 살펴보았을 때 아래 영역의 넓이가 넓은 것을 확인할 수 있으며 AUC 값이 0.75로 모델의 성능이 우수하다고 볼 수 있다.
** 로지스틱 회귀분석의 연산 과정에 따라 적절한 객체를 구성해 주면 feature선정을 컴퓨터가 처리했는데, 이는 딥러닝의 특성에 부합한다고 볼 수 있다.
'python > 실습(project)' 카테고리의 다른 글
[Python/딥러닝/실습] Keras를 이용한 다중 분류 분석(인공신경망) (0) | 2023.01.12 |
---|---|
[Python/딥러닝/실습] 단순 선형회귀 분석 (0) | 2023.01.05 |
[Python/실습] 의사결정나무를 이용한 BostonHousing 예측분석 (0) | 2023.01.03 |
[Python/실습] 랜덤포레스트 모델을 이용한 위스콘신 유방암 데이터 분류분석 (0) | 2023.01.02 |
[python/실습] xgboost를 이용한 위스콘신 유방암 데이터 분류분석 (0) | 2022.12.20 |
댓글