편집 기록

편집 기록
  • 프로필 nowp님의 편집
    날짜2020.01.03

    파이썬 스팸분류기 기본 train 데이터와 이외 test데이터 추가해 결과 도출하는법이 궁금합니다!


    현재 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.01.03

    파이썬 스팸분류기 기본 train 데이터와 이외 test데이터 추가해 결과 도출하는법이 궁금합니다!


    현재 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