웹사이트 검색

NLTK(Natural Language Toolkit)를 사용하여 Python 3에서 감정 분석을 수행하는 방법


저자는 Write for DOnations 프로그램을 선택했습니다.

소개

오늘날 생성되는 많은 양의 데이터는 텍스트 데이터를 분석하기 위해 Python에서 일반적으로 사용되는 NLP 라이브러리인 NLTK(Natural Language Toolkit)입니다.

이 자습서에서는 다양한 데이터 정리 방법을 사용하여 NLP용 NLTK 패키지의 샘플 트윗 데이터 세트를 준비합니다. 데이터 세트를 처리할 준비가 되면 사전 분류된 트윗에 대해 모델을 교육하고 모델을 사용하여 샘플 트윗을 부정적인 감정과 긍정적인 감정으로 분류합니다.

이 문서는 주로 데이터 구조, 클래스 및 메서드 사용과 같은 Python 3 시리즈 코딩 방법의 기본 사항에 익숙하다고 가정합니다. 자습서에서는 NLP 및 nltk에 대한 배경 지식이 없다고 가정하지만 이에 대한 약간의 지식이 추가 이점이 있습니다.

전제 조건

  • 이 튜토리얼은 Python 버전 3.6.5를 기반으로 합니다. Python 3가 설치되어 있지 않은 경우 Python 3용 로컬 프로그래밍 환경을 설치하고 설정하는 방법은 다음과 같습니다.
  • 언어 데이터 작업에 익숙할 것을 권장합니다. NLTK를 처음 사용하는 경우 NLTK(Natural Language Toolkit) 가이드를 사용하여 Python 3에서 언어 데이터로 작업하는 방법을 확인하세요.

1단계 - NLTK 설치 및 데이터 다운로드

이 자습서에서는 모든 NLP 작업에 Python의 NLTK 패키지를 사용합니다. 이 단계에서는 NLTK를 설치하고 모델을 훈련하고 테스트하는 데 사용할 샘플 트윗을 다운로드합니다.

먼저 pip 패키지 관리자를 사용하여 NLTK 패키지를 설치합니다.

  1. pip install nltk==3.3

이 자습서에서는 NLTK 패키지의 일부인 샘플 트윗을 사용합니다. 먼저 다음 명령을 실행하여 Python 대화형 세션을 시작합니다.

  1. python3

그런 다음 Python 인터프리터에서 nltk 모듈을 가져옵니다.

  1. import nltk

NLTK 패키지에서 샘플 트윗을 다운로드합니다.

  1. nltk.download('twitter_samples')

Python 인터프리터에서 이 명령을 실행하면 트윗을 로컬로 다운로드하고 저장합니다. 샘플이 다운로드되면 사용할 수 있습니다.

부정적인 트윗과 긍정적인 트윗을 사용하여 자습서의 뒷부분에서 감정 분석에 대해 모델을 교육합니다. 감정이 없는 트윗은 모델을 테스트하는 데 사용됩니다.

자체 데이터 세트를 사용하려는 경우 Twitter API를 사용하여 특정 기간, 사용자 또는 해시태그에서 트윗을 수집할 수 있습니다.

이제 NLTK를 가져오고 샘플 트윗을 다운로드했으므로 exit()를 입력하여 대화형 세션을 종료합니다. 트윗을 가져오고 데이터 처리를 시작할 준비가 되었습니다.

2단계 - 데이터 토큰화

원래 형태의 언어는 기계가 정확하게 처리할 수 없으므로 기계가 이해하기 쉽도록 언어를 처리해야 합니다. 데이터를 이해하는 첫 번째 부분은 토큰화라는 프로세스를 통해 또는 문자열을 토큰이라는 더 작은 부분으로 분할하는 것입니다.

토큰은 단위로 사용되는 텍스트의 일련의 문자입니다. 토큰을 만드는 방법에 따라 단어, 이모티콘, 해시태그, 링크 또는 개별 문자로 구성될 수 있습니다. 언어를 토큰으로 나누는 기본 방법은 공백과 구두점을 기준으로 텍스트를 분할하는 것입니다.

시작하려면 스크립트를 보관할 새 .py 파일을 만드세요. 이 자습서에서는 nlp_test.py를 사용합니다.

  1. nano nlp_test.py

이 파일에서 해당 데이터로 작업할 수 있도록 먼저 twitter_samples를 가져옵니다.

from nltk.corpus import twitter_samples

이렇게 하면 모델을 훈련하고 테스트하기 위한 다양한 트윗이 포함된 NLTK에서 세 개의 데이터 세트를 가져옵니다.

  • negative_tweets.json: 부정적인 감정이 있는 트윗 5000개
  • positive_tweets.json: 긍정적인 감정이 담긴 트윗 5000개
  • tweets.20150430-223406.json: 감정이 없는 트윗 20000개

다음으로 positive_tweets, negative_tweetstext에 대한 변수를 만듭니다.

from nltk.corpus import twitter_samples

positive_tweets = twitter_samples.strings('positive_tweets.json')
negative_tweets = twitter_samples.strings('negative_tweets.json')
text = twitter_samples.strings('tweets.20150430-223406.json')

twitter_samplesstrings() 메서드는 데이터세트 내의 모든 트윗을 문자열로 인쇄합니다. 다른 트윗 모음을 변수로 설정하면 처리 및 테스트가 더 쉬워집니다.

NLTK에서 토크나이저를 사용하기 전에 추가 리소스인 punkt를 다운로드해야 합니다. punkt 모듈은 단어와 문장을 토큰화하는 데 도움이 되는 선행 학습된 모델입니다. 예를 들어, 이 모델은 이름에 마침표(예: "S. Daityari\)가 포함될 수 있으며 문장에서 이 마침표가 반드시 끝나는 것은 아니라는 것을 알고 있습니다. 먼저 Python 대화형 세션을 시작합니다.

  1. python3

세션에서 다음 명령을 실행하여 punkt 리소스를 다운로드합니다.

  1. import nltk
  2. nltk.download('punkt')

다운로드가 완료되면 NLTK의 토크나이저를 사용할 준비가 된 것입니다. NLTK는 .tokenized() 메서드를 사용하여 트윗에 대한 기본 토크나이저를 제공합니다. positive_tweets.json 데이터세트를 토큰화하는 개체를 만드는 줄을 추가합니다.

from nltk.corpus import twitter_samples

positive_tweets = twitter_samples.strings('positive_tweets.json')
negative_tweets = twitter_samples.strings('negative_tweets.json')
text = twitter_samples.strings('tweets.20150430-223406.json')
tweet_tokens = twitter_samples.tokenized('positive_tweets.json')

작동 중인 .tokenized 메서드를 보기 위해 스크립트를 테스트하려면 강조 표시된 콘텐츠를 nlp_test.py 스크립트에 추가하세요. 이렇게 하면 positive_tweets.json 데이터 세트에서 단일 트윗이 토큰화됩니다.

from nltk.corpus import twitter_samples

positive_tweets = twitter_samples.strings('positive_tweets.json')
negative_tweets = twitter_samples.strings('negative_tweets.json')
text = twitter_samples.strings('tweets.20150430-223406.json')
tweet_tokens = twitter_samples.tokenized('positive_tweets.json')[0]

print(tweet_tokens[0])

파일을 저장하고 닫은 후 스크립트를 실행합니다.

  1. python3 nlp_test.py

토큰화 과정은 공백에 대한 단순한 분할이 아니기 때문에 다소 시간이 걸립니다. 몇 분의 처리 후 다음이 표시됩니다.

Output
['#FollowFriday', '@France_Inte', '@PKuchly57', '@Milipol_Paris', 'for', 'being', 'top', 'engaged', 'members', 'in', 'my', 'community', 'this', 'week', ':)']

여기서 .tokenized() 메서드는 @_와 같은 특수 문자를 반환합니다. 이러한 문자는 이 자습서의 뒷부분에서 정규식을 통해 제거됩니다.

이제 .tokenized() 메서드가 어떻게 작동하는지 확인했으므로 # 를 추가하여 스크립트에서 토큰화된 트윗을 인쇄하려면 마지막 줄을 주석 처리하거나 제거해야 합니다. 줄의 시작 부분으로:

from nltk.corpus import twitter_samples

positive_tweets = twitter_samples.strings('positive_tweets.json')
negative_tweets = twitter_samples.strings('negative_tweets.json')
text = twitter_samples.strings('tweets.20150430-223406.json')
tweet_tokens = twitter_samples.tokenized('positive_tweets.json')[0]

#print(tweet_tokens[0])

이제 스크립트가 데이터를 토큰화하도록 구성되었습니다. 다음 단계에서는 스크립트를 업데이트하여 데이터를 정규화합니다.

3단계 - 데이터 정규화

예를 들어 "ran\, "runs\ 및 "running\은 같은 동사인 "run\의 다양한 형태입니다. 분석 요구 사항에 따라 이러한 모든 버전을 동일한 형식인 "run\으로 변환해야 할 수 있습니다. NLP의 정규화는 단어를 표준 형식으로 변환하는 프로세스입니다.

정규화는 의미는 같지만 형식이 다른 단어를 그룹화하는 데 도움이 됩니다. 정규화가 없으면 "ran\, "runs\ 및 "running\은 같은 단어로 취급되기를 원할지라도 다른 단어로 취급됩니다. 이 섹션에서는 stemminglemmatization은 널리 사용되는 두 가지 정규화 기술입니다.

어간 추출은 단어에서 접사를 제거하는 과정입니다. 단순한 동사 형태로만 작업하는 어간 추출은 단어의 끝을 제거하는 휴리스틱 프로세스입니다.

이 자습서에서는 텍스트의 단어에 대한 어휘 및 형태 분석의 컨텍스트로 단어를 정규화하는 표제어 추출 프로세스를 사용합니다. 원형 복원 알고리즘은 단어의 구조와 문맥을 분석하여 정규화된 형식으로 변환합니다. 따라서 속도 비용이 발생합니다. 형태소 분석과 원형 복원의 비교는 궁극적으로 속도와 정확도 사이의 절충안으로 귀결됩니다.

원형 복원 사용을 진행하기 전에 Python 대화형 세션에 다음을 입력하여 필요한 리소스를 다운로드합니다.

  1. python3

세션에서 다음 명령을 실행하여 리소스를 다운로드합니다.

  1. import nltk
  2. nltk.download('wordnet')
  3. nltk.download('averaged_perceptron_tagger')

wordnet은 스크립트가 기본 단어를 결정하는 데 도움이 되는 영어용 어휘 데이터베이스입니다. 문장에서 단어의 컨텍스트를 확인하려면 averaged_perceptron_tagger 리소스가 필요합니다.

다운로드가 완료되면 lemmatizer를 사용할 준비가 거의 완료된 것입니다. lemmatizer를 실행하기 전에 텍스트의 각 단어에 대한 컨텍스트를 확인해야 합니다. 이는 문장에서 단어의 상대적 위치를 평가하는 태깅 알고리즘에 의해 달성됩니다. Python 세션에서 pos_tag 함수를 가져오고 토큰 목록을 인수로 제공하여 태그를 가져옵니다. 파이썬에서 이것을 시도해 봅시다:

  1. from nltk.tag import pos_tag
  2. from nltk.corpus import twitter_samples
  3. tweet_tokens = twitter_samples.tokenized('positive_tweets.json')
  4. print(pos_tag(tweet_tokens[0]))

다음은 pos_tag 함수의 출력입니다.

Output
[('#FollowFriday', 'JJ'), ('@France_Inte', 'NNP'), ('@PKuchly57', 'NNP'), ('@Milipol_Paris', 'NNP'), ('for', 'IN'), ('being', 'VBG'), ('top', 'JJ'), ('engaged', 'VBN'), ('members', 'NNS'), ('in', 'IN'), ('my', 'PRP$'), ('community', 'NN'), ('this', 'DT'), ('week', 'NN'), (':)', 'NN')]

다음은 태그 목록에서 가장 일반적인 항목 목록과 그 의미입니다.

  • NNP: 명사, 고유, 단수
  • NN: 명사, 일반, 단수 또는 질량
  • IN: 전치사 또는 접속사, 종속
  • VBG: 동사, 동명사 또는 현재분사
  • VBN: 동사, 과거분사

다음은 데이터 세트의 전체 목록입니다.

일반적으로 태그가 NN로 시작하면 명사이고 VB로 시작하면 동사입니다. 태그를 검토한 후 exit()를 입력하여 Python 세션을 종료합니다.

이를 문장을 정규화하는 함수에 통합하려면 먼저 텍스트의 각 토큰에 대한 태그를 생성한 다음 태그를 사용하여 각 단어를 표제어로 지정해야 합니다.

문장을 원형 복원하는 다음 함수로 nlp_test.py 파일을 업데이트합니다.

...

from nltk.tag import pos_tag
from nltk.stem.wordnet import WordNetLemmatizer

def lemmatize_sentence(tokens):
    lemmatizer = WordNetLemmatizer()
    lemmatized_sentence = []
    for word, tag in pos_tag(tokens):
        if tag.startswith('NN'):
            pos = 'n'
        elif tag.startswith('VB'):
            pos = 'v'
        else:
            pos = 'a'
        lemmatized_sentence.append(lemmatizer.lemmatize(word, pos))
    return lemmatized_sentence

print(lemmatize_sentence(tweet_tokens[0]))

이 코드는 WordNetLemmatizer 클래스를 가져와 변수 lemmatizer로 초기화합니다.

함수 lemmatize_sentence는 먼저 트윗의 각 토큰의 위치 태그를 가져옵니다. if 문 내에서 태그가 NN으로 시작하면 토큰이 명사로 할당됩니다. 마찬가지로 태그가 VB로 시작하면 토큰이 동사로 지정됩니다.

파일을 저장하고 닫은 후 스크립트를 실행합니다.

  1. python3 nlp_test.py

결과는 다음과 같습니다.

Output
['#FollowFriday', '@France_Inte', '@PKuchly57', '@Milipol_Paris', 'for', 'be', 'top', 'engage', 'member', 'in', 'my', 'community', 'this', 'week', ':)']

동사 being이 어근 형태인 be로 변경되고 명사 membersmember로 변경됨을 알 수 있습니다. . 계속하기 전에 스크립트에서 샘플 트윗을 인쇄하는 마지막 줄을 주석 처리하십시오.

이제 단어를 정규화하는 함수를 성공적으로 만들었으므로 잡음 제거로 이동할 준비가 되었습니다.

4단계 - 데이터에서 노이즈 제거

이 단계에서는 데이터 세트에서 노이즈를 제거합니다. 노이즈는 데이터에 의미나 정보를 추가하지 않는 텍스트의 일부입니다.

노이즈는 각 프로젝트마다 다르므로 한 프로젝트에서 노이즈를 구성하는 요소가 다른 프로젝트에는 없을 수 있습니다. 예를 들어, 한 언어에서 가장 흔한 단어를 불용어라고 합니다. 정지 단어의 몇 가지 예는 "is\, "the\ 및 "a\입니다. 특정 사용 사례가 포함되어야 하는 경우가 아니면 일반적으로 언어를 처리할 때 관련이 없습니다.

이 자습서에서는 Python의 정규식을 사용하여 다음 항목을 검색하고 제거합니다.

  • 하이퍼링크 - Twitter의 모든 하이퍼링크는 URL 단축기 t.co로 변환됩니다. 따라서 텍스트 처리에 그대로 두는 것은 분석에 어떤 가치도 추가하지 않습니다.
  • Twitter 응답 처리 - 이 Twitter 사용자 이름 앞에는 어떤 의미도 전달하지 않는 @ 기호가 옵니다.
  • 구두점 및 특수 문자 - 종종 텍스트 데이터에 컨텍스트를 제공하지만 이 컨텍스트는 처리하기 어려운 경우가 많습니다. 간단히 하기 위해 트윗에서 모든 구두점과 특수 문자를 제거합니다.

하이퍼링크를 제거하려면 먼저 http:// 또는 https://로 시작하고 뒤에 문자, 숫자 또는 특수 문자가 오는 URL과 일치하는 하위 문자열을 검색해야 합니다. 문자. 패턴이 일치하면 .sub() 메서드는 패턴을 빈 문자열로 바꿉니다.

remove_noise() 함수 내에서 단어 형식을 정규화하므로 스크립트에서 lemmatize_sentence() 함수를 주석 처리할 수 있습니다.

nlp_test.py 파일에 다음 코드를 추가하여 데이터 세트에서 노이즈를 제거합니다.

...

import re, string

def remove_noise(tweet_tokens, stop_words = ()):

    cleaned_tokens = []

    for token, tag in pos_tag(tweet_tokens):
        token = re.sub('http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+#]|[!*\(\),]|'\
                       '(?:%[0-9a-fA-F][0-9a-fA-F]))+','', token)
        token = re.sub("(@[A-Za-z0-9_]+)","", token)

        if tag.startswith("NN"):
            pos = 'n'
        elif tag.startswith('VB'):
            pos = 'v'
        else:
            pos = 'a'

        lemmatizer = WordNetLemmatizer()
        token = lemmatizer.lemmatize(token, pos)

        if len(token) > 0 and token not in string.punctuation and token.lower() not in stop_words:
            cleaned_tokens.append(token.lower())
    return cleaned_tokens

이 코드는 노이즈를 제거하고 이전 섹션에서 언급한 정규화 및 원형 복원을 통합하는 remove_noise() 함수를 생성합니다. 이 코드는 트윗 토큰과 불용어의 튜플이라는 두 가지 인수를 사용합니다.

그런 다음 코드는 루프를 사용하여 데이터 세트에서 노이즈를 제거합니다. 하이퍼링크를 제거하기 위해 코드는 먼저 http:// 또는 https://로 시작하고 뒤에 문자, 숫자 또는 특수 문자가 오는 URL과 일치하는 하위 문자열을 검색합니다. . 패턴이 일치하면 .sub() 메서드는 패턴을 빈 문자열 또는 로 바꿉니다.

마찬가지로 @ 언급을 제거하기 위해 코드는 정규식을 사용하여 텍스트의 관련 부분을 대체합니다. 이 코드는 re 라이브러리를 사용하여 @ 기호 다음에 숫자, 문자 또는 _를 검색하고 빈 문자열로 바꿉니다.

마지막으로 라이브러리 문자열을 사용하여 구두점을 제거할 수 있습니다.

이 외에도 별도로 다운로드해야 하는 NLTK의 기본 제공 불용어 세트를 사용하여 불용어를 제거합니다.

Python 대화형 세션에서 다음 명령을 실행하여 이 리소스를 다운로드합니다.

  1. nltk.download('stopwords')

리소스가 다운로드되면 대화형 세션을 종료합니다.

.words() 메서드를 사용하여 불용어 목록을 영어로 가져올 수 있습니다. 기능을 테스트하기 위해 샘플 트윗에서 실행해 보겠습니다. nlp_test.py 파일 끝에 다음 줄을 추가합니다.

...
from nltk.corpus import stopwords
stop_words = stopwords.words('english')

print(remove_noise(tweet_tokens[0], stop_words))

파일을 저장하고 닫은 후 스크립트를 다시 실행하여 다음과 유사한 출력을 수신합니다.

Output
['#followfriday', 'top', 'engage', 'member', 'community', 'week', ':)']

이 함수는 모든 @ 언급, 중지 단어를 제거하고 단어를 소문자로 변환합니다.

다음 단계에서 모델링 연습을 진행하기 전에 remove_noise() 함수를 사용하여 긍정 및 부정 트윗을 정리합니다. 샘플 트윗에서 remove_noise()의 출력을 인쇄하는 줄을 주석 처리하고 nlp_test.py 스크립트에 다음을 추가합니다.

...
from nltk.corpus import stopwords
stop_words = stopwords.words('english')

#print(remove_noise(tweet_tokens[0], stop_words))

positive_tweet_tokens = twitter_samples.tokenized('positive_tweets.json')
negative_tweet_tokens = twitter_samples.tokenized('negative_tweets.json')

positive_cleaned_tokens_list = []
negative_cleaned_tokens_list = []

for tokens in positive_tweet_tokens:
    positive_cleaned_tokens_list.append(remove_noise(tokens, stop_words))

for tokens in negative_tweet_tokens:
    negative_cleaned_tokens_list.append(remove_noise(tokens, stop_words))

이제 샘플 트윗을 정리하는 코드를 추가했으므로 원본 토큰을 샘플 트윗의 정리된 토큰과 비교할 수 있습니다. 이를 테스트하려면 파일에 다음 코드를 추가하여 목록에 있는 500번째 트윗의 두 버전을 비교하십시오.

...
print(positive_tweet_tokens[500])
print(positive_cleaned_tokens_list[500])

파일을 저장하고 닫은 후 스크립트를 실행하십시오. 출력에서 구두점과 링크가 제거되고 단어가 소문자로 변환된 것을 볼 수 있습니다.

Output
['Dang', 'that', 'is', 'some', 'rad', '@AbzuGame', '#fanart', '!', ':D', 'https://t.co/bI8k8tb9ht'] ['dang', 'rad', '#fanart', ':d']

텍스트 전처리 중에 발생할 수 있는 특정 문제가 있습니다. 예를 들어 띄어쓰기가 없는 단어("iLoveYou\)는 하나로 취급되어 분리하기 어려울 수 있습니다. 문제를 해결하기 위해 특정한 것을 작성하지 않는 한 스크립트. 특정 데이터에 대한 노이즈 제거 프로세스를 미세 조정하는 것이 일반적입니다.

이제 작동 중인 remove_noise() 함수를 보았으므로 더 추가할 수 있도록 스크립트에서 마지막 두 줄을 주석 처리하거나 제거하십시오.

...
#print(positive_tweet_tokens[500])
#print(positive_cleaned_tokens_list[500])

이 단계에서는 분석을 보다 효과적으로 수행하기 위해 데이터에서 노이즈를 제거했습니다. 다음 단계에서는 데이터를 분석하여 샘플 데이터 세트에서 가장 일반적인 단어를 찾습니다.

5단계 - 단어 밀도 결정

텍스트 데이터 분석의 가장 기본적인 형태는 단어 빈도를 빼는 것이다. 단일 트윗은 단어의 분포를 찾기에는 너무 작은 엔터티이므로 단어 빈도 분석은 모든 긍정적 트윗에서 수행됩니다.

다음 코드 조각은 조인된 모든 트윗 토큰의 단어 목록을 제공하기 위해 트윗 목록을 인수로 사용하는 get_all_words라는 생성기 함수를 정의합니다. nlp_test.py 파일에 다음 코드를 추가합니다.

...

def get_all_words(cleaned_tokens_list):
    for tokens in cleaned_tokens_list:
        for token in tokens:
            yield token

all_pos_words = get_all_words(positive_cleaned_tokens_list)

이제 트윗 샘플의 모든 단어를 컴파일했으므로 NLTK의 FreqDist 클래스를 사용하여 가장 일반적인 단어를 찾을 수 있습니다. nlp_test.py 파일에 다음 코드를 추가합니다.

from nltk import FreqDist

freq_dist_pos = FreqDist(all_pos_words)
print(freq_dist_pos.most_common(10))

.most_common() 메서드는 데이터에서 가장 자주 나타나는 단어를 나열합니다. 이러한 변경을 수행한 후 파일을 저장하고 닫습니다.

지금 파일을 실행하면 데이터에서 가장 일반적인 용어를 찾을 수 있습니다.

Output
[(':)', 3691), (':-)', 701), (':d', 658), ('thanks', 388), ('follow', 357), ('love', 333), ('...', 290), ('good', 283), ('get', 263), ('thank', 253)]

이 데이터에서 이모티콘 엔터티가 긍정적인 트윗의 가장 일반적인 부분 중 일부를 형성한다는 것을 알 수 있습니다. 다음 단계로 진행하기 전에 상위 10개 토큰을 인쇄하는 스크립트의 마지막 줄을 주석 처리해야 합니다.

요약하면 모델에서 사용하기 위해 트윗을 nltk에서 추출하고 토큰화, 정규화 및 정리했습니다. 마지막으로 데이터의 토큰 빈도도 살펴보고 상위 10개 토큰의 빈도도 확인했습니다.

다음 단계에서는 감정 분석을 위한 데이터를 준비합니다.

6단계 - 모델용 데이터 준비

감정 분석은 글을 쓰고 있는 주제에 대한 저자의 태도를 파악하는 과정입니다. 모델을 교육하기 위해 교육 데이터 세트를 생성합니다. 이는 교육을 위해 각 데이터 세트를 "감정\과 연결해야 하는 지도 학습 기계 학습 프로세스입니다. 이 자습서에서 모델은 "긍정적\ 및 "부정적\ 감정을 사용합니다.

감정 분석을 사용하여 텍스트를 다양한 감정으로 분류할 수 있습니다. 교육 데이터 세트의 단순성과 가용성을 위해 이 자습서에서는 포지티브 및 네거티브의 두 가지 범주로만 모델을 교육하는 데 도움이 됩니다.

모델은 규칙과 방정식을 사용하여 시스템을 설명하는 것입니다. 키가 주어진 사람의 체중을 예측하는 방정식만큼 간단할 수 있습니다. 구축할 감정 분석 모델은 트윗을 긍정적이거나 부정적인 감정과 연결합니다. 데이터 세트를 두 부분으로 분할해야 합니다. 첫 번째 부분의 목적은 모델을 구축하는 것이고 다음 부분은 모델의 성능을 테스트하는 것입니다.

데이터 준비 단계에서는 토큰을 사전 형식으로 변환하여 감정 분석을 위한 데이터를 준비한 다음 학습 및 테스트 목적으로 데이터를 분할합니다.

토큰을 사전으로 변환

먼저 모델에 입력할 데이터를 준비합니다. NLTK의 Naive Bayes 분류기를 사용하여 모델링 연습을 수행합니다. 모델에는 트윗의 단어 목록뿐만 아니라 단어를 키로, True를 값으로 사용하는 Python 사전이 필요합니다. 다음 함수는 정리된 데이터의 형식을 변경하는 생성기 함수를 만듭니다.

다음 코드를 추가하여 정리된 토큰 목록의 트윗을 키가 토큰이고 True가 값인 사전으로 변환합니다. 해당 사전은 positive_tokens_for_modelnegative_tokens_for_model에 저장됩니다.

...
def get_tweets_for_model(cleaned_tokens_list):
    for tweet_tokens in cleaned_tokens_list:
        yield dict([token, True] for token in tweet_tokens)

positive_tokens_for_model = get_tweets_for_model(positive_cleaned_tokens_list)
negative_tokens_for_model = get_tweets_for_model(negative_cleaned_tokens_list)

모델 교육 및 테스트를 위해 데이터 세트 분할

다음으로 NaiveBayesClassifier 클래스 학습을 위한 데이터를 준비해야 합니다. 파일에 다음 코드를 추가하여 데이터를 준비합니다.

...
import random

positive_dataset = [(tweet_dict, "Positive")
                     for tweet_dict in positive_tokens_for_model]

negative_dataset = [(tweet_dict, "Negative")
                     for tweet_dict in negative_tokens_for_model]

dataset = positive_dataset + negative_dataset

random.shuffle(dataset)

train_data = dataset[:7000]
test_data = dataset[7000:]

이 코드는 각 트윗에 긍정 또는 부정 라벨을 붙입니다. 그런 다음 긍정적인 트윗과 부정적인 트윗을 결합하여 데이터 세트를 생성합니다.

기본적으로 데이터에는 모든 긍정적인 트윗과 모든 부정적인 트윗이 차례로 포함됩니다. 모델을 교육할 때 편향이 포함되지 않은 데이터 샘플을 제공해야 합니다. 편향을 피하기 위해 random.shuffle() 메서드를 사용하여 데이터를 무작위로 배열하는 코드를 추가했습니다.

마지막으로 코드는 셔플된 데이터를 교육 및 테스트를 위해 각각 70:30의 비율로 분할합니다. 트윗 수가 10000개이므로 섞인 데이터 세트의 처음 7000개 트윗을 모델 교육에 사용하고 마지막 3000개 트윗을 모델 테스트에 사용할 수 있습니다.

이 단계에서는 정리된 토큰을 사전 형식으로 변환하고 데이터 세트를 무작위로 섞은 다음 교육 및 테스트 데이터로 분할했습니다.

7단계 - 모델 구축 및 테스트

마지막으로 NaiveBayesClassifier 클래스를 사용하여 모델을 빌드할 수 있습니다. .train() 메서드를 사용하여 모델을 훈련하고 .accuracy() 메서드를 사용하여 테스트 데이터에서 모델을 테스트합니다.

...
from nltk import classify
from nltk import NaiveBayesClassifier
classifier = NaiveBayesClassifier.train(train_data)

print("Accuracy is:", classify.accuracy(classifier, test_data))

print(classifier.show_most_informative_features(10))

코드를 추가한 후 파일을 저장하고 닫고 실행합니다. 코드의 출력은 다음과 같습니다.

Output
Accuracy is: 0.9956666666666667 Most Informative Features :( = True Negati : Positi = 2085.6 : 1.0 :) = True Positi : Negati = 986.0 : 1.0 welcome = True Positi : Negati = 37.2 : 1.0 arrive = True Positi : Negati = 31.3 : 1.0 sad = True Negati : Positi = 25.9 : 1.0 follower = True Positi : Negati = 21.1 : 1.0 bam = True Positi : Negati = 20.7 : 1.0 glad = True Positi : Negati = 18.1 : 1.0 x15 = True Negati : Positi = 15.9 : 1.0 community = True Positi : Negati = 14.1 : 1.0

정확도는 모델이 감정을 올바르게 예측할 수 있었던 테스트 데이터 세트의 트윗 비율로 정의됩니다. 테스트 세트에 대한 99.5% 정확도는 꽤 좋습니다.

가장 유익한 기능을 보여주는 테이블에서 출력의 모든 행은 훈련 데이터 세트에서 긍정 및 부정 태그가 지정된 트윗에서 토큰의 발생 비율을 보여줍니다. 데이터의 첫 번째 행은 :( 토큰을 포함하는 모든 트윗에서 긍정 트윗에 대한 부정 트윗의 비율이 2085.61임을 나타냅니다. 흥미롭게도 긍정적인 데이터셋에 :(가 포함된 토큰이 하나 있었던 것 같습니다. 텍스트에서 상위 2개의 구별 항목이 이모티콘임을 알 수 있습니다. 또한 sad 와 같은 단어도 있습니다. 는 부정적인 감정을 유발하는 반면 환영기쁨은 긍정적인 감정과 관련이 있습니다.

다음으로 모델이 Twitter의 임의 트윗에서 어떻게 수행되는지 확인할 수 있습니다. 이 코드를 파일에 추가합니다.

...
from nltk.tokenize import word_tokenize

custom_tweet = "I ordered just once from TerribleCo, they screwed up, never used the app again."

custom_tokens = remove_noise(word_tokenize(custom_tweet))

print(classifier.classify(dict([token, True] for token in custom_tokens)))

이 코드를 사용하면 custom_tweet 변수와 연결된 문자열을 업데이트하여 사용자 지정 트윗을 테스트할 수 있습니다. 이러한 변경을 수행한 후 파일을 저장하고 닫습니다.

스크립트를 실행하여 사용자 정의 텍스트를 분석하십시오. 다음은 예제의 사용자 지정 텍스트에 대한 출력입니다.

Output
'Negative'

긍정적인 트윗을 올바르게 특성화하는지 확인할 수도 있습니다.

...
custom_tweet = 'Congrats #SportStar on your 7th best goal from last season winning goal of the year :) #Baller #Topbin #oneofmanyworldies'

결과는 다음과 같습니다.

Output
'Positive'

긍정적인 감정과 부정적인 감정을 모두 테스트했으므로 변수를 업데이트하여 빈정거림과 같은 더 복잡한 감정을 테스트합니다.

...
custom_tweet = 'Thank you for sending my baggage to CityX and flying me to CityY at the same time. Brilliant service. #thanksGenericAirline'

결과는 다음과 같습니다.

Output
'Positive'

모델은 이 예를 긍정적으로 분류했습니다. 훈련 데이터가 비꼬는 트윗을 부정적으로 분류할 만큼 포괄적이지 않았기 때문입니다. 모델이 빈정거림을 예측하도록 하려면 그에 따라 훈련할 충분한 양의 훈련 데이터를 제공해야 합니다.

이 단계에서는 모델을 빌드하고 테스트했습니다. 또한 특정 예에서 빈정거림을 감지하지 못하는 것과 같은 몇 가지 제한 사항을 살펴보았습니다. 완성된 코드에는 튜토리얼을 따라 남은 아티팩트가 남아 있으므로 다음 단계에서는 코드를 Python의 모범 사례에 맞추는 과정을 안내합니다.

8단계 - 코드 정리(선택 사항)

자습서를 완료했지만 최상의 프로그래밍 방법을 따르도록 nlp_test.py 파일의 코드를 재구성하는 것이 좋습니다. 모범 사례에 따라 코드는 다음 기준을 충족해야 합니다.

  • 모든 가져오기는 파일의 맨 위에 있어야 합니다. 동일한 라이브러리에서 가져온 항목은 단일 문으로 함께 그룹화해야 합니다.
  • 모든 기능은 가져온 후에 정의해야 합니다.
  • 파일의 모든 문은 if __name__ == \__main__\: 조건 아래 있어야 합니다. 이렇게 하면 다른 파일에서 파일의 기능을 가져오는 경우 명령문이 실행되지 않습니다.

새로운 remove_noise 함수에 의해 표제어 정리가 완료되므로 lemmatize_sentence 함수와 함께 튜토리얼을 따라 주석 처리된 코드도 제거합니다.

다음은 nlp_test.py의 정리된 버전입니다.

from nltk.stem.wordnet import WordNetLemmatizer
from nltk.corpus import twitter_samples, stopwords
from nltk.tag import pos_tag
from nltk.tokenize import word_tokenize
from nltk import FreqDist, classify, NaiveBayesClassifier

import re, string, random

def remove_noise(tweet_tokens, stop_words = ()):

    cleaned_tokens = []

    for token, tag in pos_tag(tweet_tokens):
        token = re.sub('http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+#]|[!*\(\),]|'\
                       '(?:%[0-9a-fA-F][0-9a-fA-F]))+','', token)
        token = re.sub("(@[A-Za-z0-9_]+)","", token)

        if tag.startswith("NN"):
            pos = 'n'
        elif tag.startswith('VB'):
            pos = 'v'
        else:
            pos = 'a'

        lemmatizer = WordNetLemmatizer()
        token = lemmatizer.lemmatize(token, pos)

        if len(token) > 0 and token not in string.punctuation and token.lower() not in stop_words:
            cleaned_tokens.append(token.lower())
    return cleaned_tokens

def get_all_words(cleaned_tokens_list):
    for tokens in cleaned_tokens_list:
        for token in tokens:
            yield token

def get_tweets_for_model(cleaned_tokens_list):
    for tweet_tokens in cleaned_tokens_list:
        yield dict([token, True] for token in tweet_tokens)

if __name__ == "__main__":

    positive_tweets = twitter_samples.strings('positive_tweets.json')
    negative_tweets = twitter_samples.strings('negative_tweets.json')
    text = twitter_samples.strings('tweets.20150430-223406.json')
    tweet_tokens = twitter_samples.tokenized('positive_tweets.json')[0]

    stop_words = stopwords.words('english')

    positive_tweet_tokens = twitter_samples.tokenized('positive_tweets.json')
    negative_tweet_tokens = twitter_samples.tokenized('negative_tweets.json')

    positive_cleaned_tokens_list = []
    negative_cleaned_tokens_list = []

    for tokens in positive_tweet_tokens:
        positive_cleaned_tokens_list.append(remove_noise(tokens, stop_words))

    for tokens in negative_tweet_tokens:
        negative_cleaned_tokens_list.append(remove_noise(tokens, stop_words))

    all_pos_words = get_all_words(positive_cleaned_tokens_list)

    freq_dist_pos = FreqDist(all_pos_words)
    print(freq_dist_pos.most_common(10))

    positive_tokens_for_model = get_tweets_for_model(positive_cleaned_tokens_list)
    negative_tokens_for_model = get_tweets_for_model(negative_cleaned_tokens_list)

    positive_dataset = [(tweet_dict, "Positive")
                         for tweet_dict in positive_tokens_for_model]

    negative_dataset = [(tweet_dict, "Negative")
                         for tweet_dict in negative_tokens_for_model]

    dataset = positive_dataset + negative_dataset

    random.shuffle(dataset)

    train_data = dataset[:7000]
    test_data = dataset[7000:]

    classifier = NaiveBayesClassifier.train(train_data)

    print("Accuracy is:", classify.accuracy(classifier, test_data))

    print(classifier.show_most_informative_features(10))

    custom_tweet = "I ordered just once from TerribleCo, they screwed up, never used the app again."

    custom_tokens = remove_noise(word_tokenize(custom_tweet))

    print(custom_tweet, classifier.classify(dict([token, True] for token in custom_tokens)))

결론

이 자습서에서는 Python 3의 nltk 라이브러리를 사용하는 기본 감정 분석 모델을 소개했습니다. 먼저 트윗을 토큰화하고 단어를 정규화하고 노이즈를 제거하여 트윗에 대한 사전 처리를 수행했습니다. 다음으로 데이터에서 자주 발생하는 항목을 시각화했습니다. 마지막으로 트윗을 특정 감정에 연결하는 모델을 구축했습니다.

감독 학습 모델은 교육 데이터만큼만 우수합니다. 모델을 더욱 강화하기 위해 흥분 및 분노와 같은 더 많은 범주를 추가하는 것을 고려할 수 있습니다. 이 자습서에서는 기본 모델을 구축하여 표면만 긁어 보았습니다. 다음은 감정 분석을 수행하는 동안 주의해야 할 다양한 고려 사항에 대한 자세한 가이드입니다.