Main Content

이 번역 페이지는 최신 내용을 담고 있지 않습니다. 최신 내용을 영문으로 보려면 여기를 클릭하십시오.

감성 분류기 훈련시키기

이 예제에서는 주석이 있는 긍정적, 부정적 감성 단어 목록과 사전 훈련된 단어 임베딩을 사용하여 분류기에게 감성 분석을 훈련시키는 방법을 보여줍니다.

사전 훈련된 단어 임베딩은 이 워크플로에서 여러 가지 역할을 합니다. 이 단어 임베딩은 단어를 숫자형 벡터로 변환하고 분류기의 기본을 형성합니다. 사용자는 이 분류기로 벡터 표현을 사용하여 다른 단어들의 감성을 예측할 수 있으며, 이러한 분류를 사용하여 텍스트의 감성을 계산할 수 있습니다. 다음과 같은 네 단계를 사용하여 감성 분류기를 훈련시키고 사용합니다.

  • 사전 훈련된 단어 임베딩을 불러옵니다.

  • 긍정 단어와 부정 단어를 나열하는 의견 어휘사전을 불러옵니다.

  • 긍정 단어와 부정 단어로 구성된 단어 벡터를 사용하여 감성 분류기를 훈련시킵니다.

  • 텍스트 내 단어의 평균 감성 점수를 계산합니다.

사전 훈련된 단어 임베딩 불러오기

단어 임베딩은 단어집에 있는 단어를 숫자형 벡터로 매핑합니다. 이러한 임베딩은 비슷한 단어들이 비슷한 벡터를 갖도록 단어의 의미 체계 정보를 캡처할 수 있습니다. 벡터 연산을 통해 단어 사이의 관계도 모델링합니다. 예를 들어 관계 Rome is to Paris as Italy is to FranceRome-Italy+FranceParis라는 식으로 설명됩니다.

fastTextWordEmbedding 함수를 사용하여 사전 훈련된 단어 임베딩을 불러옵니다. 이 함수를 사용하려면 Text Analytics Toolbox™ Model for fastText English 16 Billion Token Word Embedding 지원 패키지가 필요합니다. 이 지원 패키지가 설치되어 있지 않으면 함수에서 다운로드 링크를 제공합니다.

emb = fastTextWordEmbedding;

의견 어휘사전 불러오기

https://www.cs.uic.edu/~liub/FBS/sentiment-analysis.html의 의견 어휘사전(감성 어휘사전이라고도 함)에서 긍정 단어와 부정 단어를 불러옵니다. [1] 먼저 .rar 파일에서 opinion-lexicon-English 폴더로 파일을 추출한 다음, 텍스트를 가져옵니다.

이 예제 끝부분에 나와 있는 함수 readLexicon을 사용하여 데이터를 불러옵니다. 출력값 data는 단어가 포함된 변수 Word와 범주형 감성 레이블(Positive 또는 Negative)이 포함된 Label로 구성된 테이블입니다.

data = readLexicon;

긍정으로 레이블이 지정된 처음 몇 개의 단어를 표시합니다.

idx = data.Label == "Positive";
head(data(idx,:))
ans=8×2 table
        Word         Label  
    ____________    ________

    "a+"            Positive
    "abound"        Positive
    "abounds"       Positive
    "abundance"     Positive
    "abundant"      Positive
    "accessable"    Positive
    "accessible"    Positive
    "acclaim"       Positive

부정으로 레이블이 지정된 처음 몇 개의 단어를 표시합니다.

idx = data.Label == "Negative";
head(data(idx,:))
ans=8×2 table
        Word          Label  
    _____________    ________

    "2-faced"        Negative
    "2-faces"        Negative
    "abnormal"       Negative
    "abolish"        Negative
    "abominable"     Negative
    "abominably"     Negative
    "abominate"      Negative
    "abomination"    Negative

훈련용 데이터 준비하기

감성 분류기를 훈련시키려면 사전 훈련된 단어 임베딩 emb를 사용하여 단어를 단어 벡터로 변환합니다. 먼저 단어 임베딩 emb에 나타나지 않는 단어를 제거합니다.

idx = ~isVocabularyWord(emb,data.Word);
data(idx,:) = [];

테스트를 위해 무작위로 단어의 10%를 남겨 둡니다.

numWords = size(data,1);
cvp = cvpartition(numWords,'HoldOut',0.1);
dataTrain = data(training(cvp),:);
dataTest = data(test(cvp),:);

word2vec를 사용하여 훈련 데이터의 단어를 단어 벡터로 변환합니다.

wordsTrain = dataTrain.Word;
XTrain = word2vec(emb,wordsTrain);
YTrain = dataTrain.Label;

감성 분류기 훈련시키기

단어 벡터를 긍정 범주와 부정 범주로 분류하는 SVM(서포트 벡터 머신) 분류기를 훈련시킵니다.

mdl = fitcsvm(XTrain,YTrain);

분류기 테스트하기

word2vec를 사용하여 테스트 데이터의 단어를 단어 벡터로 변환합니다.

wordsTest = dataTest.Word;
XTest = word2vec(emb,wordsTest);
YTest = dataTest.Label;

테스트 단어 벡터의 감성 레이블을 예측합니다.

[YPred,scores] = predict(mdl,XTest);

혼동행렬에서 분류 정확도를 시각화합니다.

figure
confusionchart(YTest,YPred);

워드 클라우드에서 분류를 시각화합니다. 긍정 감성인 단어와 부정 감성인 단어를 예측 점수에 해당하는 크기로 워드 클라우드에 플로팅합니다.

figure
subplot(1,2,1)
idx = YPred == "Positive";
wordcloud(wordsTest(idx),scores(idx,1));
title("Predicted Positive Sentiment")

subplot(1,2,2)
wordcloud(wordsTest(~idx),scores(~idx,2));
title("Predicted Negative Sentiment")

텍스트 모음의 감성 계산하기

텍스트(예: 소셜 미디어 업데이트)의 감성을 계산하려면 텍스트의 각 단어에 대한 감성 점수를 예측하고 평균 감성 점수를 구합니다.

filename = "weekendUpdates.xlsx";
tbl = readtable(filename,'TextType','string');
textData = tbl.TextData;
textData(1:10)
ans = 10×1 string array
    "Happy anniversary! ❤ Next stop: Paris! ✈ #vacation"
    "Haha, BBQ on the beach, engage smug mode! 😍 😎 ❤ 🎉 #vacation"
    "getting ready for Saturday night 🍕 #yum #weekend 😎"
    "Say it with me - I NEED A #VACATION!!! ☹"
    "😎 Chilling 😎 at home for the first time in ages…This is the life! 👍 #weekend"
    "My last #weekend before the exam 😢 👎."
    "can’t believe my #vacation is over 😢 so unfair"
    "Can’t wait for tennis this #weekend 🎾🍓🥂 😀"
    "I had so much fun! 😀😀😀 Best trip EVER! 😀😀😀 #vacation #weekend"
    "Hot weather and air con broke in car 😢 #sweaty #roadtrip #vacation"

분석에 사용할 수 있도록 텍스트 데이터를 토큰화하고 전처리하는 함수를 만듭니다. 이 예제의 마지막에 나오는 함수 preprocessText는 다음 단계를 순서대로 수행합니다.

  1. tokenizedDocument를 사용하여 텍스트를 토큰화합니다.

  2. erasePunctuation을 사용하여 문장 부호를 지웁니다.

  3. removeStopWords를 사용하여 불용어(예: "and", "of", "the")를 제거합니다.

  4. lower를 사용하여 소문자로 변환합니다.

전처리 함수 preprocessText를 사용하여 텍스트 데이터를 준비합니다. 이 단계는 실행하는 데 몇 분 정도 소요될 수 있습니다.

documents = preprocessText(textData);

단어 임베딩 emb에 나타나지 않는 단어를 문서에서 제거합니다.

idx = ~isVocabularyWord(emb,documents.Vocabulary);
documents = removeWords(documents,idx);

감성 분류기가 새로운 텍스트에 얼마나 잘 일반화되는지 시각화하기 위해, 텍스트에는 나타나지만 훈련 데이터에는 나타나지 않는 단어들의 감성을 분류하고 워드 클라우드로 시각화합니다. 워드 클라우드를 사용하여 분류기가 예상대로 동작하는지 직접 확인합니다.

words = documents.Vocabulary;
words(ismember(words,wordsTrain)) = [];

vec = word2vec(emb,words);
[YPred,scores] = predict(mdl,vec);

figure
subplot(1,2,1)
idx = YPred == "Positive";
wordcloud(words(idx),scores(idx,1));
title("Predicted Positive Sentiment")

subplot(1,2,2)
wordcloud(words(~idx),scores(~idx,2));
title("Predicted Negative Sentiment")

주어진 텍스트의 감성을 계산하기 위해, 텍스트의 각 단어에 대해 감성 점수를 계산한 후 평균 감성 점수를 계산합니다.

업데이트의 평균 감성 점수를 계산합니다. 각 문서에 대해 단어를 단어 벡터로 변환하고, 단어 벡터에서 감성 점수를 예측하고, 점수 사후 변환 함수를 사용하여 점수를 변환한 다음, 평균 감성 점수를 계산합니다.

for i = 1:numel(documents)
    words = string(documents(i));
    vec = word2vec(emb,words);
    [~,scores] = predict(mdl,vec);
    sentimentScore(i) = mean(scores(:,1));
end

예측한 감성 점수를 텍스트 데이터와 함께 표시합니다. 0보다 큰 점수는 긍정 감성에 해당하고 0보다 작은 점수는 부정 감성에 해당하며 0에 가까운 점수는 중립 감성에 해당합니다.

table(sentimentScore', textData)
ans=50×2 table
       Var1                                                                textData                                                          
    __________    ___________________________________________________________________________________________________________________________

        1.8382    "Happy anniversary! ❤ Next stop: Paris! ✈ #vacation"                                                                       
         1.294    "Haha, BBQ on the beach, engage smug mode! 😍 😎 ❤ 🎉 #vacation"                                                           
        1.0922    "getting ready for Saturday night 🍕 #yum #weekend 😎"                                                                     
      0.094709    "Say it with me - I NEED A #VACATION!!! ☹"                                                                                 
        1.4073    "😎 Chilling 😎 at home for the first time in ages…This is the life! 👍 #weekend"                                          
       -0.8356    "My last #weekend before the exam 😢 👎."                                                                                  
       -1.3556    "can’t believe my #vacation is over 😢 so unfair"                                                                          
        1.4312    "Can’t wait for tennis this #weekend 🎾🍓🥂 😀"                                                                            
        3.0458    "I had so much fun! 😀😀😀 Best trip EVER! 😀😀😀 #vacation #weekend"                                                      
      -0.39243    "Hot weather and air con broke in car 😢 #sweaty #roadtrip #vacation"                                                      
        0.8028    "🎉 Check the out-of-office crew, we are officially ON #VACATION!! 😎"                                                     
       0.38217    "Well that wasn’t how I expected this #weekend to go 👎 Total washout!! 😢"                                                
          3.03    "So excited for my bestie to visit this #weekend! 😀 ❤ 😀"                                                                 
        2.3849    "Who needs a #vacation when the weather is this good ☀ 😎"                                                                 
    -0.0006176    "I love meetings in summer that run into the weekend! Wait that was sarcasm. Bring on the aircon apocalypse! 👎 ☹ #weekend"
       0.52992    "You know we all worked hard for this! We totes deserve this 🎉 #vacation 🎉 Ibiza ain’t gonna know what hit em 😎"        
      ⋮

감성 어휘사전 읽기 함수

이 함수는 감성 어휘사전에서 긍정 단어와 부정 단어를 읽고 테이블을 반환합니다. 테이블에는 변수 WordLabel이 포함됩니다. 여기서 Label에는 각 단어의 감성에 해당하는 범주형 값인 PositiveNegative가 포함됩니다.

function data = readLexicon

% Read positive words
fidPositive = fopen(fullfile('opinion-lexicon-English','positive-words.txt'));
C = textscan(fidPositive,'%s','CommentStyle',';');
wordsPositive = string(C{1});

% Read negative words
fidNegative = fopen(fullfile('opinion-lexicon-English','negative-words.txt'));
C = textscan(fidNegative,'%s','CommentStyle',';');
wordsNegative = string(C{1});
fclose all;

% Create table of labeled words
words = [wordsPositive;wordsNegative];
labels = categorical(nan(numel(words),1));
labels(1:numel(wordsPositive)) = "Positive";
labels(numel(wordsPositive)+1:end) = "Negative";

data = table(words,labels,'VariableNames',{'Word','Label'});

end

전처리 함수

함수 preprocessText는 다음 단계를 수행합니다.

  1. tokenizedDocument를 사용하여 텍스트를 토큰화합니다.

  2. erasePunctuation을 사용하여 문장 부호를 지웁니다.

  3. removeStopWords를 사용하여 불용어(예: "and", "of", "the")를 제거합니다.

  4. lower를 사용하여 소문자로 변환합니다.

function documents = preprocessText(textData)

% Tokenize the text.
documents = tokenizedDocument(textData);

% Erase punctuation.
documents = erasePunctuation(documents);

% Remove a list of stop words.
documents = removeStopWords(documents);

% Convert to lowercase.
documents = lower(documents);

end

참고 문헌

  1. Hu, Minqing, and Bing Liu. "Mining and summarizing customer reviews." In Proceedings of the tenth ACM SIGKDD international conference on Knowledge discovery and data mining, pp. 168-177. ACM, 2004.

참고 항목

| | | | | | |

관련 항목