본문 바로가기

파이썬라이브러리&sklearn&keras

ML&DL_sklearn공부(2) << Iris Data를 이용한 학습과 평가

ML&DL_sklearn공부(2). Iris Data를 이용한 학습과 평가

데이터 불러오기.

from sklearm.dataset import load_iris
data = load_iris()
  • 여기서 load_iris는 데이터 및 데이터의 설명을 담은 딕셔너리를 반환.
  • dictionary를 아래의 코드를 통해 확인해볼 수 있다.

전처리 및 EDA

np.unique(data.target, return_counts = True)
# unique한 데이터를 반환해주고, return_counts를 설정해주면 갯수도 반환해준다.

print(data.target_names) #['setosa' 'versicolor' 'virginica']

print(data.target_names.shape, data.target_names[data.target].shape) # (3,) (150,)

# 열이름, 타겟값 수정
iris.columns = ['sl', 'sw', 'pl', 'pw']
iris['Species'] = data.target_names[data.target]
# => data.target_names를 data.target의 개수 즉 150번만큼 색인해준다는 것을 의미. 타겟값을 수정.
iris.head()

결측값 있는지 확인해주기.

  • 결측값이 있다면 처리를 해주어야 함.
  • 결측값 제거: dropna
  • 결측값 대체: fillna, interpolate
iris.isna().sum() # 결측값 몇개냐?

기초통계 분석

  • iris.describe() : 통계정보 알려줌.
  • iris.info() : Dataframe의 기본정보 확인.
  • iris.groupby('Species').size() : 종류별로 개수 알려줌.
  • iris.Species.value_counts() : 종류별로 개수 알려줌.

데이터 시각화

기초 통계량 및 이상치 시각화(boxplot)

    def boxplot_iris(feature_names, dataset):
      i = 1
      plt.figure(figsize = (11, 9))
      for col in feature_names:
          plt.subplot(2, 2, i)
          plt.axis('on')
          plt.tick_params((axis = 'both', left = True, top = False,
                         right = False, bottom = True, labelleft = False,
                         labeltop = False, labelright = False, labelbottom = False)
          dataset[col].plot(kind = 'box', subplots = True, sharex = False, sharey = False)
          plt.title(col)
          i += 1
      plt.show()

    boxplot_iris(iris.columns[:-1], iris)

만약에 상대적인 위치를 보고 싶으면 sharex와 sharey를 True로 해줄 것.

  fig, axes = plt.subplots(2, 2, figsize = (11, 9), sharex = True, sharey = True)
  axes = axes.ravel() # np.ravel()은 1차원 배열로 만들어준다.
  for i, ax in enumerate(axes):
      iris.iloc[:, i].plot(kind = 'box', ax = ax)
      ax.set_title(iris.columns[i])
  plt.show()

데이터 분포 시각화(histogram)

  def histogram_iris(feature_names, dataset):
      i = 1
      plt.figure(figsize = (11, 9))
      for col in feature_names:
          plt.subplot(2, 2, i)
          plt.axis('on')
          plt.tick_params(axis = 'both', left = True, top = False,
                         right = False, bottom = False, labelleft = False,
                         labeltop = False, labelright = False, labelbottom = False)
          dataset[col].plot(kind = 'hist', subplots = True, sharex = False, sharey = False)
          plt.title(col)
          i += 1
      plt.show()
  histogram_iris(iris.columns[:-1], iris)

상관관계 시각화(heatmap)

  • correlationship matrix를 생성해줌.

        corr = iris.corr() 
        cmap = sns.diverging_palette(220, 19, as_cmap = True)
        plt.figure(figsize=(11,9))
        sns.heatmap(corr, cmap=cmap, vmax=1.0, vmin=-1.0, center=0,
                   square=True, linewidths=.5, cbar_kws={'shrink':.5})
        plt.show()

피처 간의 상관관계 및 데이터 분포 시각화(pairplot)

  sns.pairplot(iris, hue = 'Species')
  plt.show()

타겟의 클래스 비율(piechart)

  • 타겟의 클래스 비율을 시각화해서 살펴본다.

        def piechar_iris(feature_names, target, dataset):
            i = 1
            plt.figure(figsize = (11, 9))
            for colName in [target]:
                labels = []; sizes = []
                df = dataset.groupby(colName).size()
    
                for key in df.keys():
                    labels.append(key)
                    sizes.append(df[key])
    
                plt.subplot(2, 2, i)
                plt.axis('on')
                plt.tick_params(axis = 'both', left = False, top = False,
                               right = False, bottom = False, labelleft = True,
                               labeltop = True, labelright = False, labelbottom = False)
                plt.pie(sizes, labels = labels, autopct = '%1.1f%%',
                       shadow = True, startangle = 140)
                plt.axis('equal')
                i += 1
    
                #plt.axis('equal') 은 동그란 표를 만들자는 뜻.
            plt.show()
    
        piechar_iris(iris.columns[:-1], iris.Species, iris)

Hold out

```python
from sklearn.model_selection import train_test_split

X_train, X_test, y_train, y_test = train_test_split(iris.iloc[:, :-1], iris.iloc[:, -1], test_size = 0.33, random_state = 42)
```
  • : sklearn의 train_test_split 함수로 훈련용 데이터셋과 성능평가용 데이터셋을 나눈다.

학습

  • train : 학습 파라미터를 학습시키는 용도

  • validation : 어떤 hyperparameter가 좋은지 튜닝과 평가

  • test : Best parameter로 학습시킨 모델을 평가하는 용도

모델생성🙊

\- 알고리즘 선택 : 이 예제에서는 **Decision Tree Classifier** 을 이용할 것이다.  
`python from sklearn.tree import DecisionTreeClassifier model = DecisionTreeClassifier(random_state = 42)`  
\- 모델학습  
`python model.fit(X_train, y_train)`  
\- score  
`python model.score(X_test, y_test) # 0.98, iris 데이터는 굉장히 좋은 데이터라 어떻게 학습을 시켜도 높은 점수가 나온다.`

모델 일반화 전략 & Learning curve🙊

머신러닝이란 데이터에 의해서 모델의 성능이 결정되기 때문에 데이터가 충분히 많아야 한다. 데이터가 충분치 않은 경우, 특정 학습데이터에만 높은 성능을 가지는 과적합이 발생할 수 있기 때문에 모델을 일반화해주는 노력이 필요하다.
  • validation set
    🔎 학습데이터셋에서도 일부를 hold out해서 validation set으로 활용해준다.

  • cross vaildation(교차검증)
    🔎 데이터셋을 k개만큼 나누어, 조각들을 돌아가면서 validation set으로 사용한다. 그 다음, k개의 성능 결과를 평균내서 모델의 성능을 추정한다.

    • KFold

            from sklearn.model_selection import cross_val_score, KFold
      
            cv = KFold(n_splits = 10, shuffle = True, random_state = 42)
            results = cross_val_score(model, X_train, y_train, cv = cv)
            fin_result = results.mean()
      
            for i, r in enumerate(results):
            print(f"{i}번째 교차 검증 정확도: {r}")
      
            print(f"\n교차검증 최종 정확도: {fin_result}")
    • Stratified KFold
      : 한 validation set안에 꽃 3가지의 종류가 골고루 섞어준 후 성능을 평가한다.

          from sklearn.model_selection import cross_val_score, StratifiedKFold
      
          cv = StratifiedKFold(n_splits = 10, shuffle = True, random_state = 42)
          results = cross_val_score(model, X_train, y_train, cv = cv)
          fin_result = results.mean()
      
          for i, r in enumerate(results):
          print(f"{i}번째 교차 검증 정확도: {r}")
      
          print(f"\n교차검증 최종 정확도: {fin_result}")

  • Learning curve
    교차검증 기법은 데이터의 양이 충분하지 않을 때 사용하는 기법인데, 이 때 데이터의 양이 충분한가에 대해서는 학습곡선을 그림으로써 판단할 수 있다.

      import scikitplot as skplt
      skplt.estimators.plot_learning_curve(model, X_train, y_train, figsize = (6,6))
      plt.show()
    ``
    

모델 최적화 전략🙊

-   하이퍼파라미터 : scikit-learn에서는 알고리즘을 인스턴스화할 때 하이퍼파라미터를 설정할 수 있다.
-   **GridSearchCV** 를 이용하여 하이퍼 파라미터 탐색  
    🔎 하이퍼 파라미터 조합에 대한 경우의 수를 모두 격자(grid)에 나열하고 모든 조합을 일일히 학습 및 성능 측정하는 기능이다.  
    🔎 estimator로는 알고리즘 인스턴스를 전달하고, param\_grid에너느 테스트할 하이퍼파라미터를 담은 **딕셔너리**를 전달한다.
from sklearn.model_selection import GridSearchCV
estimator = DecisionTreeClassifier()
params= {'max_depth':range(4, 13, 2),
        'criterion':['gini', 'entropy'],
        'splitter':['best', 'random'],
        'min_weight_fraction_leaf':[0.0, 0.1, 0.2, 0.3],
        'random_state':[7, 23, 42, 78, 142],
        'min_impurity_decrease':[0., 0.05, 0.1, 0.2]}
model = GridSearchCV(estimator, params, cv=cv, verbose=1,
                    n_jobs = -1, refit=True) # validation set 10개 * 하이퍼파라미터 조합수 1600개 = 16000번
                    # refit : best parmaeter 학습결과를 best_estimator_ 속성에 기록해둔다.
model.fit(X_train, y_train)

print(f"Best Estimator: {model.best_estimator_}\n")
print(f"Best Params: {model.best_params_}\n")
print(f"Best Scorer: {model.best_score_}\n")

평가 지표 및 모델 평가

정확도만으로 모델을 평가/검증하는 것은 부족하기 때문에 다른 평가지표들도 알 필요가 있다.

Confusion Matrix

  • 이진분류 : 예측을 할 때 두가지로 예측하는 경우 총 4가지의 경우가 나오게 된다.

  • 다중분류 : 아이리스 데이터의 경우 꽃의 특징들(feature)들을 가지고 이 꽃이 setosa인지, versicolor인지, virginic인지 예측하게 된다. 이를 바탕으로 지표를 만들면 아래와 같이 된다.

  • 아이리스 데이터셋의 confusiom matrix 코드

      from sklearn.metrics import confusion_matrix
    
      pred = model.predict(X_test)
      confMatrix = confusin_matrix(y_test, pred)
      print('Confusion Matrix :\n : ', confMatrix)

scikit-plot을 이용하면 confusion matrix를 더 직관적인 heatmap으로 시각화할 수 있다.

    skplt.metrics.plot_confusion_matrix(y_test, pred, figsize=(8,6))
    plt.show()

Precision, Recall, Fall-out, F-score

  • FP, FN, TP, TN : 앞은 예측을 맞췄는지 틀렸는지 / 뒤는 P라 예측했는지, N이라 예측했는지
  • precision(정밀도)
    • 예측한 클래스 중에 실제로 맞은 비율(비싼 신뢰성있는 진단기), 예를 들어 양성이라 예측한 것 중에서 실제 양성인 것의 비율.
    • TP/TP+FP
  • recall(재현율)(TPR)
    • 실제 타겟 클래스 중에서 예측이 맞은 비율, 예를 들어 실제 양성의 개수 중에서 양성으로 예측한 것의 비율(효율적인 값싼 진단기)
    • TP/TP+FN
  • fall-out
    • 타겟이 아닌 실제 클래스 중에서 틀린 비율.
  • f-score
    • 정밀도와 재현율은 trade-off관계이다.
    • 정밀도와 재현율의 가중조화평균.
      precs = []
      rcls = []
      specs = []
      for i in range(3):
          TP = confMatrix[i, i]
          FN = confMatrix[i].sum() - TP
          FP = confMatrix[:,i].sum() - TP
          TN = confMatrix.sum() - TP - FN - FP
          precs.append(TP/(TP+FP))
          rcls.append(TP/(TP+FN))
          specs.append(TN/(TN+FP))

      precs = np.array(precs)
      rcls = np.array(rcls)
      specs = np.array(specs)
      fall_outs = 1 - specs

      print(precs)
      print(rcls)
      print(specs)
      print(fall_outs)

ROC curve와 AUC

  • ROC curve
    • 얘는 TPR(True Positive Rate)를 y축, FPR(False Positive Rate)를 x축으로 하는 그래프이다.
    • TPR은 recall이랑 같고, FPR은 fall-out과 같아서 FP/FP+TN(실제 negative인 표본개수)을 의미한다.
    • 클래스 판별 기준값의 변화에 따를 재현율과 위양성율의 변화를 시각화 한 것.
    skplt.metrics.plot_roc(y_test, pred_proba, figsize = (8,6))
    plt.show()
  • AUC
    • ROC curve 밑의 면적을 계산. 거꾸로 기억자일수록 좋은 성능을 나타낸다.

최종 모델

최종모델학습

    model.fit(iris.iloc[:, :-1], iris.iloc[:, -1]model.fit(iris.iloc[:, :-1], iris.iloc[:, -1]`)

모델저장

모델을 재사용 하기 위해서 모델을 저장해두자. pickle을 이용하면 모델 객체 자체를 저장할 수 있다.

    import pickle
    with open("final_model.pickle", "wb") as fp:
        pickle.dump(model, fp)

모델 불러오기 및 예측

모델을 다시 불러올 때는 load 메서드를 이용하고 저장한 모델을 불러와서 예측값을 csv로 저장해보자.

    f = open('new_model.pickle', 'rb')
    model = pickle.load(f); f.close()

    predicted_species = model.predict(iris.iloc[:, :-1])
    iris['predicted_species'] = predicted_species #새로운 열을 만들어주기.
    iris.to_csv('Final.csv', index = False)