github : https://github.com/nalinzip/ml_study
colab : https://colab.research.google.com/drive/14wzHk55v1fJU9m14VuAjW5DaAiyM7-_M?usp=sharing
import sklearn
print(sklearn.__version__)
데이터 세트로 붓꽃의 품종을 분류(Classification)하는 것입니다.
from sklearn.datasets import load_iris
from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import train_test_split
sklearn.datasets = 자체적으로 제공하는 세트를 생성하는 모듈의 모임sklearn.model_selection = 학습 데이터와 검증 데이터 , 예측 데이터로 데이터를 분리하거나 최적의 하이퍼 파라미터로 평가하기 위한 다양한 모듈train_test_split() = 데이터 세트를 학습 데이터와 테스트 데이터로 분리하는 데 사용하는 함수import pandas as pd
# 붓꽃 데이터 세트를 로딩합니다.
iris = load_iris()
# iris.data는 Iris 데이터 세트에서 피처(feature)만으로 된 데이터를 numpy 로 가지고 있습니다.
iris_data = iris.data
#iris.target은 붓꽃 데이터 세트에서 레이블 ( 결정 값 ) 데이터를 numpy 로 가지고 있습니다.
iris_label = iris. target
print('iris target값:', iris_label)
print('iris target?:', iris.target_names)
# 붓꽃 데이터 세트를 자세히 보기 위해 DataFrame 으로 변환합니다.
iris_df = pd.DataFrame(data=iris_data, columns=iris.feature_names)
iris_df[ 'label'] = iris. target
iris_df.head (3)
붓꽃 데이터 세트를 로딩한 후 , 피처들 (sepal length, sepal width, petal length, petal width 가)과 데이터 값이 어떻게 구성되어 있는지를 확인하기 위해 DataFrame 으로 변환.
레이블 (결정값) 은 0, 1, 2
0 = Setosa 품종
1 이 versicolor 품종
2 가 vinginica 품종

train_test_split() API 제공되어 있음 X_train, X_test, y_train, y_test = train_test_split(iris_data, iris_label,
test_size=0.2, random_state=11)
(random_state 는 random값을 만드는 seed와 같은 의미. 숫자 자체는 어떤 값을 지정해도 상관없음)
# DecisionTreeClassifier 객체 생성
dt_clf = DecisionTreeClassifier(random_state=11)
# 학습 수행
dt_clf.fit(X_train, y_train)

- DecisionTreeClassifier를 객체로 생성 (random_state=11 : 동일한 학습 / 예측 결과를 출력하기 위한 용도로만 사용)
# 학습이 완료된 DecisionTreeclassifier 객체에서 테스트 데이터 세트로 예측 수행.
pred = dt_clf.predict(X_test)

accuracy_score() 함수1.데이터 세트 분리 : 데이터를 학습 데이터 vs 테스트 데이터로 분리.
2.모델 학습 : 학습 데이터를 기반으로 ML 알고리즘을 적용해 모델을 학습시킴.
3.예측 수행 : 학습된 ML 모델을 이용해 테스트 데이터의 분류 (즉, 붓꽃 종류) 를 예측.
4.평가 : 이렇게 예측된 결값과 테스트 데이터의 실제 결값을 비교해 ML 모델 성능을 평가.
fit()& predict()sklearn.datasets : 사이킷런에 내장되어 예제로 제공하는 데이터 세트sklearn.preprocessing : 데이터 전처리에 필요한 다양한 가공 기능 제공 (문자열을 숫자sklearn.feature_selection : 알고리즘에 큰 영향을 미치는 피처를 우선순위대로 셀렉션 작sklearn.feature_extraction : 텍스트 데이터나 이미지 데이터의 벡터화된 피처를 추출하는 데 사용됨.sklearn.decomposition : 차원 축소와 관련한 알고리즘을 지원하는 모듈임. PCA, NMF.sklearn.model_selection sklearn.metrics인터넷에서 내려받아 홈 디렉터리 아래의 scikit learn_data라는 서브 디렉터리에 저장한 후 추후 불러들이는 데이터임
인터넷 연결해야 사용할 수 있음
datasets.make_classifications( ) : 분류를 위한 데이터 세트를 만듭니다. 특히 높은 상관도 , 불필요한 속성 등의 노이즈 효과를 위한 데이터를 무작위로 생성해줌.
datasets.make_blobs( ) : 클러스터링을 위한 데이터 세트를 무작위로 생성해줌.
사이킷런에 내
장된 이 데이터 세트는 일반적으로 딕셔너리 형태로 돼 있습니다.
from sklearn.datasets import load_iris
iris_data = load_iris()
print(type(iris_data))
keys = iris_data.keys()
print('붓꽃 데이터 세트의 키들 :', keys)
출력은 아래와 같이 나옴
붓꽃 데이터 세트의 키들 : dict_keys(['data', 'target', 'frame', 'target_names', 'DESCR', 'feature_names', 'filename', 'data_module'])
print('\n feature_names 의 type:', type(iris_data.feature_names))
print('feature_names 의 shape:', len(iris_data.feature_names))
print(iris_data.feature_names)
print('\n target_names 의 type:', type(iris_data.target_names))
print('target_names 의 shape:', len(iris_data. target_names))
print(iris_data.target_names)
print('\n data 의 type:', type(iris_data.data))
print(' data 의 shape:', iris_data.data.shape)
print(iris_data[ 'data'])
print('\n target 의 type:', type(iris_data.target))
print('target 의 shape:'
, iris_data. target.shape)
print(iris_data.target)
출력은 아래와 같이 나옴
feature_names 9 type: (class 'list'>
feature_names 9 shape: 4
['sepal length (cm)', 'sepal width (cm)', 'petal length (cm)', 'petal width (cm) ']
target_names © type: (class 'numpy.ndarray'>
target_names ® shape: 3
['setosa' 'versicolor' 'virginica']
data 9 type: (class 'numpy.ndarray'>
data ° shape: (150, 4)
[[5.1 3.5 1.4 0.2]
[4.9 3. 1.4 0.2]
[6.5 3. 5.2 2. ]
[6.2 3.4 5.4 2.3]
[5.9 3. 5.1 1.8]1
target © type: <class 'numpy.ndarray'>
target © shape: (150, )
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 1 8 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2
2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
2 2]
from sklearn.metrics import accuracy_score
iris = load_iris()
dt_clf = DecisionTreeClassifier()
train_data = iris.data
train_label = iris.target
dt_clf. fit(train_data, train_label)
# 학습 데이터 세트으로 예측 수행
pred = dt_clf.predict(train_data)
print(' 예측 정확도 :', accuracy_score(train_label, pred))
결과
예측 정확도 : 1.0
이미 학습한 학습 데이터 세트를 기반으로 예측했기 때문에 예측 정확도 100% 나오는 경우가 있음.
따라서 전용의 테스트 데이터 세트여야 함.
sklearn.model_selection 모듈에서 train_test_split() 를 통해 쉽게 분리할 수 있음
train_test_split()는 첫 번째 파라미터로 피처 데이터 세트, 두 번째 파라미터로 레이블 데이터 세트를 입력받음.
그리고 선택적으로 다음 파라미터를 입력받음.
test_size: 전체 데이터에서 테스트 데이터 세트 크기를 얼마로 샘플링할 것인가를 결정함.
디폴트는 0.25, 즉 25% 임.
train_size: 전체 데이터에서 학습용 데이터 세트 크기를 얼마로 샘플링할 것인가를 결정함.
텍스트_test_size parameter를 통상적으로 사용하기 때문에 train_size 는 잘 사용되지 않음.
shuffle: 데이터를 분리하기 전에 데이터를 미리 섞을지를 결정함.
디폴트는 True 입니다. 데이터를 분산시켜서 좀 더
효율적인 학습 및 테스트 데이터 세트를 만드는 데 사용됩니다.
random_state: random_state는 호출할 때마다 동일한 학습/테스트용 데이터 세트를 생성하기 위해 주어지는 난수 값임.
train_test_split( )는 호출 시 무작위로 데이터를 분리하므로 random_state 를 지정하지 않으면 수행할 때마다 다른
학습 / 테스트 용 데이터를 생성함.
train_test_split() 의 반환값은 튜플 형태입니다.붓꽃 데이터 세트를 train_test_split()을 이용해서 나누어져 있음
from sklearn. tree import DecisionTreeClassifier
from sklearn.metrics import accuracy_score
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
dt_clf = DecisionTreeClassifier()
iris_data = load_iris( )
X_train, X_test, y_train, y_test = train_test_split(iris_data.data, iris_data.target, \
test_size=0.3, random_state=121)
dt_clf.fit(X_train, y_train)
pred = dt_clf.predict(X_test)
print('예측 정확도 : {0: 4f}'.format(accuracy_score(y_test, pred)))
예측 정확도 : 0.955556
알고리즘을 학습시키는 학습 데이터와 이에 대한 예측 성능을 평가하기 위한 별도의 테스트용 데이터가 필요하지만 과적합 (Overfitting) 에 취약한 약점을 가질 수 있음
학습 데이터에만 과도하게 최적화되어 -> 실제로 예측 시 예측 성능이 과도하게 떨어짐!
일반화된 성능을 갖춘 모델을 만드는 것이 중요.
교차 검증은 이러한 데이터 편중을 막기 위해서 별도의 여러 세트로 구성된 학습 데이터 세트와 검증 데이터 세트에서 학습과 평가를 수행하는 것임.
각 세트에서 수행한 평가 결과에 따라 하이퍼 파라미터 튜닝 등의 모델 최적화를 더욱 손쉽게 할 수 있음.
대부분의 ML 모델의 성능 평가는 교차 검증 기반으로 1차 평가를 한 뒤에 최종적으로 테스트 데이터 세트에 적용해 평가하는 프로세스임.

데이터 세트를 K 등분 (5등분) 합니다.
첫 번째 반복에서는 처음부터 4개 등분을 학습 데이터 세트
마지막 5번째 등분 하나를 검증 데이터 세트로 설정하고 학습 데이터 세트에서 학습 수행, 검증 데이터 세트에서 평가를 수행
첫 번째 평가를 수행하고 나면 이제 두 번째 반복에서 다시 비슷한 학습과 평가 작업을 수행
단, 이번에는 학습 데이터와 검증 데이터를 변경
(처음부터 3개 등분까지, 그리고 마지막 5번째 등분을 학습 데이터 세트로, 4번째 등분 하나를 검증 데이터 세트로 설정).
이렇게 학습 데이터 세트와 검증 데이터 세트를 점진적으로 변경하면서b 마지막 5 번째 (K 번째) 까지 학습과 검증을 수행하는 것이 바로 K 폴드 교차 검증입니다.
5개 (K 개) 의 예측 평가를 구했으면 이를 평균해서 K 폴드 평가 결과로 반영하면 됩니다.
사이킷런에서는 K 폴드 교차 검증 프로세스를 구현하기 위해
KFold와 StratifiedKFold 클래스를 제공합니다.
먼저 KFold 클래스를 이용해 붓꽃 데이터 세트를 교차 검증하고 예측 정확도를 알아보겠습니다.
붓꽃 데이터 세트와 DecisionTreeClassifier 를 다시 생성합니다. 그리고 5 개의 폴드 세트로 분리하는 KFold 객체를 생성합니다.
from sklearn.tree import DecisionTreeClassifier
from sklearn.metrics import accuracy_score
from sklearn.model_selection import KFold
import numpy as np
iris = load_iris()
features = iris.data
label = iris.target
dt_clf = DecisionTreeClassifier(random_state=156)
kfold = KFold(n_splits=5)
cv_accuracy = []
print('붓꽃 데이터 세트 크기 :', features.shape [0])
# 붓꽃 데이터 세트 크기 : 150 출력
n_iter = 0
cv_accuracy = []
# KFold 객체의 split()를 호출하면 폴드별 학습용, 검증용 테스트의 로우 인덱스를 array로 반환
for train_index, test_index in kfold.split(features):
# kfold.split()으로 반환된 인덱스를 이용해 학습용, 검증용 테스트 데이터 추출
X_train, X_test = features[train_index], features[test_index]
y_train, y_test = label[train_index], label[test_index]
# 학습 및 예측
dt_clf.fit(X_train, y_train)
pred = dt_clf.predict(X_test)
n_iter += 1
# 반복 시마다 정확도 측정
accuracy = np.round(accuracy_score(y_test, pred), 4)
train_size = X_train.shape[0]
test_size = X_test.shape[0]
# 출력
print('\n#{} 교차 검증 정확도: {}, 학습 데이터 크기: {}, 검증 데이터 크기: {}'
.format(n_iter, accuracy, train_size, test_size))
print('#{} 검증 세트 인덱스: {}'.format(n_iter, test_index))
cv_accuracy.append(accuracy)
# 평균 검증 정확도 계산
print('\n## 평균 검증 정확도 :', np.mean(cv_accuracy))

KFold(n_splits=5)로 KFold 객체를 생성했으니 Split()을 호출해 전체 붓꽃 데이터를 5 개의 폴드 데이터 세트로 분리.
KFold 객체는 split() 을 호출하면 학습용 / 검증용 데이터로 분할할 수 있는 인덱스를 반환.
전체 붓꽃 데이터는 모두 150개 -> 학습용 데이터 세트는 이 중 4/5 인 120 개, 검증 테스트 데이터 세트는 1/5 인 30 개로 분할됨.
실제로 학습용 / 검증용 데이터 추출은 반환된 인덱스를 기반으로 개발 코드에서 직접 수행해야 함.
본 예제는 5 개의 폴드 세트를 생성하는 KFold 객체의 split()을 호출해 교차 검증 수행 시마다 학습과 검증을 반복해 예측 정확도를 측정함.
- split() 이 어떤 값을 실제로 반환하는지도 확인해 보기 위해 검증 데이터 세트의 인덱스도 추출.
import pandas as pd
from sklearn.datasets import load_iris
iris = load_iris()
iris_df = pd.DataFrame(data=iris.data, columns=iris.feature_names)
iris_df['label']=iris.target
iris_df['label'].value_counts()

from sklearn.model_selection import KFold
kfold = KFold(n_splits=3)
n_iter =0
for train_index, test_index in kfold.split(iris_df):
n_iter += 1
label_train= iris_df ['label'].iloc[train_index]
label_test= iris_df ['label' ].iloc[test_index]
print('# 교차 검증 : {0}'.format(n_iter))
print('학습 레이블 데이터 분포 :Mn', label_train.value_counts())
print(' 검증 레이블 데이터 분포 :M', label_test.value_counts())

교차 검증 시마다 3 개의 폴드 세트로 만들어지는 학습 레이블과 검증 레이블이 완전히 다른 값으로 추출됨.
예를 들어 첫 번째 교차 검증에서는 학습 레이블의 1, 2 값이 각각 50 개가 추출되었고, 검증 레이블의 0 값이 50 개 추출되었습니다.
학습 레이블은 1, 2 밖에 없으므로 0 의 경우는 전혀 학습하지 못합니다.
반대로 검증 레이블은 0 밖에 없으므로 학습 모델은 절대 0 을 예측하지 못합니다.
이런 유형으로 교차 검증 데이터 세트를 분할하면 검증 예측 정확도는 0 이 될 수밖에 없습니다.
StratifiedKFold는 이렇게 KFold로 분할된 레이블 데이터 세트가 전체 레이블 값의 분포도를 반영하지 못하는 문제를 해결해 줍니다.
이번에는 동일한 데이터 분할을 StratifiedKFold로 수행하고 학습 / 검증 레이블 데이터의 분포도를 확인해 보겠습니다.
StratifiedKFold 를 사용하는 방법은 KPold 를 사용하는 방법과 거의 비슷합니다.
단 하나 큰 차이는 StratifiedKPold 는 레이블 데이터 분포도에 따라 학습 / 검증 데이터를 나누기 때문에
split() 메서드에 인자로 피처 데이터 세트뿐만 아니라 레이블 데이터 세트도 반드시 필요하다는 사실입니다
(K 폴드의 경우 레이블 데이터 세트는 split() 메서드의 인자로 입력하지 않아도 무방합니다).
폴드 세트는 3 개로 설정하겠습니다.
🌟 중요 포인트 (핵심 강조):
일반 KFold는 레이블 분포를 반영하지 않아 불균형한 학습/검증 세트가 생성될 수 있음
학습 레이블에 특정 클래스가 없으면, 모델은 그 클래스를 학습하지 못하고 예측 정확도 0 발생
StratifiedKFold는 이러한 문제를 해결하고, 레이블 분포를 유지하며 학습/검증 세트를 나눔
StratifiedKFold 사용 시 split()에 레이블도 반드시 함께 전달해야 함
폴드 수는 이 예제에서는 3 개로 설정됨
일반 KFold는 레이블 분포를 반영하지 않아 불균형한 학습/검증 세트가 생성될 수 있음
학습 레이블에 특정 클래스가 없으면, 모델은 그 클래스를 학습하지 못하고 예측 정확도 0 발생
StratifiedKFold는 이러한 문제를 해결하고, 레이블 분포를 유지하며 학습/검증 세트를 나눔
StratifiedKFold 사용 시 split()에 레이블도 반드시 함께 전달해야 함
폴드 수는 이 예제에서는 3 개로 설정됨
from sklearn.model_selection import StratifiedKFold
skf = StratifiedKFold(n_splits=3)
n_iter=0
for train_index, test_index in skf.split(iris_df, iris_df ['label']):
n_iter += 1
label_train= iris_df['label'].iloc[train_index]
label_test= iris_df['label'].iloc[test_index]
print('# 교차 검증 : {0}'.format(n_iter))
print('학습 레이블 데이터 분포:\n', label_train.value_counts())
print(' 검증 레이블 데이터 분포 :\n', label_test.value_counts())

출력 결과를 보면 학습 레이블과 검증 레이블 데이터 값의 분포도가 거의 동일하게 할당됨.
전체 150 개의 데이터에서 학습으로 100 개, 검증으로 50 개가 교차 검증 단계별로 할당이 되었습니다.
첫 번째 교차 검증에서 100 개의 학습 레이블은 0, 1, 2 값이 각각 34, 33, 33 개로, 레이블 값별로 거의 동일하게 할당됐고,
50 개의 검증 레이블 역시 0, 1, 2 값이 각각 17, 17, 16 개로, 레이블 값별로 거의 동일하게 할당되었습니다.
이렇게 분할이 되어야 레이블 값 0, 1, 2 를 모두 학습할 수 있고, 이에 기반해 검증을 수행할 수 있습니다.
StratifiedKFold 를 이용해 붓꽃 데이터를 교차 검증해 보겠습니다.
다음 코드는 StratifiedKFold 를 이용해 데이터를 분리한 것입니다.
피처 데이터와 레이블 데이터는 앞의 붓꽃 StratifiedKFold 예제에서 추출한 데이터를 그대로 이용하겠습니다.
from sklearn.tree import DecisionTreeClassifier
from sklearn.metrics import accuracy_score
from sklearn.model_selection import StratifiedKFold
from sklearn.datasets import load_iris
import numpy as np
# 데이터 로딩
iris = load_iris()
features = iris.data
label = iris.target
# 모델 및 StratifiedKFold 설정
dt_clf = DecisionTreeClassifier(random_state=156)
skfold = StratifiedKFold(n_splits=3)
n_iter = 0
cv_accuracy = []
# StratifiedKFold의 split() 호출 시 반드시 레이블 데이터 세트도 추가 입력 필요
for train_index, test_index in skfold.split(features, label):
# split()으로 반환된 인덱스를 이용해 학습용, 검증용 테스트 데이터 추출
X_train, X_test = features[train_index], features[test_index]
y_train, y_test = label[train_index], label[test_index]
# 학습 및 예측
dt_clf.fit(X_train, y_train)
pred = dt_clf.predict(X_test)
# 반복 시마다 정확도 측정
n_iter += 1
accuracy = np.round(accuracy_score(y_test, pred), 4)
train_size = X_train.shape[0]
test_size = X_test.shape[0]
print('\n#{0} 교차 검증 정확도 : {1}, 학습 데이터 크기 : {2}, 검증 데이터 크기 : {3}'
.format(n_iter, accuracy, train_size, test_size))
print('#{0} 검증 세트 인덱스 : {1}'.format(n_iter, test_index))
cv_accuracy.append(accuracy)
# 교차 검증별 정확도 및 평균 정확도 계산
print('\n## 교차 검증별 정확도:', np.round(cv_accuracy, 4))
print('## 평균 검증 정확도:', np.round(np.mean(cv_accuracy), 4))

``
3 개의 Stratified K 폴드로 교차 검증한 결과 평균 검증 정확도가 약 96.67% 로 측정.
Stratified K 폴드의 경우 원본 데이터의 레이블 분포도 특성을 반영한 학습 및 검증 데이터 세트를 만들 수 있으므로 왜곡된 레이블 데이터 세트에서는 반드시 Stratified K 폴드를 이용해 교차 검증해야 함.
분류(Classification) → Stratified K 폴드 자동 적용
회귀(Regression) → 기본 K 폴드 사용
회귀 (Regression) 에서는 Stratified K 폴드가 지원되지 않음.
회귀의 결정값은 이산값 형태의 레이블이 아니라 연속된 숫자값이기 때문에 결정값별로 분포를 정하는 의미가 없음.
cross_val_score() 와 같은 API 를 제공합니다.KFold 로 데이터를 학습하고 예측하는 코드를 보면
먼저
1. 폴드 세트를 설정
2. for 루프에서 반복으로 학습 및 테스트 데이터의 인덱스를 추출
3. 반복적으로 학습과 예측을 수행하고 예측 성능을 반환.
cross_val_score()는 이런 일련의 과정을 한꺼번에 수행해주는 API 입니다.
회귀인 경우는 Stratified K 폴드 방식으로 분할할 수 없으므로 K 폴드 방식으로 분할합니다
from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import cross_val_score, cross_validate
from sklearn.datasets import load_iris
iris_data = load_iris()
dt_clf = DecisionTreeClassifier(random_state=156)
data = iris_data.data
label = iris_data. target
# 성능 지표는 정확도 (accuracy), 교차 검증 세트는 3 개
scores = cross_val_score(dt_clf, data, label, scoring='accuracy', cv=3)
print('교차 검증별 정확도 :' , np.round(scores, 4))
print('평균 검증 정확도 :', np.round(np.mean(scores), 4))
실행 결과는 이렇게 나옴
교차 검증별 정확도 : [0.98 0.94 0.98]
평균 검증 정확도 : 0.9667
cross_val_score()는 cv로 지정된 횟수만큼 scoring 파라미터로 지정된 평가 지표로 평가 결과 값을 배열로 반환.
일반적으로 이를 평균해 평가 수치로 사용합니다.
cross_val_score() API는 내부에서 Estimator를 학습 (fit), 예측 (predict), 평가 (evaluation) 시켜주므로 간단하게 교차 검증을 수행 가능.
붓꽃 데이터의 cross_val_score() 수행 결과와 앞 예제의 붓꽃 데이터 StratifiedKFold의 수행 결과를 비교해 보면 각 교차 검증별 정확도와 평균 검증 정확도가 모두 동일함. (cross_val_score()가 내부적으로 StratifiedKFold를 이용하기 때문임)
비슷한 API로 cross_validate()있음.
cross_val_score() : 단 하나의 평가 지표만 가능
cross_validate() : 여러 개의 평가 지표를 반환 가능
하이퍼 파라미터는 알고리즘의 성능에 중요한 영향을 주는 요소
GridSearchCV는 하이퍼 파라미터 튜닝을 자동화하는 사이킷런의 주요 도구
Grid 방식은 가능한 조합을 촘촘하게 테스트해 최적값 탐색
아직 상세 설명 전이지만, 튜닝 방식에 대한 사전 이해가 중요
사이킷런은 GridSearchCV API 를 이용해 Classifier나 Regressor와 같은 알고리즘에 사용되는 하이퍼 파라미터를 순차적으로 입력하면서 편리하게 최적의 파라미터를 도출할 수 있는 방안을 제공
Grid 는 격자라는 뜻으로, 촘촘하게 파라미터를 입력하면서 테스트를 하는 방식입니다
grid_parameters = {'max_depth': [1, 2, 3],
'min_samples_split': [2, 3]}
from sklearn.datasets import load_iris
from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import GridSearchCV
from sklearn.model_selection import train_test_split
# 데이터를 로딩하고 학습 데이터와 테스트 데이터 분리
iris_data = load_iris()
X_train, X_test, y_train, y_test = train_test_split(iris_data.data, iris_data.target,
test_size=0.2, random_state=121)
dtree = DecisionTreeClassifier()
### 파라미터를 딕셔너리 형태로 설정
parameters = {'max_depth':[1, 2, 3], 'min_samples_split': [2, 3]}
import pandas as pd
# paran_grid 의 하이퍼 파라미터를 3 개의 train, test set fold 로 나누어 테스트 수행 설정.
## refit=True가 default임. True 이면 가장 좋은 파라미터 설정으로 재학습시킴.
grid_dtree = GridSearchCV(dtree, param_grid=parameters, cv=3, refit=True)
# 붓꽃 학습 데이터로 param grid의 하이퍼 파라미터를 순차적으로 학습 / 평가 .
grid_dtree. fit(X_train, y_train)
#GridsearchcV 결과를 추출해 Dataframe 으로 변환
scores_df = pd.DataFrame(grid_dtree.cv_results_)
scores_df[['params', 'mean_test_score', 'rank_test_score',
'split0_test_score', 'split1_test_score', 'split2_test_score']]

params 칼럼 : 수행할 때마다 적용된 개별 하이퍼 파라미터값
rank_test_score: 하이퍼 파라미터별 성능 순위 (1이 최적의 하이퍼 파라미터)
mean_test_score : 하이퍼 파라미터별로 CV 폴딩 테스트 세트에 대한 평균 평가값
GridSearchCV 객체의 fit() 을 수행하면 최고 성능을 나타낸 하이퍼 파라미터 값과 평가 결과 값이 각각 bestparams, bestscore 속성에 기록됨
cv_results의 ranktest_score가 1일 때의 값
이 속성을 이용해 최적 하이퍼 파라미터와 정확도를 확인할 수 있음
print('Gridsearchcv 최적 파라미터 :', grid_dtree.best_params_)
# GridsearchcV 최적 파라미터 : ('max_depth': 3 , 'min_samples_split : 2} 출력
print('GridsearchCV 최고 정확도:{0:.4f}'.format(grid_dtree.best_score_))
# GridSearchcV 최고 정확도 : 0.9750 출력
max_depth가 3, min_samples_split이 2일 때 평균 최고 정확도는 97.50%
GridSearchCV는 기본 파라미터 refit=True
refit=True이면 최적 하이퍼파라미터로 Estimator 재학습 후 bestestimator로 저장
bestestimator를 사용해 train_test_split()으로 나눈 테스트 세트에 예측 및 성능 평가 가능
# GridSearchcV의 refit으로 이미 학습된 estimator 반환
estimator = grid_dtree.best_estimator_
# Gridsearchcv의 best_estimator_는 이미 최적 학습이 됐으므로 별도 학습이 필요 없음
pred = estimator.predict(X_test)
print('테스트 데이터 세트 정확도 : {0: 4f}'.format(accuracy_score(y_test, pred)))
# 출력 |||| 테스트 데이터 세트 정확도 : 0.966667
from sklearn.preprocessing import LabelEncoder
items=['TV', '냉장고' , '전자레인지' , '컴퓨터', '선풍기' , '선풍기' , '믹서', '믹서']
# LabelEncoder를 객체로 생성한 후 , fit() 과 transform() 으로 레이블 인코딩 수행.
encoder = LabelEncoder()
encoder.fit(items)
labels = encoder.transform(items)
print('인코딩 변환값:', labels)
# 출력 |||| 인코딩 변환값: [0 1 4 5 3 3 2 2]
print('인코딩 클래스 :' , encoder.classes_)
# 출력 ||| 인코딩 클래스 : [' 선풍기 , 선풍기 , 믹서, 믹서 ' ' 컴퓨터 ' 'TV' '냉장고' '전자레인지']
from sklearn.preprocessing import OneHotEncoder
import numpy as np
items= ['TV', '냉장고','전자레인지', '컴퓨터' ,'선풍기' , '선풍기' , '믹서' , '믹서' ]
# 2차원 ndarray로 변환합니다.
items = np.array(items).reshape(-1, 1)
# 원- 핫 인코딩을 적용합니다.
oh_encoder = OneHotEncoder()
oh_encoder. fit(items)
oh_labels = oh_encoder.transform(items)
# OnetotEncoder로 변환한 결과는 희소행렬이므로 toarray()를 이용해 밀집 행렬로 변환.
print('원-핫 인코딩 데이터')
print(oh_labels. toarray())
print('원-핫 인코딩 데이터 차원 ')
print(oh_labels.shape)

import pandas as pd
df= pd.DataFrame({'item':['TV', '냉장고' ,'전자레인지' ,'컴퓨터' , '선풍기' , '선풍기' , '믹서' , '믹서']
})
pd.get_dummies(df)

- 대표적인 방법
1. 표준화 (Standardization)
2. 정규화 (Normalization)

일반적으로 정규화는 서로 다른 피처의 크기를 통일하기 위해 크기를 변환하는 개념
예:
피처 A: 거리 (0 ~ 100KM)
피처 B: 금액 (0 ~ 100,000,000원)
모든 값을 0 ~ 1 사이로 변환해 동일 단위로 비교
새로운 데이터는 원래 값에서 피처의 최솟값을 빼고, 최댓값과 최솟값의 차이로 나눈 값으로 변환됨


혼선을 방지하기 위해
사이킷런의 대표적인 피처 스케일링 클래스
특히 중요한 알고리즘:
from sklearn.datasets import load_iris
import pandas as pd
# 붓꽃 데이터 세트를 로딩하고 Dataframe 으로 변환합니다.
iris = load_iris()
iris_data = iris.data
iris_df = pd.DataFrame(data=iris_data, columns=iris.feature_names)
print('feature 들의 평균 값 ')
print(iris_df.mean())
print('Infeature 들의 분산 값 ')
print(iris_df.var())

from sklearn.preprocessing import StandardScaler
# StandardScaler 객체 생성
scaler = StandardScaler()
# StandardScaler로 데이터 세트 변환. fit()과 transform( ) 호출.
scaler.fit(iris_df)
iris_scaled = scaler.transform(iris_df)
# transform() 시 스케일 변환된 데이터 세트가 NumPy ndarray로 반환돼 이를 Dataframe 으로 변환
iris_df_scaled = pd.DataFrame(data=iris_scaled, columns=iris.feature_names)
print('feature 들의 평균 값 ' )
print(iris_df_scaled.mean())
print('Infeature 들의 분산 값')
print(iris_df_scaled.var())

모든 칼럼 값의 평균이 0 에 아주 가까운 값으로 ,
그리고 분산은 1 에 아주 가까운 값으로 변환됨
from sklearn.preprocessing import MinMaxScaler
# MinMaxScaler 객체 생성
scaler = MinMaxScaler()
# MinMaxScaler 로 데이터 세트 변환. fit()과 transform() 호출.
scaler.fit(iris_df)
iris_scaled = scaler.transform(iris_df)
# transform() 시 스케일 변환된 데이터 세트가 NumPy ndarray로 반환돼 이를 Dataframe으로 변환
iris_f_scaled = pd.DataFrame(data=iris_scaled, columns=iris.feature_names)
print('feature들의 최솟값')
print(iris_df_scaled.min())
print('Infeature들의 최댓값')
print(iris_df_scaled.max())

주의점:
from sklearn.preprocessing import MinMaxScaler
import numpy as np
# 학습 데이터는 0 부터 10 까지 , 테스트 데이터는 0 부터 5 까지 값을 가지는 데이터 세트로 생성
# Scaler 클래스의 fit(), transform() 은 2 차원 이상 데이터만 가능하므로 reshape(-1, 1) 로 차원 변경
train_array = np.arange(0, 11) .reshape(-1, 1)
test_array = np.arange(0, 6). reshape(-1, 1)
학습 데이터 train_array에 MinMaxScaler 적용
데이터: 0부터 10까지 값
fit() 적용 시 → 최솟값 0, 최댓값 10 설정 → 1/10 스케일 적용
# MinMaxScaler 객체에 별도의 feature_range 파라미터 값을 지정하지 않으면 0~1 값으로 변환
scaler = MinMaxScaler()
# fit()하게 되면 train_array 데이터의 최솟값이 0, 최댓값이 10 으로 설정.
scaler.fit(train_array)
# 1/10 scale 로 train_array 데이터 변환함. 원본 10- 〉 1 로 변환됨.
train_scaled = scaler. transform(train_array)
print('원본 train_array 데이터 :', np.round (train_array.reshape(-1), 2))
print('Scale된 train_array 데이터:', np.round(train_scaled.reshape(-1), 2))

# MinMaxScaler 에 test_array를 fit()하게 되면 원본 데이터의 최솟값이 0, 최댓값이 scaler. fit(test_array)
#5 로 설정됨
# 1/5 scale로 test_array 데이터 변함. 원본 5->1로 변환.
test_scaled = scaler. transform(test_array)
# test_array의 Scale 변환 출력.
print('원본 test_array 데이터 :', np.round(test_array.reshape(-1), 2))
print('Scale된 test_array 데이터:', np.round(test_scaled.reshape(-1), 2))
윗부분 코드가 출력이 이렇게 됩니다.
원본 test_array 데이터 : [0 1 2 3 4 5]
Scale된 test_array 데이터: [0. 0.1 0.2 0.3 0.4 0.5]
출력 결과: 학습 데이터와 테스트 데이터의 스케일링이 맞지 않음
테스트 데이터는 최솟값 0, 최댓값 5 → 1/5 스케일
1 → 0.2, 5 → 1
학습 데이터는 1/10 스케일
2 → 0.2, 10 → 1
서로 다른 원본값이 같은 값으로 변환됨 → 잘못된 결과
테스트 데이터는 학습 데이터의 스케일링 기준을 따라야 함
테스트 데이터는 다시 fit() 하면 안 됨, 학습 데이터로 fit()된 Scaler로 transform()만 적용
결과: 학습/테스트 데이터 모두 1/10 수준으로 동일하게 스케일링
scaler = MinMaxScaler()
scaler.fit(train_array)
train_scaled = scaler. transform(train_array)
print('원본 train_array 데이터 :', np.round(train_array.reshape(-1), 2))
print('Scale train_array 데이터:', np.round(train_scaled.reshape(-1), 2))
# test_array에 Scale 변환을 할 때는 반드시 fit()을 호출하지 않고 transform()만으로 변환해야 함.
test_scaled = scaler.transform(test_array)
print('\n원본 test_array 데이터 :' , np.round(test_array.reshape(-1), 2))
print('Scale된 test_array 데이터 :', np.round(test_scaled.reshape(-1), 2))

https://colab.research.google.com/drive/1K5avPMjL-bXZLhmycFRVBhgx7hNwtKNJ?usp=sharing
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline
titanic_df = pd.read_csv('sample_data/train.csv')
titanic_df.head(3)

로딩된 데이터 컬럼 타입 확인
DataFrame 의 info() 메서드를 통해 쉽게 확인이 가능
print('\n ### 학습 데이터 정보 ### \n')
print(titanic_df.info())
처리 방법:
titanic_df ['Age'].fillna(titanic_df['Age'].mean(), inplace=True)
titanic_df[ 'Cabin'].fillna('N', inplace=True)
titanic_df['Embarked'].fillna('N', inplace=True)
print('데이터 세트 Null 값 개수', titanic_df.isnull().sum().sum())
출력이 이렇게 나옵니다.
데이터 세트 Null 값 개수 0
print(' Sex 값 분포 :\n', titanic_df['Sex'].value_counts())
print('\n Cabin 값 분포 :\n', titanic_df ['Cabin'].value_counts())
print('\n Embarked 값 분포:\n', titanic_df ['Embarked' ].value_counts())

titanic_df['Cabin'] = titanic_df['Cabin'].str[:1]
print(titanic_df['Cabin'].head(3))

titanic_df.groupby(['Sex', 'Survived'])['Survived' ].count()

Survived 칼럼은 레이블 (결정 클래스)
0: 사망, 1: 생존
탑승객 수: 남자 577명, 여자 314명
생존율:
여자: 314명 중 233명 생존 → 약 74.2%
남자: 577명 중 109명 생존 → 약 18.8%
Seaborn 패키지로 시각화 진행
X축: Sex, Y축: Survived
barplot() 함수 사용
DataFrame 객체 입력하여 막대 차트 출력
sns.barplot(x='Sex', y = 'Survived', data=titanic_df)

sns.barplot(x='Pclass', y='Survived', hue='Sex', data=titanic_df)

# 입력 age 에 따라 구분 값을 반환하는 함수 설정. DataFrame 의 apply lambda 식에 사용.
def get_category (age):
cat = ''
if age <= -1: cat = 'Unknown'
elif age <= 5: cat = 'Baby'
elif age <= 12: cat = 'Child'
elif age <= 18: cat = 'Teenager'
elif age <= 25: cat = 'Student'
elif age <= 35: cat = 'Young Adult'
elif age <= 60: cat = 'Adult'
else : cat = 'Elderly'
return cat
# 막대그래프의 크기 figure를 더 크게 설정
plt.figure(figsize=(10, 6))
# X 축의 값을 순차적으로 표시하기 위한 설정
group_names = ['Unknown', 'Baby', 'Child', 'Teenager', 'Student', 'Young Adult', 'Adult', 'Elderly']
# lambda 식에 위에서 생성한 get_category() 함수를 반환값으로 지정.
# get_category(X)는 입력값으로 'Age' 칼럼 값을 받아서 해당하는 Cat 반환
titanic_df['Age_cat'] = titanic_df['Age'].apply(lambda x : get_category(x))
sns.barplot(x='Age_cat', y='Survived', hue='Sex', data=titanic_df, order=group_names)
titanic_df.drop('Age_cat', axis=1, inplace=True)

from sklearn.preprocessing import LabelEncoder
def encode_features(dataDF):
features = ['Cabin', 'Sex', 'Embarked']
for feature in features:
le = LabelEncoder( )
le = le.fit(dataDF[feature])
dataDF [feature] = le.transform(dataDF[feature])
return dataDF
titanic_df = encode_features(titanic_df)
titanic_df.head()

# Null 처리 함수
def fillna(df):
df['Age'].fillna(df['Age'].mean(), inplace=True)
df['Cabin'].fillna('N', inplace=True)
df['Embarked'].fillna('N', inplace=True)
df['Fare'].fillna(0, inplace=True)
return df
# 머신러닝 알고리즘에 불필요한 피처 제거
def drop_features (df):
df.drop(['PassengerId', 'Name', 'Ticket'], axis=1, inplace=True)
return df
# 레이블 인코딩 수행.
def format_features(df):
df['Cabin'] = df['Cabin'].str[:1]
features = ['Cabin', 'Sex', 'Embarked']
for feature in features:
le = LabelEncoder()
le = le.fit(df[feature])
df[feature] = le.transform(df[feature])
# Removed premature return statement
return df # The return statement was inside the for loop, causing it to exit after the first iteration.
# 앞에서 설정한 데이터 전처리 함수 호출
def transform_features(df):
df = fillna(df)
df = drop_features(df)
df = format_features(df)
return df
# 원본 데이터를 재로딩하고 , 피처 데이터 세트와 레이블 데이터 세트 추출.
import pandas as pd
titanic_df = pd.read_csv('sample_data/train.csv')
y_titanic_df = titanic_df['Survived']
X_titanic_df= titanic_df.drop('Survived', axis=1)
X_titanic_df = transform_features(X_titanic_df)
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test=train_test_split(X_titanic_df, y_titanic_df,
test_size=0.2, random_state=11)
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score
# 분류기 생성
dt_clf = DecisionTreeClassifier(random_state=11)
rf_clf = RandomForestClassifier(random_state=11)
lr_clf = LogisticRegression(solver='liblinear')
# DecisionTreeClassifier 학습 / 예측 / 평가
dt_clf.fit(X_train, y_train)
dt_pred = dt_clf.predict(X_test)
print('DecisionTreeClassifier 정확도 : {:.4f}'.format(accuracy_score(y_test, dt_pred)))
# RandomForestClassifier 학습 / 예측 / 평가
rf_clf.fit(X_train, y_train)
rf_pred = rf_clf.predict(X_test)
print('RandomForestClassifier 정확도 : {:.4f}'.format(accuracy_score(y_test, rf_pred)))
# LogisticRegression 학습 / 예측 / 평가
lr_clf.fit(X_train, y_train)
lr_pred = lr_clf.predict(X_test)
print('LogisticRegression 정확도 : {:.4f}'.format(accuracy_score(y_test, lr_pred)))
from sklearn.model_selection import KFold
def exec_kfold(clf, folds=5):
# 폴드 세트를 5 개인 KFold 객체를 생성 , 폴드 수만큼 예측결과 저장을 위한 리스트 객체 생성.
kfold = KFold(n_splits=folds) # Moved this line inside the function
scores = []
# KFold 교차 검증 수행.
for iter_count,(train_index, test_index) in enumerate(kfold.split(X_titanic_df)):
# X_titanic_df 데이터에서 교차 검증별로 학습과 검증 데이터를 가리키는 index 생성
X_train, X_test = X_titanic_df.values[train_index], X_titanic_df.values[test_index]
y_train, y_test = y_titanic_df.values[train_index], y_titanic_df.values[test_index]
# Classifier 학습 , 예측 , 정확도 계산
clf.fit(X_train, y_train)
predictions = clf.predict(X_test)
accuracy = accuracy_score(y_test, predictions)
scores.append(accuracy)
print("교차 검증 {0} 정확도 : {1:.4f}".format(iter_count, accuracy)) # Corrected the format string
# 5개 fold 에서의 평균 정확도 계산.
mean_score = np.mean(scores)
print("평균 정확도 : {0:.4f}".format(mean_score))
# exec_kfold 호출
exec_kfold(dt_clf, folds=5)
평균 정확도는 약 78.23% 입니다. 이번에는 교차 검증을 cross_val_score() API 를 이용해 수행합
from sklearn.model_selection import cross_val_score
scores = cross_val_score(dt_clf, X_titanic_df, y_titanic_df, cv=5)
for iter_count, accuracy in enumerate(scores):
print("교차 검증 {0} 정확도 : {1:.4f}".format(iter_count, accuracy))
print("평균 정확도 : {0:.4f}".format(np.mean(scores)))
from sklearn.model_selection import GridSearchCV
parameters = {'max_depth':[2, 3, 5, 10],
'min_samples_split':[2, 3, 5], 'min_samples_leaf': [1, 5, 8]}
grid_dclf = GridSearchCV(dt_clf, param_grid=parameters, scoring='accuracy', cv=5)
grid_dclf.fit(X_train, y_train)
print('GridSearchcV 최적 하이퍼 파라미터 :', grid_dclf.best_params_)
print('GridsearchcV 최고 정확도 : {0: 4f}'.format(grid_dclf.best_score_))
best_dclf = grid_dclf.best_estimator_
# Gridsearchcv의 최적 하이퍼 파라미터로 학습된 Estimator로 예측 및 평가 수행.
predictions = best_dclf.predict(X_test)
accuracy = accuracy_score(y_test, predictions)
print('테스트 세트에서의 DecisionTreeClassifier 정확도 : (0:.4f)'.format(accuracy))