파이썬 스팸분류기 기본 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
  • 표라는 것이 구체적으로 어떤 것을 의미하는가요? 무턱대고 "표" 라고만 하면 알수가 없습니다. 어떤 필요에 의해서 사용하는 것인데 단순히 "표"를 도출하는 방법이라고만 하면 이해를 할 수 없습니다. 정영훈 2020.1.2 22:57
  • 그리고 딥러닝이라고 했는데...위의 머신러닝 알고리즘(knn, SVM, 배깅)은 딥러닝 알고리즘이 아닙니다. 정영훈 2020.1.2 23:05
  • 모호하게 질문드려서 죄송합니다. 알려주신바와 같이 질문 수정하였습니다! 최준호 2020.1.2 23:14

2 답변

  • 좋아요

    1

    싫어요
    채택 취소하기

    아래와 같이 해보면 분류기가 예측한 상황을 볼 수 있습니다.

    즉 어떤 단어들일 경우 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') ...]
    
    • test.csv 파일이 존재할때에는 test = pd.read_csv('test.csv') 이렇게 불러와주면 되는건가요? 최준호 2020.1.3 02:09
  • 아래와 같이 테스트 해보세요.

    그리고 코드를 전혀 이해를 못한 것 같아요. 그러면 의미가 없어요. 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']
    

답변을 하려면 로그인이 필요합니다.

프로그래머스 커뮤니티는 개발자들을 위한 Q&A 서비스입니다. 로그인해야 답변을 작성하실 수 있습니다.

(ಠ_ಠ)
(ಠ‿ಠ)