scikit-learn (2) - 선형분류 (훈련데이터 만들기)
1. 훈련데이터셋 만들기
이 문제는 속성에 따라 인스턴스의 레이블을 지정하는 분류 문제의 한 종류이다. 선택한 두 속성과 목적값으로 만든 본래 데이터셋의 일부 데이터이다. 데이터셋을 임포트한 후 약 75%의 인스턴스를 무작위로 선택하고 남은 인스턴스를 평가 목적을 위해 보유한다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | >>> from sklearn import datasets >>> iris = datasets.load_iris() >>> X_iris, y_iris = iris.data, iris.target >>> print X_iris.shape, y_iris.shape (150, 4) (150,) >>> from sklearn.cross_validation import train_test_split >>> from sklearn import preprocessing >>> # 처음 두개의 속성으로 데이터셋을 얻는다 >>> X, y = X_iris[:, :2], y_iris >>> # 훈련데이터와 테스트데이터로 나눈다. 25%의 테스트데이터를 구한다. >>> X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25, random_state=33) >>> print X_train.shape, y_train.shape (112, 2) (112,) | cs |
train_test_split 함수는 자동으로 표본을 무작위로 선택해 훈련 데이터와 평가 데이터를 나눈다. 75% 인스턴스를 훈련데이터로 선택하므로, 전체 150개 중 112개가 훈련데이터셋에 편입된다.그런데, 문제는 아이리스 데이터셋을 살펴보면, 목적 범주 순서로 인스턴스가 나열되어 있다. 즉, 이대로 훈련데이터셋을 만들게 되면 범주 0 과 1 의 비율이 본래의 데이터셋에 비해 높아지게 되는 것이다.
1 2 3 4 5 | >>> print (y_iris[0:111]) [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 0 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 1 1 1 2 2 2 2 2 2 2 2 2 2 2] >>> | cs |
random_state 파라메터를 이용하여 목적범주별로 적절히 섞는다. 아래와 같이 적절히 섞였음을 볼 수 있다.
1 2 3 4 5 | >>> print (y_train[0:111]) [1 0 1 1 1 0 0 1 0 2 0 0 1 2 0 1 2 2 1 1 0 0 2 0 0 2 1 1 2 2 2 2 0 0 1 1 0 1 2 1 2 0 2 0 1 0 2 1 0 2 2 0 0 2 0 0 0 2 2 0 1 0 1 0 1 1 1 1 1 0 1 0 1 2 0 0 0 0 2 2 0 1 1 2 1 0 0 1 1 1 0 1 1 0 2 2 2 1 2 0 1 0 0 0 2 1 2 1 2 1 2] >>> | cs |
2. 스케일링 (값의 표준화)
이제 필요한 것은 값의 표준화이다. 큰 값을 가진 속성이 최종 결과에 너무 많은 영향을 주지 않도록 하는 것이다.각 속성에 대해 평균을 계산하고, 각 속성값에서 평균을 뺀 후 표준 편차로 결과를 나눈다. 스케일링을 한 후 각 속성의 평균은 0 이 되고, 표준 편차는 1 을 갖는다.
1 2 3 4 | >>> # 속성을 표준화한다 >>> scaler = preprocessing.StandardScaler().fit(X_train) >>> X_train = scaler.transform(X_train) >>> X_test = scaler.transform(X_test) | cs |
3. 훈련 인스턴스 분포 확인
그럼 앞서 만든 훈련데이터셋의 분포를 2차원 공간에서 확인해보자.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | >>> %matplotlib inline >>> >>> import matplotlib >>> import numpy as np >>> import matplotlib.pyplot as plt >>> colors = ['red', 'greenyellow', 'blue'] >>> for i in xrange(len(colors)): >>> xs = X_train[:,0][y_train == i] >>> ys = X_train[:,1][y_train == i] >>> plt.scatter(xs, ys, c=colors[i]) >>> plt.legend(iris.target_names) >>> plt.xlabel('Sepal length') >>> plt.ylabel('Sepal width') >>> <matplotlib.text.Text at 0x7f89ce027690> | cs |
scatter 함수는 각 인스턴스의 첫 번째 속성값(꽃받침 너비) 대 두 번째 속성값(꽃받침 길이), 각기 다른 색인 목적 범주를 사용해 도식화했다. 이로써, 속성이 어떻게 영향을 주어 목적 범주를 결정하는지 알 수 있다.
4. 학습 태스크 재정의
3의 이미지에서 빨간색의 Setosa 품종과 다른 품종의 구별은 뚜렷한 반면, 다른 두 품종의 구별은 모호하다. 그러므로 우리는 다음의 질문들에 답해야 한다. .
- 속성들이 해결하고자 하는 태스크에 유리한가?
- 새로운 속성을 더 추가해야 하는가?
- 새로운 기법을 개발해야 하는가?
즉, 학습 태스크를 재정의해야 한다. 우리의 목표는 아이리스 꽃의 인스턴스를 고려해 목표는 세토사인지 아닌지를 예측하는 일이다. 문제를 이진 분류 태스크로 변환한다. 즉 현재의 3개의 목적 범주를 2개의 목적 범주(세토사, 세토사 아님)로 변환하는 것이다.
최적으로 두 범주를 구별하는 직선을 만들어 결정 경계(decision boundary)로 사용한다. 여기서는 확률적 기울기 강하법(Stochastic Gradient Descent)의 SDGClassifier 를 사용한다. 알고리즘은 손실함수를 최소로 만드는 초평면의 계수를 학습한다. 이를 위해서는 해당 분류기 오브젝트를 만들고 훈련 데이터로 모델을 훈련시킨다. 다음과 같다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | >>> from sklearn.linear_model import SGDClassifier >>> clf = SGDClassifier() >>> clf.fit(X_train, y_train) SGDClassifier(alpha=0.0001, average=False, class_weight=None, epsilon=0.1, eta0=0.0, fit_intercept=True, l1_ratio=0.15, learning_rate='optimal', loss='hinge', n_iter=5, n_jobs=1, penalty='l2', power_t=0.5, random_state=None, shuffle=True, verbose=0, warm_start=False) >>> print clf.coef_ [[-34.40522613 4.82101696] [ 7.45335653 -12.21001281] [ 9.80914958 -7.53435314]] >>> print clf.intercept_ [-11.70270038 -2.86524274 1.45188531] | cs |
line 3 에서 보는 fit 메소드는 scikit-learn 에서 가장 중요하다. 훈련 데이터와 훈련 범주를 입력받아 분류기를 만든다.
모든 미래 분류 결정은 초평면에서만 한다. clf 오브젝트와 coef_ 속성은 선형 경계의 계수를 나타내며, intercept_ 속성은 y 축과 경계선의 교차점을 나타낸다. 위의 In [6], [7] 의 결과를 통해 확인해보자. 즉, 위에서 출력된 값을 통해 다음 방정식을 그릴 수 있다.
-11.70270038 - 34.40522613*x1 + 4.82101696*x2 = 0
x1 과 x2(실제 속성값)를 고려해 방정식의 좌측을 계산한다. 이 값이 0 보다 크면 결정경계보다 위쪽(빨간색 측)에 있게 되고, 그렇지 않으면 경계보다 아래 쪽에 있게 된다.
그런데 여기서 계수 매트릭스는 왜 세 개의 행을 가지는가? 앞서 작업을 재정한 것을 기법에 알려주지 않아 아직도 세 개의 범주 문제로 다루고 있기 때문이다. 문제를 하나 대 나머지 모두로 설정해 이진 분류로 변환한다. 다음 코드는 3개의 결정 경계를 그린다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | >>> x_min, x_max = X_train[:,0].min() - .5, X_train[:,0].max() +.5 >>> y_min, y_max = X_train[:,1].min() - .5, X_train[:,1].max() +.5 >>> xs = np.arange(x_min, x_max, 0.5) >>> fig = plt.figure() >>> fig, axes = plt.subplots(1,3) >>> fig.set_size_inches(10, 6) >>> for i in [0, 1, 2]: >>> axes[i].set_aspect('equal') >>> axes[i].set_title('Class '+ str(i) + ' versus the rest') >>> axes[i].set_xlabel('Sepal length') >>> axes[i].set_ylabel('Sepal width') >>> axes[i].set_xlim(x_min, x_max) >>> axes[i].set_ylim(y_min, y_max) >>> pylab.sca(axes[i]) >>> plt.scatter(X_train[:,0], X_train[:, 1], c=y_train, cmap=plt.cm.prism) >>> ys = (-clf.intercept_[i] - xs * clf.coef_[i, 0]) / clf.coef_[i, 1] >>> plt.plot(xs, ys, hold=True) >>> plt.show() <matplotlib.figure.Figure at 0x7f4578b0a450> | cs |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | --------------------------------------------------------------------------- ValueError Traceback (most recent call last) <ipython-input-10-d5ca27aa75c3> in <module>() 12 axes[i].set_xlim(x_min, x_max) 13 axes[i].set_ylim(y_min, y_max) ---> 14 pylab.sca(axes[i]) 15 plt.scatter(X_train[:,0], X_train[:, 1], c=y_train, cmap=plt.cm.prism) 16 ys = (-clf.intercept_[i] - xs * clf.coef_[i, 0]) / clf.coef_[i, 1] /root/anaconda/envs/tensorflow/lib/python2.7/site-packages/matplotlib/pyplot.pyc in sca(ax) 913 m.canvas.figure.sca(ax) 914 return --> 915 raise ValueError("Axes instance argument was not found in a figure.") 916 917 ValueError: Axes instance argument was not found in a figure. | cs |
※ 코드대로 실행을 시켰으나 위와 같은 에러메시지가 발생. 혹시 이에 대한 해결 방법을 알고 계신 분은 알려주시기 바랍니다. 스택오버플로우에 올렸는데 아직 답이 없네요.
'프로그래밍 Programming' 카테고리의 다른 글
서포터 벡터 머신과 이미지 인식 (1) - 정의 및 장점 (0) | 2016.11.06 |
---|---|
scikit-learn (3) - 선형분류 (결과평가) (0) | 2016.11.06 |
matplotlib - <matplotlib.text.Text at 0x7fc3298533d0> (0) | 2016.11.03 |
Jupyter Notebook 셀 크기 조절하기 How to increase/decrease the cell width of the jupyter notebook in browser (0) | 2016.11.03 |
scikit-learn (1) - 기계학습이란? (0) | 2016.11.01 |