[핸즈온 ML with Kaggle] 3. 분류: Multiclass Classification

김서연·2021년 10월 2일
1

핸즈온 3장에서는 분류에 대해 다루고 있다. binomial, multiclass, multilabel 등 분류 모델이 나오는데, 그 중 이중 분류 모델을 사용하여 multiclass 데이터셋을 분류하는 OvR과 OvO에 대해 알아보기로 하자.

캐글 노트북

SGD, 랜덤 포레스트, 나이브 베이즈 등은 다중 분류가 가능하지만, 퍼셉트론, 로지스틱 회귀, SVM은 이진 분류만 가능하기 때문에, 해당 모델을 다중 분류에 쓰기 위해서는 다중 클래스를 가진 데이터셋을 여러 개의 이중 분류 모델로 쪼갠다.
이 쪼개는 방법에 따라 OvR, OvO가 나뉘는 것!

OVR (One vs. Rest):

다른 이름으로 OvA (One vs. All) 이라고 불리기도 한다.

다중 분류 데이터셋을 여러 개의 이중 분류 셋으로 쪼갠 후, 각 이중 분류 셋에 대해 이진 분류를 한다.
결과를 비교해서 가장 결과 좋은 모델을 최종 모델로 선정하는 것이다.

예시)
[red, blue, green] 3개의 클래스를 가진 데이터셋이 있다고 할 때,
이중 분류 1: red vs. [blue, green] → red: 1, 나머지: 0 으로 분류됨
이중 분류 2: blue vs. [red, green]
이중 분류 3: green vs. [red, blue]
이렇게 3개의 분류 모델을 만든다.

즉, 데이터셋이 가진 클래스 개수만큼 분류 모델이 생성될 것이다.
이 예시에서는 세 개의 클래스 뿐이었지만 데이터셋의 규모가 크거나/클래스가 많거나/모델이 무거운 경우 문제가 될 수 있다.

각 모델의 성능을 비교해야 하기 위해 확률값이 필요하기 때문에, 자동으로 확률값을 반환하는 로지스틱 회귀, 퍼셉트론이 주로 쓰인다고 한다.

from sklearn.linear_model import LogisticRegression
model = LogisticRegression(multi_class='ovr')

sklearn에는 Logistic Regression 함수에 muti_class라는 파라미터가 존재해서 ovr로 셋팅해줄 수 있다.

from sklearn.multiclass import OneVsRestClassifier
model = LogisticRegression()
ovr = OneVsRestClassifier(model)
ovr.fit(X, y)

또는 로지스틱 회귀 모델을 만들고 OvR 함수를 씌워주는 방법도 있다.
근데 OvR 관련 코드를 살펴보면 대부분 OvR 모듈을 쓰는 듯 하다. 이진분류 모델 뿐만 아니라 다중 분류 모델에도 쓸 수 있어서 더욱 편리하다고 한다.

OVO (One vs. One):

다중 분류 데이터를 이중 분류 태스크로 쪼개는건 OvR과 같지만, OvO는 클래스 별로 일대일 비교를 한다.

예시)
아까와 같이 [red, blue, green] 3개의 클래스를 가진 데이터셋이 있다.
이중 분류 1: red vs. blue
이중 분류 2: blue vs. green
이중 분류 3: green vs. red
3C2=3개

OvO의 경우 데이터셋의 클래스가 n개일 때 분류 모델의 개수는 nC2=n(n1)/2nC2=n(n-1)/2 가 될 것이다.
각 모델에서 가장 많이 나온 클래스가 있을텐데, 투표가 가장 많은, 그러니까 가장 많은 모델에서 정답이라고 분류한 클래스가 최종 결과가 된다.
OvO의 경우 SVM을 많이 쓰는데, SVM의 커널 방법이 데이터셋 크기에 영향을 받지 않는다(?)어쩌구 되어있는데 이해를 못했기 때문에 SVM 단원에서 더 알아보도록 하고,

from sklearn.svm import SVC
model = SVC(decision_function_shape='ovo')

sklearn의 SVC도 역시 파라미터로 ovo를 설정할 수 있다.

from sklearn.multiclass import OneVsOneClassifier
model = SVC()
ovo = OneVsOneClassifier(model)
ovo.fit(X, y)

OvO도 OvR처럼 이진분류 뿐만 아니라 다중분류 모델에도 쓸 수 있다.

📘 Kaggle

1. 데이터가 어떻게 생겼나

사용한 데이터: Iris Dataset

SepalLengthCmSepalWidthCmPetalLengthCmPetalWidthCmSpecies
05.13.51.40.2Iris-setosa
14.93.01.40.2Iris-setosa
24.73.21.30.2Iris-setosa
34.63.11.50.2Iris-setosa
45.03.61.40.2Iris-setosa

이렇게 생겼다.

#Records per Species
data.Species.value_counts()

Iris-setosa 50
Iris-versicolor 50
Iris-virginica 50
Name: Species, dtype: int64

분류할 클래스는 'Iris-setosa', 'Iris-versicolor', 'Iris-virginica' 이렇게 3개고, 'SepalLengthCm', 'SepalWidthCm' 'PetalLengthCm', 'PetalWidthCm' 4개의 피쳐로 Species를 분류해볼 것이다.

2. Data Split & Feature Scaling

Train = 90%, Test = 10%

#Encoding Species columns (to numerical values)
data['Species'] = data['Species'].astype('category').cat.codes

#Feature & Target Selection
features = data.select_dtypes('float').columns
target = ['Species']

# Feature& Target  Dataset
X = data[features]
y = data[target]

#Split Parameters
test_size = 0.1

#Dataset Split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=test_size, random_state=0) 

#Feature Scaling
#sc = StandardScaler()
#X_train = sc.fit_transform(X_train)
#X_test = sc.transform(X_test)

#Reset Index
X_test = X_test.reset_index(drop=True)
y_test = y_test.reset_index(drop=True)

3. OvR

  • Binary Classification Dataset #1: Iris-setosa vs. [Iris-versicolor, Iris-virginica]
  • Binary Classification Dataset #2: Iris-virginica vs. [Iris-setosa, Iris-versicolor]
  • Binary Classification Dataset #3: Iris-versicolor vs. [Iris-setosa, Iris-virginica]

3개의 분류 모델이 필요하다.
왜 ovr도 SVM 모델을 썼는지는 잘 모르겠다. 그냥 모델 통일하고 싶었던 듯

#SVC Model
model = SVC(gamma='scale',random_state=0)

#Define 1-vs-Rest Strategy / Classifier
ovr = OneVsRestClassifier(model)

#fit model to training data
ovr.fit(X_train, y_train)

#Predications
ovr_pred = ovr.predict(X_test)

#Adding Predictions to Test Dataset
ovr_df = X_test.copy()
ovr_df.insert(4,"Actual",y_test, True)
ovr_df.insert(5,"Predicted",ovr_pred, True)

ovr_df.head()
SepalLengthCmSepalWidthCmPetalLengthCmPetalWidthCmActualPredicted
05.82.85.12.422
16.02.24.01.011
25.54.21.40.200
37.32.96.31.822
45.03.41.50.200

잘 분류가 되었군!

4. OvO

  • Binary Classification Dataset #1: Iris-setosa vs. Iris-versicolor
  • Binary Classification Dataset #2: Iris-virginica vs. Iris-setosa
  • Binary Classification Dataset #3: Iris-versicolor vs. Iris-virginica

마찬가지로 3개의 분류모델이 필요하다.

#Define 1-vs-1 Strategy / Classifier
ovo = OneVsOneClassifier(model)

#fit model to training data
ovo.fit(X_train, y_train)

#Predications
ovo_pred = ovo.predict(X_test)

#Adding Predictions to Test Dataset
ovo_df = X_test.copy()
ovo_df.insert(4,"Actual",y_test, True)
ovo_df.insert(5,"Predicted",ovo_pred, True)

ovo_df.head()
SepalLengthCmSepalWidthCmPetalLengthCmPetalWidthCmActualPredicted
05.82.85.12.422
16.02.24.01.011
25.54.21.40.200
37.32.96.31.822
45.03.41.50.200

분류가 굉장히 잘 되었다.


참고

ovr, ovo

profile
공부 중

0개의 댓글