앞서 Part IPart II를 통해서 기본적인 feature matrix를 구성하는 법까지 알아봤습니다. 그럼 이제 어떻게 training을 하고 prediction을 하는지에 대해서 알아보겠습니다 :)

간단하게 앞서 짠 코드를 요약하면,

>>> import pandas as pd
>>> train = pd.read_csv('train.tsv', sep='\t')

>>> from sklearn.feature_extraction.text import CountVectorizer
>>> cv = CountVectorizer()
>>> cv.fit(train['Phrase'])

앞서 Part II에서는 중복되는 sentence를 제거했었으나, 다시 생각해보니 제거하지 않는 것이 맞겠다는 생각이 들었습니다.(sentiment가 다르더라구요~) 이렇게 phrase들의 단어들로 구성된 vectorizer로 sparse matrix를 만든 다음에 Stochastic Gradient Descent방법을 사용하여 classify하겠습니다. 이 SGD방법은 다양한 penalty와 loss function으로 구성할 수 있으며, 매우 빠르기 때문에 빅데이터 처리에 적합한 방법이라고 할 수 있습니다. 여기서는 디테일은 다음에 다루기로 하고, 일단은 default로 세팅된 SGDClassifier를 사용하도록 하겠습니다. 이 classifier를 train시키기 위해서는 X(predictors)와 Y(response)가 필요한데요, X는 우리가 vectorize한 sparse matrix가 되고, Y는 해당 리뷰의 sentiment가 됩니다.

>>> X = cv.transform(train['Phrase'])
>>> print X[:3]
  (0, 288)	1
  (0, 529)	1
  (0, 593)	1
  (0, 602)	1
  (0, 1879)	1
  (0, 3490)	1
  (0, 4577)	1
  (0, 5323)	2
  (0, 5595)	1
  (0, 5821)	2
  (0, 5837)	1
  (0, 7217)	2
  (0, 8807)	1
  (0, 9085)	1
  (0, 9204)	1
  (0, 9227)	4
  (0, 11837)	1
  (0, 12424)	1
  (0, 12857)	1
  (0, 13503)	1
  (0, 13505)	3
  (0, 13681)	1
  (0, 14871)	1
  (0, 14888)	2
  (1, 288)	1
  (1, 3490)	1
  (1, 4577)	1
  (1, 5323)	1
  (1, 5821)	1
  (1, 5837)	1
  (1, 7217)	1
  (1, 9227)	1
  (1, 11837)	1
  (1, 13503)	1
  (1, 13505)	2
  (1, 14871)	1
  (2, 11837)	1

>>> Y = train['Sentiment']
>>> print Y[:3]
0    1
1    2
2    2
Name: Sentiment, dtype: int64

자, 이제 모든 준비가 끝났으니, SGDClassifier를 선언하고 training을 시킵시다.

>>> from sklearn.linear_model import SGDClassifier
>>> clf = SGDClassifier()
>>> clf.fit(X, Y)
>>> print clf.coef_ #coef_는 각 feature에 해당하는 weight입니다.
[[  8.95943806e-02   8.95943806e-02  -7.67951834e-02 ...,  -2.55983945e-02
    0.00000000e+00   3.19979931e-01]
 [ -1.27991972e-01   1.15192775e-01   3.83975917e-02 ...,   0.00000000e+00
   -1.27991972e-02  -1.27991972e-02]
 [  3.83975917e-02  -2.94381536e-01   1.27991972e-02 ...,   6.39959862e-02
    1.15192775e-01  -3.19979931e-01]
 [  7.67951834e-02  -1.19698594e-15   3.83975917e-02 ...,  -1.58992439e-17
   -6.39959862e-02  -7.67951834e-02]
 [  1.27991972e-02  -8.95943806e-02  -5.11967889e-02 ...,  -7.67951834e-02
    3.83975917e-02  -1.27991972e-02]]

>>> print clf.coef_.shape 
(5, 15240) #5개의 행을 갖는 이유는 sentiment가 0~4까지의 5개 값을 갖기 때문입니다.

그럼 이제 train된 이 모델을 가지고 train dataset을 예측해보겠습니다.(우리가 알고있는 정답을 쓰지 않고 말이죠~)

>>> predicted_Y = clf.predict(X)
>>> for i in range(10):
...     print predicted_Y[i], Y[i]

1 1
2 2
2 2
2 2
2 2
2 2
2 2
2 2
2 2
2 2

와우~! 정답이랑 거의 일치하네요~ 물론 처음 10개지만요. 그럼 전체 train dataset에 대해서 예측한 결과와 그 일치율을 계산해보겠습니다. 이는 score함수로 쉽게 가능합니다.

>>> print clf.score(X, Y)
0.640170447264

64%정도의 정확도를 가지네요. Class가 5개(0~4)인 것에 비해서는 정확도가 나쁘지 않죠? 그런데 이것은 training set에 대해서 구한 점수이기 때문에 정확한 지표가 될 순 없습니다. Kaggle에서 제공한 test set을 예측하기 전에 간단하게 우리가 만든 모델이 얼마나 정확한지 샘플 예제를 입력해 봅시다.

>>> sample_X = cv.transform(['It is really really good! Awesome!'])
>>> print clf.predict(sample_X)
[3]
>>> sample_X = cv.transform(['It is bad.. Terrible experience.'])
>>> print clf.predict(sample_X)
[0]

보시면 좋은 평가에 대해서는 만점인 4에 가까운 점수가, 혹평에는 0이 나오는 것을 보니 잘 train된 모델이라고 생각해 볼 수 있겠네요 :)

마지막으로 실제 test dataset을 predict하고 submission을 해 봅시다 :)

>>> test = pd.read_csv('test.tsv', sep='\t')
>>> test_X = cv.transform(test['Phrase'])
>>> test_predicted = clf.predict(test_X)

각 test dataset의 리뷰당 sentiment를 얻었는데요, 이를 제출용 포맷에 맞추어 저장하는 방법은 간단합니다.

>>> with open('prediction.csv', 'w') as f:
...     f.write('PhraseId,Sentiment\n')
...     for i in range(len(test_predicted)):
...         f.write('%d,%d\n' % (test['PhraseId'][i], test_predicted[i]))

#prediction.csv에는 이런식으로 쓰여집니다.
PhraseId,Sentiment
156061,3
156062,3
156063,2
156064,3
156065,3
156066,3
156067,3
156068,2

두구두구.. 우리의 예측은 얼마나 잘 맞을까요!?

img

509등 정도의 성적이네요 :) 가장 기본적인 vectorize와 그 외에 어떤 feature도 추가하지 않은 점, 그리고 SGDClassifier를 전혀 건들지 않은 것 치고는 나쁘지 않은 성적이네요 :) 일단은 여기까지 해서 시리즈를 마무리 하고, 앞으로도 계속해서 다른 재미있는 text mining 예제들도 다루겠습니다 :)