logistic regression는 분류문제이다
시그모이드 함수에 직선의 함수를 넣어서 결과를 판정한다.
분류 문제는 0 또는 1로 예측해야 하나, linear regression을 그대로 적용하면 예측값()은 0보다 작거나 1보다 큰 값을 가질 수 있다.
그래서 예측값이 항상 0 ~ 1 사이 값을 갖도록 hypothesis 함수를 수정한다.
를
로 수정
그래프를 그려서 logistic function을 간단히 살펴보자
import numpy as np
#함수
z = np.arange(-10, 10, 0.01)
g = 1/(1+np.exp(-z))
#그래프
import matplotlib.pyplot as plt
%matplotlib inline
plt.plot(z, g)
plt.grid()
plt.show()

여러가지 옵션을 줘서 그래프를 그려보자
#sigmoid는 항상 0과 1 사이
plt.figure(figsize=(12,8))
ax = plt.gca() #설정값을 변경하는 함수 gca()
ax.plot(z, g)
ax.spines['left'].set_position('zero') #축을 지정하는 옵션 spines
ax.spines['bottom'].set_position('center')
ax.spines['right'].set_color('none') #나머지는 삭제
ax.spines['top'].set_color('none')
plt.show()

h = np.arange(0.01, 1, 0.01)
C0 = -np.log(1-h)
C1 = -np.log(h)
plt.figure(figsize=(12,8))
plt.plot(h, C0, label='y=0')
plt.plot(h, C1, label='y=1')
plt.legend()
plt.show()

는 주어진 입력 x(종양의 크기)에서 예측 결과가 1(악성)이 될 확률을 의미한다
예를 들어, 가 0.7이면 환자의 종양이 악성일 확률이 70%라는 것
가 0.5보다 크거나 같으면 1(악성)
가 0.5보다 작으면 0(양성)으로 예측

Logistic Reg. Cost Function의 그래프
h = np.arange(0.01, 1, 0.01)
C0 = -np.log(1-h)
C1 = -np.log(h)
plt.figure(figsize=(12,8))
plt.plot(h, C0, label='y=0')
plt.plot(h, C1, label='y=1')
plt.legend()
plt.show()

와인데이터로 실습해보자
#데이터 불러오기
import pandas as pd
wine_url = 'https://raw.githubusercontent.com/PinkWink/ML_tutorial/master/dataset/wine.csv'
wine = pd.read_csv(wine_url, index_col=0)
#taste 컬럼 추가,
wine['taste'] = [1. if grade > 5 else 0. for grade in wine['quality']]
X = wine.drop(['taste', 'quality'], axis=1)
y = wine['taste']
#데이터분리
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=13)
#간단한 로지스틱 회귀 테스트
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score
lr = LogisticRegression(solver='liblinear', random_state=13) # solver : 최적화 알고리즘을 뭘로 할거냐 데이터 수가 작으면 liblinear 선택
lr.fit(X_train, y_train)
y_pred_tr = lr.predict(X_train)
y_pred_test = lr.predict(X_test)
print('Train Acc : ', accuracy_score(y_train, y_pred_tr))
print('Test Acc : ', accuracy_score(y_test,y_pred_test))
Train Acc : 0.7429286126611506
Test Acc : 0.7446153846153846
스케일러까지 적용해서 파이프라인 구축해보자
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
estimators = [
('scaler', StandardScaler()),
('clf', LogisticRegression(solver='liblinear', random_state=13))
]
pipe = Pipeline(estimators)
#fit
pipe.fit(X_train, y_train)
y_pred_tr = pipe.predict(X_train)
y_pred_test = pipe.predict(X_test)
print('Train Acc : ', accuracy_score(y_train, y_pred_tr))
print('Test Acc : ', accuracy_score(y_test, y_pred_test))
Train Acc : 0.7444679622859341
Test Acc : 0.7469230769230769
#Acc가 약간 올라간 것 같다
decision tree와 비교해보자
from sklearn.tree import DecisionTreeClassifier
wine_tree = DecisionTreeClassifier(max_depth=2, random_state=13)
wine_tree.fit(X_train, y_train)
models = {
'logistic regression': pipe,
'decision tree': wine_tree
}
#AUC 그래프를 이용하여 모델간 비교
from sklearn.metrics import roc_curve
plt.figure(figsize=(18,8))
plt.plot([0,1], [0,1], label='random guess')
for model_name, model in models.items():
pred = model.predict_proba(X_test)[:, 1] #첫번째 컬럼은 0일 확률, 두번째 컬럼은 1일 확률
fpr, tpr, thresholds = roc_curve(y_test, pred)
plt.plot(fpr, tpr, label=model_name)
plt.grid()
plt.legend()
plt.show()
LogisticRegression이 decision tree보다 성능이 좋다는 것을 알 수 있다.
#데이터 불러오기
import pandas as pd
pima_url = 'https://raw.githubusercontent.com/PinkWink/ML_tutorial/master/dataset/diabetes.csv'
pima = pd.read_csv(pima_url)

#float형으로 데이터형 변환
pima = pima.astype('float')
#상관관계 확인
import seaborn as sns
import matplotlib.pyplot as plt
plt.figure(figsize=(12,10))
sns.heatmap(pima.corr(), cmap='YlGnBu')
plt.show()
outcome과 연관성이 높은 컬럼들이 몇몇 보인다.
0인 데이터들 확인해보자
0이 되면 이상한 데이터들 변경,
일단 정보가 없으니 그 컬럼의 평균값으로 대체
zero_features = ['Glucose', 'BloodPressure', 'SkinThickness', 'BMI']
pima[zero_features] = pima[zero_features].replace(0, pima[zero_features].mean())
#데이터 나누기
from sklearn.model_selection import train_test_split
X = pima.drop(['Outcome'], axis=1)
y = pima['Outcome']
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=13, stratify=y)
#pipeline 만들기
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression
estimators = [
('scaler', StandardScaler()),
('clf', LogisticRegression(solver='liblinear', random_state=13))
]
pipe_lr = Pipeline(estimators)
pipe_lr.fit(X_train, y_train)
pred = pipe_lr.predict(X_test)
#몇몇 수치 확인
from sklearn.metrics import accuracy_score, recall_score, precision_score
from sklearn.metrics import roc_auc_score, f1_score
print('Accuracy : ', accuracy_score(y_test, pred))
print('Recall : ', recall_score(y_test, pred))
print('Precision : ', precision_score(y_test, pred))
print('AUC score : ', roc_auc_score(y_test, pred))
print('F1 score : ', f1_score(y_test, pred))
Accuracy : 0.7727272727272727
Recall : 0.6111111111111112
Precision : 0.7021276595744681
AUC score : 0.7355555555555556
F1 score : 0.6534653465346535
위 값들은 상대적인 값이 아니므로 수치자체를 평가하기는 어렵다
여기서 outcome을 제외한 8개 변수가 있다.
이 8개 변수의 계수를 확인해보자
#다변수 방정식의 각 계수 값을 확인할 수 있다
coef = list(pipe_lr['clf'].coef_[0])
labels = list(X_train.columns)
#pipe_lr['clf'].coef_
array([[ 0.35426589, 1.20142444, -0.15840136, 0.03394658, -0.16286472,
0.62040452, 0.36669356, 0.17195965]])

중요한 feature에 대해 그려보자
features = pd.DataFrame({'Features':labels, 'importance':coef})
features.sort_values(by=['importance'], ascending=True, inplace=True)
features['positive'] = features['importance'] > 0
features.set_index('Features', inplace=True)
#그림그리기
features['importance'].plot(kind='barh',
figsize=(11,6),
color=features['positive'].map({True:'blue', False:'red'})
)
plt.xlabel('importance')
plt.show()

포도당, BMI 등은 당뇨에 영향을 미치는 정도가 높다
혈압은 예측에 부정적 영향을 준다
연령은 BMI보다 출력 변수와 더 관련이 있었지만, 모델은 BMI와 Glucose에 더 의존함
와인데이터를 불러와서 간단한 로지스틱 회귀를 적용하면
import pandas as pd
wine_url = 'https://raw.githubusercontent.com/PinkWink/ML_tutorial/master/dataset/wine.csv'
wine = pd.read_csv(wine_url, index_col=0)
wine['taste'] = [1. if grade > 5 else 0. for grade in wine['quality']]
X = wine.drop(['taste', 'quality'], axis=1)
y = wine['taste']
#데이터분리
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random
#간단한 로지스틱 회귀 적용
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score
lr = LogisticRegression(solver='liblinear', random_state=13)
lr.fit(X_train, y_train)
y_pred_tr = lr.predict(X_train)
y_pred_test = lr.predict(X_test)
print('Train Acc : ', accuracy_score(y_train, y_pred_tr))
print('Test Acc : ', accuracy_score(y_test, y_pred_test))
Train Acc : 0.7429286126611506
Test Acc : 0.7446153846153846
from sklearn.metrics import classification_report
print(classification_report(y_test, lr.predict(X_test)))

from sklearn.metrics import confusion_matrix
confusion_matrix(y_test, lr.predict(X_test))

import matplotlib.pyplot as plt
from sklearn.metrics import precision_recall_curve
%matplotlib inline
plt.figure(figsize=(18,8))
pred = lr.predict_proba(X_test)[:,1] #클래스 별로 계산
precisions, recalls, thresholds = precision_recall_curve(y_test, pred)
plt.plot(thresholds, precisions[:len(thresholds)], label='precisions')
plt.plot(thresholds, recalls[:len(thresholds)], label='recalls')
plt.grid()
plt.legend()
plt.show()

threshold의 변화에 따라 0, 1 결과가 바뀌게 됨


이런 방식으로 threshold 변경을 잘 사용하지는 않는다.
앙상블 학습을 통한 분류 : 여러 개의 분류기를 생성하고 그 예측을 결합하여 정확한 최종 예측을 기대하는 기법
다양한 분류기의 예측 결과를 결합하여 단일 분류기보다 신뢰성이 높은 예측 값을 얻는 것을 기대한다.
현재 정형데이터를 대상 분류기에서는 앙상블 기법이 효과적이다.
앙상블은 전통적으로 voting, bagging, boosting, 스태깅 등으로 나눈다.
보팅, 배깅은 여러개의 분류기가 투표를 통해 최종 예측 결과를 결정하는 방식
보팅은 각각 다른 분류기, 배깅은 같은 분류기를 사용
대표적인 배깅 방식이 랜덤포레스트
voting은 data set 전체를 여러가지 분류기로 돌리는 방식
bagging에서 데이터는 전체 data set가 아닌 샘플링한 data set이고, 중복을 허용한다. 그리고 한 종류의 분류기를 여러개 돌려서 투표로 결정
위 방식에서 최종 결정을 하기 위한 voting 방식은
다수결의 원칙과 비슷한 하드보팅, 확률의 평균값을 이용한 소프트 보팅이 있다.
IMU 센서를 활용해서 사람의 행동을 인식하는 실험을 통해 데이터가 수집됨


시간 영역 데이터를 머신러닝에 적용하기 위해 여러 통계적 데이터로 변환하였다.
시간 영역의 평균, 분산, 피크, 중간 값,
주파수 영역의 평균, 분산 등
이러한 수치를 뽑아내는 것을 특징 추출이라 한다.
이제 HAR 데이터를 살펴보자
import pandas as pd
import matplotlib.pyplot as plt
%matplotlib inline
url = 'https://raw.githubusercontent.com/PinkWink/ML_tutorial/master/dataset/HAR_dataset/features.txt'
feature_name_df = pd.read_csv(url, sep='\s+', header=None,
names=['column_index', 'column_name'])

column_name 컬럼에서 t : 시간, f : 주파수
feature_name = feature_name_df.iloc[:,1].values.tolist() #column_name의 데이터만 추출하고 리스트형으로 바꿔라
X, y 데이터가 나눠져 있어서 이를 읽어온다
# X 데이터 읽어오기
X_train_url = 'https://raw.githubusercontent.com/PinkWink/ML_tutorial/master/dataset/HAR_dataset/train/X_train.txt'
X_test_url = 'https://raw.githubusercontent.com/PinkWink/ML_tutorial/master/dataset/HAR_dataset/test/X_test.txt'
X_train = pd.read_csv(X_train_url, sep='\s+', header=None)
X_test = pd.read_csv(X_test_url, sep='\s+', header=None)
#컬럼명 지정
X_train.columns = feature_name
X_test.columns = feature_name
# y 데이터 읽어오기
y_train_url = 'https://raw.githubusercontent.com/PinkWink/ML_tutorial/master/dataset/HAR_dataset/train/y_train.txt'
y_test_url = 'https://raw.githubusercontent.com/PinkWink/ML_tutorial/master/dataset/HAR_dataset/test/y_test.txt'
y_train = pd.read_csv(y_train_url, sep='\s+', header=None, names=['action'])
y_test = pd.read_csv(y_test_url, sep='\s+', header=None, names=['action'])
데이터 확인


#결정나무
from sklearn.tree import DecisionTreeClassifier
from sklearn.metrics import accuracy_score
dt_clf = DecisionTreeClassifier(max_depth=4, random_state=13)
dt_clf.fit(X_train, y_train)
pred = dt_clf.predict(X_test)
accuracy_score(y_test, pred)
0.8096369189005769
max_depth를 다양하게 하기 위해 GridSearchCV 이용해보자
from sklearn.model_selection import GridSearchCV
params = {
'max_depth' : [6,8,10,12,16,20,24]
}
grid_cv = GridSearchCV(dt_clf, param_grid=params, scoring='accuracy',
cv=5, return_train_score=True)
grid_cv.fit(X_train, y_train)

max depth 값을 여러개 지정해서 돌려보자
#max depth를 표로 정리
cv_results_df = pd.DataFrame(grid_cv.cv_results_)
cv_results_df = cv_results_df[['param_max_depth', 'mean_test_score', 'mean_train_score']]
#cv_results_df :
Index(['mean_fit_time', 'std_fit_time', 'mean_score_time', 'std_score_time',
'param_max_depth', 'params', 'split0_test_score', 'split1_test_score',
'split2_test_score', 'split3_test_score', 'split4_test_score',
'mean_test_score', 'std_test_score', 'rank_test_score',
'split0_train_score', 'split1_train_score', 'split2_train_score',
'split3_train_score', 'split4_train_score', 'mean_train_score',
'std_train_score'],
dtype='object')

#실제 test 데이터에서 결과
max_depths = [6, 8, 10, 12, 16, 20, 24]
for depth in max_depths:
dt_clf = DecisionTreeClassifier(max_depth=depth, random_state=13)
dt_clf.fit(X_train, y_train)
pred = dt_clf.predict(X_test)
accuracy = accuracy_score(y_test, pred)
print('Max_Depth : ', depth, ', Accuracy : ', accuracy)

랜덤포레스트에 적용해보자
#랜덤포레스트 적용
from sklearn.model_selection import GridSearchCV
from sklearn.ensemble import RandomForestClassifier
params = {
'max_depth' : [6, 8, 10],
'n_estimators' : [50, 100, 200], #나무 몇개 쓸지
'min_samples_leaf' : [8, 12], #leaf 오는 최소 데이터 개수
'min_samples_split' : [8, 12] #분할시킬 때 분할기준에서 최소한으로 남는 데이터 개수
}
rf_clf = RandomForestClassifier(random_state=13, n_jobs=-1) #n_jobs : cpu core를 몇개 쓸건지, -1은 모두사용옵션
grid_cv = GridSearchCV(rf_clf, param_grid=params, cv=2, n_jobs=-1)
grid_cv.fit(X_train, y_train)
결과 성능이 좋아보인다.


561개 특성은 너무 많기 때문에 중요 특성을 파악해보자
#중요 특성 확인
best_cols_Values = rf_clf_best.feature_importances_
best_cols = pd.Series(best_cols_Values, index=X_train.columns)
top20_cols = best_cols.sort_values(ascending=False)[:20]
#주요 특성 관찰
import seaborn as sns
plt.figure(figsize=(8,8))
sns.barplot(x=top20_cols, y=top20_cols.index)
plt.show()

#20개 특성만 가지고 다시 성능 확인
X_train_re = X_train[top20_cols.index]
X_test_re = X_test[top20_cols.index]
rf_clf_best_re = grid_cv.best_estimator_
rf_clf_best_re.fit(X_train_re, y_train.values.reshape(-1,))
pred1_re = rf_clf_best_re.predict(X_test_re)
accuracy_score(y_test, pred1_re)
0.8177807940278249
561개 특성에 비해 20개의 특성만 보면 accuracy는 낮지만 속도가 아주 빠르다!