ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [텍스트] 감성 분석 (Sentiment Analysis)
    머신러닝 & 딥러닝 2021. 11. 28. 21:34

    감성 분석 (Sentiment Analysis)

    • 문서의 주관적인 감성/의견/감정/기분 등을 파악하기 위한 방법.

    • 소셜 미디어, 여론 조사, 온라인 리뷰, 피드백 등 다양한 분야에서 활용.

    지도 학습 기반의 분석

    • 지도 학습은 학습 데이터와 타깃 레이블 값을 기반으로 감성 분석 학습을 수행한 뒤 이를 기반으로 다른 데이터의 감성 분석을 예측하는 방법.

    감성 어휘 사전을 이용한 분석

    • 감성 어휘 사전은 감성 분석을 위한 용어와 문맥에 대한 다양한 정보를 가지고 있으며 이를 통해 문서의 긍정적, 부정적 감성 여부 판단.

    • 문서 내 텍스트가 나타내는 여러 가지 주관적인 단어와 문맥을 기반으로 감성 수치를 계산.

    IMDB의 영화 review에 대한 긍정/부정 예측

    import pandas as pd
    
    review_df = pd.read_csv('./labeledTrainData.tsv', header=0, sep="\t", quoting=3)
    review_df.head(3)

    id sentiment review
    0 "5814_8" 1 "With all this stuff going down at the moment ...
    1 "2381_9" 1 "\"The Classic War of the Worlds\" by Timothy ...
    2 "7759_3" 0 "The film starts with a manager (Nicholas Bell...
    print(review_df['review'][0])
    "With all this stuff going down at the moment with MJ i've started listening to his music, watching the odd documentary here and there, watched The Wiz and watched Moonwalker again. Maybe i just want to get a certain insight into this guy who i thought was really cool in the eighties just to maybe make up my mind whether he is guilty or innocent. Moonwalker is part biography, part feature film which i remember going to see at the cinema when it was originally released. Some of it has subtle messages about MJ's feeling towards the press and also the obvious message of drugs are bad m'kay.

    Visually impressive but of course this is all about Michael Jackson so unless you remotely like MJ in anyway then you are going to hate this and find it boring. Some may call MJ an egotist for consenting to the making of this movie BUT MJ and most of his fans would say that he made it for the fans which if true is really nice of him.

    The actual feature film bit when it finally starts is only on for 20 minutes or so excluding the Smooth Criminal sequence and Joe Pesci is convincing as a psychopathic all powerful drug lord. Why he wants MJ dead so bad is beyond me. Because MJ overheard his plans? Nah, Joe Pesci's character ranted that he wanted people to know it is he who is supplying drugs etc so i dunno, maybe he just hates MJ's music.

    Lots of cool things in this like MJ turning into a car and a robot and the whole Speed Demon sequence. Also, the director must have had the patience of a saint when it came to filming the kiddy Bad sequence as usually directors hate working with one kid let alone a whole bunch of them performing a complex dance scene.

    Bottom line, this movie is for people who like MJ on one level or another (which i think is most people). If not, then stay away. It does try and give off a wholesome message and ironically MJ's bestest buddy in this movie is a girl! Michael Jackson is truly one of the most talented people ever to grace this planet but is he guilty? Well, with all the attention i've gave this subject....hmmm well i don't know because people can be different behind closed doors, i know this for a fact. He is either an extremely nice but stupid guy or one of the most sickest liars. I hope he is not the latter."

    데이터 사전 처리 html태그 제거 및 숫자문자 제거

    import re
    
    # <br> html 태그는 replace 함수로 공백으로 변환
    review_df['review'] = review_df['review'].str.replace('<br />',' ')
    
    # 파이썬의 정규 표현식 모듈인 re를 이용하여 영어 문자열이 아닌 문자는 모두 공백으로 변환 
    review_df['review'] = review_df['review'].apply( lambda x : re.sub("[^a-zA-Z]", " ", x) )

    학습/테스트 데이터 분리

    from sklearn.model_selection import train_test_split
    
    class_df = review_df['sentiment']
    feature_df = review_df.drop(['id','sentiment'], axis=1, inplace=False)
    
    X_train, X_test, y_train, y_test= train_test_split(feature_df, class_df, test_size=0.3, random_state=156)
    
    X_train.shape, X_test.shape
    ((17500, 1), (7500, 1))
    

    Pipeline을 통해 Count기반 피처 벡터화 및 머신러닝 학습/예측/평가

    from sklearn.feature_extraction.text import CountVectorizer, TfidfVectorizer
    from sklearn.pipeline import Pipeline
    from sklearn.linear_model import LogisticRegression
    from sklearn.metrics import accuracy_score, roc_auc_score
    
    # 스톱 워드는 English, filtering, ngram은 (1,2)로 설정해 CountVectorization수행. 
    # LogisticRegression의 C는 10으로 설정. 
    pipeline = Pipeline([
        ('cnt_vect', CountVectorizer(stop_words='english', ngram_range=(1,2) )),
        ('lr_clf', LogisticRegression(C=10))])
    
    # Pipeline 객체를 이용하여 fit(), predict()로 학습/예측 수행. predict_proba()는 roc_auc때문에 수행.  
    pipeline.fit(X_train['review'], y_train)
    pred = pipeline.predict(X_test['review'])
    pred_probs = pipeline.predict_proba(X_test['review'])[:,1]
    
    print('예측 정확도는 {0:.4f}, ROC-AUC는 {1:.4f}'.format(accuracy_score(y_test ,pred),
                                             roc_auc_score(y_test, pred_probs)))
    /Users/terrydawunhan/opt/anaconda3/lib/python3.8/site-packages/sklearn/linear_model/_logistic.py:814: ConvergenceWarning: lbfgs failed to converge (status=1):
    STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.
    
    Increase the number of iterations (max_iter) or scale the data as shown in:
        https://scikit-learn.org/stable/modules/preprocessing.html
    Please also refer to the documentation for alternative solver options:
        https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression
      n_iter_i = _check_optimize_result(
    
    예측 정확도는 0.8860, ROC-AUC는 0.9503
    

    Pipeline을 통해 TF-IDF기반 피처 벡터화 및 머신러닝 학습/예측/평가

    # 스톱 워드는 english, filtering, ngram은 (1,2)로 설정해 TF-IDF 벡터화 수행. 
    # LogisticRegression의 C는 10으로 설정. 
    pipeline = Pipeline([
        ('tfidf_vect', TfidfVectorizer(stop_words='english', ngram_range=(1,2) )),
        ('lr_clf', LogisticRegression(C=10))])
    
    pipeline.fit(X_train['review'], y_train)
    pred = pipeline.predict(X_test['review'])
    pred_probs = pipeline.predict_proba(X_test['review'])[:,1]
    
    print('예측 정확도는 {0:.4f}, ROC-AUC는 {1:.4f}'.format(accuracy_score(y_test ,pred),
                                             roc_auc_score(y_test, pred_probs)))
    예측 정확도는 0.8936, ROC-AUC는 0.9598
    

    감성 어휘 사전 기반의 감성 분석

    • SentiWordNet: NLTK패키지의 WordNet과 유사하게 감성 단어 전용의 WordNet을 구현.

      • Synset 별로 세 가지 감성 점수(sentiment score)를 할당.

      • 긍정 감성 지수, 부정 감성 지수, 객관성 지수.

    • VADER: 주로 소셜 미디어의 텍스트에 대한 감성 분석을 제공하기 위한 패키지.

      • 빠른 수행 시간. 대용량 텍스트 데이터에 잘 사용된다.

      • SentimentIntensityAnalyzer 클래스를 이용해 쉽게 감성 분석을 제공.

      • SentimentIntensityAnalyzer 객체를 생성한 뒤에 문서별로 polarity_scores()메서드를 호출해 감성 점수를 구한 뒤, 해당 문서의 감성 점수가 특정 임계값 이상이면 긍정, 그렇지 않으면 부정으로 판단.

      • 'neg'는 부정 감성, 'neu'는 중립, 'pos'는 긍정

    • Pattern : 파이썬 3.x 버전에서 호환되지 않는다. 예측 성능이 좋다.

    SentiWordNet을 이용한 Sentiment Analysis

    1. 문서를 문장 단위로 분해

    2. 다시 문장을 단어 단위로 토큰화하고 품사 태깅 (POS)

    3. 품사 태깅된 단어 기반으로 synset 객체와 senti_synset 객체를 생성

    4. senti_synset에서 긍정 감성/부정 감성 지수를 구하고 이를 모두 합산해 특정 임계치 값 이상일 때 긍정 감성, 그렇지 않을 때 부정 감성으로 결정

    VADER lexicon을 이용한 Sentiment Analysis

    from nltk.sentiment.vader import SentimentIntensityAnalyzer
    
    senti_analyzer = SentimentIntensityAnalyzer()
    senti_scores = senti_analyzer.polarity_scores(review_df['review'][0])
    print(senti_scores)
    {'neg': 0.13, 'neu': 0.743, 'pos': 0.127, 'compound': -0.7943}
    
    def vader_polarity(review,threshold=0.1):
        analyzer = SentimentIntensityAnalyzer()
        scores = analyzer.polarity_scores(review)
    
        # compound 값에 기반하여 threshold 입력값보다 크면 1, 그렇지 않으면 0을 반환 
        agg_score = scores['compound']
        final_sentiment = 1 if agg_score >= threshold else 0
        return final_sentiment
    
    # apply lambda 식을 이용하여 레코드별로 vader_polarity( )를 수행하고 결과를 'vader_preds'에 저장
    review_df['vader_preds'] = review_df['review'].apply( lambda x : vader_polarity(x, 0.1) )
    y_target = review_df['sentiment'].values
    vader_preds = review_df['vader_preds'].values
    print('#### VADER 예측 성능 평가 ####')
    from sklearn.metrics import accuracy_score, confusion_matrix, precision_score 
    from sklearn.metrics import recall_score, f1_score, roc_auc_score
    
    print(confusion_matrix( y_target, vader_preds))
    print("정확도:", accuracy_score(y_target , vader_preds))
    print("정밀도:", precision_score(y_target , vader_preds))
    print("재현율:", recall_score(y_target, vader_preds))
    #### VADER 예측 성능 평가 ####
    [[ 6730  5770]
     [ 1857 10643]]
    정확도: 0.69492
    정밀도: 0.64844939986596
    재현율: 0.85144
    

    댓글