앞서 Part I과 Part 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
두구두구.. 우리의 예측은 얼마나 잘 맞을까요!?
509등 정도의 성적이네요 :) 가장 기본적인 vectorize와 그 외에 어떤 feature도 추가하지 않은 점, 그리고 SGDClassifier를 전혀 건들지 않은 것 치고는 나쁘지 않은 성적이네요 :) 일단은 여기까지 해서 시리즈를 마무리 하고, 앞으로도 계속해서 다른 재미있는 text mining 예제들도 다루겠습니다 :)