파이썬 스팸분류기 기본 train 데이터와 이외 test데이터 추가해 결과 도출하는법이 궁금합니다!
조회수 1536회
현재 python을 배우는 학생으로 주어진 코드로 따라하면서 공부하는 중입니다.
http://www.datamarket.kr/xe/index.php?mid=board_BoGi29&document_srl=33272&listStyle=viewer
현재 이 사이트 문서를 보며 따라하고 있고 사이트에 나온 것은 현재 따라한 상태입니다.
질문드리고 싶은 건 지금은 이진 데이터로 스팸 필터기를 공부하는 중인데 text와 smishing 여부 (0,1)가 주어진 train 데이터를 주어진 코드를 문서에 있는대로 만들어 보았는데 text만 주어진 test 데이터를 집어넣어 코드안에 적용시켜서 결과를 내고 이 결과를 모두 출력하고 싶은데 이럴때는 어떻게 하는지 궁금합니다. (결과는 train 데이터와 같이 test 데이터를 text와 smishing여부 (0,1)로 출력하는 것을 의미합니다.)
지금 현재의 코드입니다.
< word2vec을 활용한 spam 메일 분류 >
# ham/spam 데이터 불러오기
import pandas as pd
ham_spam = pd.read_csv('ham_spam.csv')
# ham_spam 데이터에서 "text"와 "category"만 가져와서 리스트로 만들기
data = list(zip(ham_spam['text'],ham_spam['category']))
# text와 category(=label) 나누기
text = [data[i][0] for i in range(len(data))]
label = [data[i][1] for i in range(len(data))]
# 숫자 제거, 문자 아닌 것 제거하고 띄어쓰기(' ') 기준으로 split하여 단어 뽑아내기
import re
text1 = [re.sub('\d+',' ',tmp) for tmp in text]
text2 = [re.sub('\W+',' ',tmp) for tmp in text1]
text_split = [tmp.split(' ') for tmp in text2]
text_split
# train, test 데이터 나누기
from sklearn.cross_validation import train_test_split # 버전에 따라 다름
text_train, text_test, label_train, label_test = train_test_split(text_split, label, random_state = 0)
# text(메일 내용)의 train과 test 를 나눠줌
# 정답인 label(ham인지 spam인지)도 train, test 따로 나눠줌
# random_state : 난수 고정 / test_size(default) : 0.25
print(len(text_train), len(text_test)) # 4169 / 1390
print(len(label_train), len(label_test)) # 4169 / 1390
# stop_words 설정 후 제거하기
# stop_words 설정하기(의미가 없다고 판단되는 단어들)
stop_words = ['are','a','just','in','','am','Am','also','to',
'is','or','and','we','at','it','the','on','for','I','m',
'by','i','on','an','By','be','me','that','Up','But','Are']
# stop words 제거 함수
def rm_stop(token):
final = []
for words in token:
word_list = []
for word in words:
if word.split("/")[0] not in stop_words:
word_list.append(word)
final.append(word_list)
return final
# text에 stop_words 제거하기
text_train = rm_stop(text_train)
text_test = rm_stop(text_test)
text_train
# Word2Vec(CBOW / skip-gram)
# 단어의 문맥적 의미를 보존하면서 단어를 벡터로 표현하는 과정
- CBOW : 주변 N개의 단어들로 target단어를 예측
- skip-gram : target단어로 주변 N개 단어 등장여부를 예측
from gensim.models import Word2Vec
# Skip-gram (sg=1)
model1 = Word2Vec(text_train, size=100, window=10, min_count=10, workers=4, sg=1)
# CBOW (sg=0)
model2 = Word2Vec(text_train, size=100, window=10, min_count=10, workers=4, sg=0)
# size : 한 단어당 몇 차원의 벡터로 만들지
# window : 앞뒤 몇개의 단어를 사용할지
# min_count : 최소 등장 횟수(min_count이하인 단어는 제외)
# sg : CBOW(=0)로 할지 skip-gram(=1)으로 할지
# Text embedding 하기
from sklearn.feature_extraction.text import TfidfVectorizer
from collections import defaultdict
import numpy as np
# 문서 embedding
class TfidfEmbeddingVectorizer:
def __init__(self, word2vec):
self.word2vec = word2vec
def transform(self, X):
tfidf = TfidfVectorizer(analyzer = lambda x : x)
tfidf.fit(X)
max_idf = max(tfidf.idf_)
word2weight = defaultdict(lambda : max_idf, [(w, tfidf.idf_[i]) for w, i in tfidf.vocabulary_.items()])
array_list =[]
for words in X:
array_list.append(np.array(np.mean([self.word2vec[w]*word2weight[w] for w in words if w in self.word2vec] or [np.zeros(100)], axis = 0)))
return(array_list)
vec_tf_skip_gram = TfidfEmbeddingVectorizer(w2v_skip_gram)
vec_tf_CBOW = TfidfEmbeddingVectorizer(w2v_CBOW)
# skip-gram
train_tf_s = vec_tf_skip_gram.transform(text_train)
test_tf_s = vec_tf_skip_gram.transform(text_test)
# CBOW
train_tf_c = vec_tf_CBOW.transform(text_train)
test_tf_c = vec_tf_CBOW.transform(text_test)
# Support Vector Machine
from sklearn.svm import SVC
clf1 = SVC(decision_function_shape='ovo') # SVM 만들기
svc_clf_s = clf.fit(train_tf_s, label_train) # skip-gram
svc_clf_c = clf.fit(train_tf_c, label_train) # CBOW
# 예측값 뽑아내기
svc_pred_s = svc_clf.predict(test_tf_s) # skip-gram
svc_pred_c = svc_clf.predict(test_tf_c) # CBOW
# 정확도 확인
from sklearn import metrics
print(metrics.classification_report(label_test, svc_pred_s)) # skip-gram
precision recall f1-score support
ham 0.98 0.96 0.97 1221
spam 0.75 0.82 0.79 169
avg / total 0.95 0.95 0.95 1390
print(metrics.classification_report(label_test, svc_pred_c)) # CBOW
precision recall f1-score support
ham 0.88 1.00 0.94 1221
spam 0.00 0.00 0.00 169
avg / total 0.77 0.88 0.82 1390
# Skip_gram이 성능이 훨씬 좋다.
# 따라서, skip_gram으로 처리한 text로 다른 모델(K-NN, RF)도 만들어보자
# K-Nearest Neighbor
from sklearn import neighbors, datasets
clf = neighbors.KNeighborsClassifier()
knn_clf = clf.fit(train_tf_s, label_train)
knn_pred = knn_clf.predict(test_tf_s)
knn_pred
print(metrics.classification_report(label_test, knn_pred))
precision recall f1-score support
ham 0.98 0.98 0.98 1221
spam 0.88 0.86 0.87 169
avg / total 0.97 0.97 0.97 1390
# 랜덤 포레스트
from sklearn.ensemble import RandomForestClassifier
clf = RandomForestClassifier()
RF_clf = clf.fit(train_tf_s, label_train)
RF_pred = RF_clf.predict(test_tf_s)
RF_pred
print(metrics.classification_report(label_test, RF_pred))
precision recall f1-score support
ham 0.98 0.99 0.98 1221
spam 0.91 0.86 0.88 169
avg / total 0.97 0.97 0.97 1390
2 답변
-
아래와 같이 해보면 분류기가 예측한 상황을 볼 수 있습니다.
즉 어떤 단어들일 경우 ham 인지 spam 인지 알 수 있습니다.
L = list(zip(text_test[0:10], RF_pred[0:10])) print(L) (['Subject', 'ship', 'channel', 'hub', 'co', 'please', 'review', 'comment', 'attached', 'presentation', 'gary', 'can', 'you', 'jd', 'take', 'ownership', 'of', 'this', 'once', 'incorporate', 'everyone', 's', 'comments', 'can', 'set', 'up', 'meeting', 'with', 'air', 'products', 'dow', 'others', 'discuss', 'thanks', 'brian'], 'ham') ...]
-
아래와 같이 테스트 해보세요.
그리고 코드를 전혀 이해를 못한 것 같아요. 그러면 의미가 없어요. word2vec 사용 및 이해를 위해 NLP 학습이 되어야 하고 사이킷런 사용 및 이해를 위해 머신러닝 알고리즘 선학습이 되어야 합니다.
custom_words1 = [['Subject', 'ship', 'channel', 'hub', 'co', 'please', 'review', 'comment', 'attached', 'presentation', 'gary', 'can', 'you', 'jd', 'take', 'ownership', 'of', 'this', 'once', 'incorporate']] custom_gram1 = vec_tf_skip_gram.transform(custom_words1) print(RF_clf.predict(custom_gram1)) custom_words2 = [['credit', 'mortgage', 'viagra', 'shipped', 'cialis']] custom_gram2 = vec_tf_skip_gram.transform(custom_words2) print(RF_clf.predict(custom_gram2)) ['ham'] ['spam']
댓글 입력