ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Text 전처리(preprocessing)- english 영어편
    Text Analysis 2021. 11. 24. 00:31

    *본 게시물은 21-2학기 연세대학교 일반대학원 온라인데이터수집과분석(이상엽 교수님) 수업 내용을 정리한 것입니다.

     

      앞선 포스트에서 잠시 text 전처리는 영어와 한국어가 다르다고 말씀드렸었습니다. 언뜻 생각해도 영어는 알파벳이고 한글은 한글자모이니 다를 것 같기도 한데... 정확히 이야기하라고 하면 어렵습니다.ㅠㅠ 

    우선 텍스트 전처리가 무엇인지부터 설명하겠습니다.

     

    텍스트 전처리

      텍스트 전처리란, 텍스트 분석에 적합한 형태로 텍스트를 준비하는 것을 말합니다. 전처리를 거치게 되면 조금 더 정확한 분석 결과 도출이 가능합니다.

      전처리 이후의 결과물은 '불용어가 제거된 특정한 품사들의 단어(ex. 명사)입니다. 비단 명사뿐만이 아니라도, 최종적으로 선택되는 단어들은 해당 문서의 특성을 잘 나타내는 것이어야 합니다. 따라서 최종적으로 선택되는 단어들은 분석 목적에 따라 달라지기도 합니다. 가령 topic 분석은 명사가 주, 감성분석은 형용사, 부사가 주가 됩니다. 

     

      전처리, 특히 영어의 전처리 주요 과정은 다음과 같습니다. 총 7개의 과정을 거치게 됩니다. 

    단계 설명 nltk 예시
    1. 정제
    (cleaning)
    불필요한 기호(! . ' " ;...), 표현 제거 .replace('!', '')
    re.sub('[^\w\d\s]','',content)
    2. 대소문자 변환
    (case conversion)
    소문자 ⇔ 대문자 변환(영어만 해당)
    ∵분석 정확도를 높이기 위해서는 컴퓨터가 동일한 단어로 인식할 수 있게 해야하기 때문
    .lower()
    .upper()
    3. 토큰화
    (tokenization)
    단어, 혹은 토큰 단위로 자르기
    영어의 경우 띄어쓰기 기준의 '단어'가 토큰입니다. 영어는 .split()으로 쉽게 할 수도 있습니다.
    .split()
    nltk.word_tokenize(content)
    4. 품사 태깅
    (part-of-speech tagging)
    단어로 쪼갠 후에는 단어의 품사를 찾아줌
    ∵ 원하는 품사의 단어들만 선택할 경우 분석 결과의 정확도가 향상됨
    nltk.pos_tag(word_tokens)
    5. 원하는 품사만 찾기 원하는 품사의 단어들만 선택할 경우 분석 결과의 정확도가 향상됨 wlem = nltk.WordNetLemmatizer() #생성자 함수를 통해 객체를 생성함 
    lemmatized_words = []
    for word in NN_words:
        new_word = wlem.lemmatize(word)
        lemmatized_words.append(new_word)
    6. lemmatization, stemming 원형(lemma) 혹은 어근(stem)을 찾음 wlem = nltk.WordNetLemmatizer()
    new_word = wlem.lemmatize(word
    7. 불용어(stopword) 제거 nltk는 기본적으로 언어에 따른 불용어 사전 제공
    customized된 사전도 사용 가능 
    from nltk.corpus import stopwords
    stopwords_list = stopwords.words('english')
    customized_stopwords = ['str']

     

    텍스트 전처리 단계에 따른 실제 코드

    위의 총 7개 코드는 다음 예제 코드들로 확인하실 수 있습니다. 

     

    우선, nltk 및 txt 파일을 불러옵니다. 

    1
    2
    3
    4
    5
    6
    7
    import nltk # natural language tool kit # 영어 전처리 모듈 불러오기
    #nltk.download('all') # nltk의 모든 패키지를 다운받을 수 있습니다. 오류 생기면 이 코드를 돌리세요.
     
    # 0. 텍스트 파일 불러오기
    with open('nytimes.txt''r', encoding='utf8'as f:
        content = f.read()
    print(content) # 기사 원문 확인
    dir(content) # 본문(str 타입)에 적용 가능한 문자열 함수 리스트 확인 
    cs

     

    그 다음 1. 정제(cleaning)를 진행해보겠습니다. 

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    # 1. 정제(cleaning) 진행: 불필요한 symbols과 marks 제거하기
     
    #1.1. 아주 기초적인 정제
    content.replace('!',''# 불러온 txt 파일 본문에 있는 !들이 모두 없어집니다
    cleaned_content = content.replace('.','').replace(',','').replace('!',''#순차, 반복적으로 replace() 적용도 가능 
    #그으런데 정제를 위해 계속 저렇게 번잡스럽게 replace를 붙일 수는 없습니다 ㅠㅠ
    # 즉 replace()는 상당히 비효율적입니다.
    # 또한 한번에 하나씩만의 기호가 삭제되기 때문에 삭제하는 기호가 무엇인지를 먼저 알아야 삭제가 가능합니다.
     
    #1.2. regex를 이용한 정제
    import re # 정제의 효율성을 위해 정규표현식(regex)를 사용해야 합니다. 
    cleaned_content = re.sub('[^\w\d\s]','',content) # 바꾸려는 대상, 바꿔지는 것, 본문 순으로 괄호 안 작성 
    print(cleaned_content)
    cs

     

    정제를 진행한 이후에는 2. 대소문자 바꾸기를 진행합니다.

    1
    2
    3
    4
    5
    6
    7
    # 2. Case conversion; 대문자를 소문자로 바꾸기
     
    cleaned_content = cleaned_content.upper() #모두 대문자로 변경
    cleaned_content = cleaned_content.lower() #모두 소문자로 변경
    #string은 immutable하기 때문에 새로운 변수에 저장해야 합니다.
    # 새 변수에 저장하지 않을 경우 날아갑니다 ㅠㅠ
    print(cleaned_content)
    cs

     

    여기서부터는 tokenizing이 진행됩니다. 3. 토큰화를 해보겠습니다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    # 3. Word tokenization(여기서부터 nltk 본격적 사용)
     
    word_tokens = nltk.word_tokenize(cleaned_content) #토크나이징 결과가 리스트로 나옴
     
    print(word_tokens)
     
    '''
    ['hurray', 'for', 'the', 'hotblack', 'coffee', 'cafe', 
    'in', 'toronto', 'for', 'declining', 'to', 'offer'...]
    '''
    print(len(word_tokens)) # 토크나이징 된 단순한 언어 ㅜ 
    print(len(set(word_tokens))) # 중복을 없애서 unique한 단어 수(type)를 구해줌 
    # set은 중복을 지워줄 수 있는 자료형입니다!
    cs

     

    토큰화된 단어들에 대해 POS를 태깅하는 4. 품사 태깅을 진행하겠습니다. 

    품사 태깅 결과는 튜플(단어, pos tag) 형태로 반환이 되며, 이를 활용하여 5. 원하는 품사만 리스트에 골라 담을 수도 있습니다

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    # 4. POS tagging
    '''
    nltk가 제공하는 품사 정보 확인하기
    Tag의 품사 정보 확인하기
    여기에서도 확인 가능: https://www.ling.upenn.edu/courses/Fall_2003/ling001/penn_treebank_pos.html
    nltk.help.upenn_tagset()
    '''
    # 영어의 경우는 nltk에서 제공하는 pos_tag() 함수를 사용해서 품사 태깅을 할 수 있습니다.
    # pos_tag()의 입력값으로는 단어의 리스트가 들어가야 합니다.
    # 즉 아까 토크나이징된 결과를 그대로 가져다 쓸 수 있습니다.
     
    tokens_pos = nltk.pos_tag(word_tokens) #pos_tag function을 사용해서 pos태깅(단어를 가지는 리스트를 인자로 함)
    print(tokens_pos)
     
    # 5 명사 단어만 추출하기(regex 사용; NN.*?)
    #tokens_pos는 튜플을 담은 리스트, 튜플이기 때문에 튜플의 (앞원소, 뒤원소)를 담는 2개의 변수가 필요함
    # 때문에 for문에 word, pos가 들어간 것을 확인하실 수 있습니다.
     
    NN_words = []
    for word, pos in tokens_pos:
        if 'NN' in pos:
            NN_words.append(word)
    print(NN_words)
    cs

     

    품사 태깅을 진행한 후에는 6. lemmatization, stemming을 진행하게 됩니다. 

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    # 6. Lemmatization, stemming
    # nltk에서 제공되는 WordNetLemmatizer을 이용하는 경우 
    # 명사의 경우는 보통 복수 -> 단수 형태로 변형
    # for more details, please see https://textminingonline.com/dive-into-nltk-part-iv-stemming-and-lemmatization
     
     #생성자 함수(nltk.WordNetLemmatizer())를 통해 우선적으로 객체(wlem)를 생성함
    wlem = nltk.WordNetLemmatizer() 
    lemmatized_words = []
    for word in NN_words:
        new_word = wlem.lemmatize(word)
        lemmatized_words.append(new_word)
    # lemmatized_words = [wlem.lemmatize(word) for word in NN_words]
     
    print(lemmatized_words) # 단수로 다 바뀜
    cs

    마지막으로는 7. stopword를 지정해서 불용어 처리를 진행합니다. 

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    # 7. 불용어 ㅓ리 
    from nltk.corpus import stopwords # nltk가 불용어 사전을 제공 
    # 분석의 목적과 상관없이 일반적으로 불용어로 간주되는 단어들(a, the, this)
    #분석의 목적에 따라서 불용어로 간주되는 단어들 : customizing 필요
     
    stopwords_list = stopwords.words('english')
    print(stopwords_list)
    len(stopwords_list)
     
    # 기본사전으로 불용어 제거: nltk에서 제공하는 불용어사전을 이용해서 불용어를 제거할 수 있습니다.
    # 분석의 목적과 상관없이 일반적으로 불용어로 간주되는 단어들(a, the, this)이 포함됩니다.
    from nltk.corpus import stopwords
    stopwords_list = stopwords.words('english'#nltk에서 제공하는 불용어사전 중 영어 불용어사전 이용
    #print('stopwords: ', stopwords_list)
    unique_NN_words = set(lemmatized_words)
    final_NN_words = lemmatized_words
     
    # 불용어 제거2
    for word in unique_NN_words:
        if word in stopwords_list:
            while word in final_NN_words: 
                final_NN_words.remove(word)
    print(final_NN_words)
    '''
    ['hurray', 'hotblack', 'coffee'...]
    '''            
     
    # 제거하거자 하는 단어가 nltk에서 제공되는 사전에 포함되어 있지 않은 경우에, 아래와 같이 직접 만들어 사용할 수도 있습니다.
    #분석의 목적에 따라서 불용어로 간주되는 단어들 : customizing 필요
     
    customized_stopwords = ['be''today''yesterday'"it’s""don’t""new""york""time"# 직접 만든 불용어 사전
    unique_NN_words1 = set(final_NN_words)
    for word in unique_NN_words1:
        if word in customized_stopwords:
            while word in final_NN_words: final_NN_words.remove(word)
     
    print(final_NN_words)
    cs

     

      이렇게 텍스트 데이터 분석을 위한 준비가 완료되었습니다.

      텍스트 데이터 분석은 2가지 방법으로 이루어집니다. 그 중 하나인 ML 알고리즘을 사용하기 위해서는 vectorize가 필요하나, 다른 방법인 ML 알고리즘을 사용하지 않는 분석 방법은 벡터화를 필요로 하지 않습니다.

      대표적인 방법 중 하나는 앞 포스트에서도 다뤘듯이 빈도분석입니다. 빈도분석은 연구 문제를 해결하기 위한 키워드 파악이 강하다는 점에서 중요한 분석입니다. 

      지금까지의 순서는 텍스트 데이터 준비(스크래핑 결과) > 전처리를 통해 불용어가 제거된 특정 품사/형태소들 >빈도분석입니다. 빈도분석을 위해서는 Counter를 주로 많이 사용합니다. 

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    from collections import Counter
     
    # 빈도 세기
    = Counter(final_NN_words) # input type should be a list of words (or tokens)
    print(c)
    '''
    Counter({'health': 11, 'people': 11, 'researcher': 7,...})
    '''
     
    # 상위 빈도 단어+빈도수 출력
    print(c.most_common(10)) # .most_common(): #빈도수 기준 상위 k개 단어 출력
    '''
    [('health', 11), ('people', 11), ('researcher', 7)...]
    '''
     
    #빈도를 바탕으로 한 워드클라우드 생성
    from wordcloud import WordCloud
    import matplotlib.pyplot as plt
    # total_words = ''
    # for word in final_NN_words:
    #     total_words = total_words+' '+word
    total_words = ' '.join(final_NN_words) #리스트 안에 있는 원소들이 '구분자'를 넣어서 하나의 string으로 합쳐집니다.
    wordcloud = WordCloud(max_font_size=50, relative_scaling=.9)
    wordcloud.generate(total_words)
    plt.figure()
    plt.imshow(wordcloud, interpolation='bilinear')
    plt.axis("off")
    plt.show()
    cs

     

     

     

    ㄴㅇ

    ㄹㄴ

    ㄹㄹ

    ㄴㄹ

     

     

    'Text Analysis' 카테고리의 다른 글

    빈도 분석(frequency analysis)- 영어편  (0) 2021.11.24
    Text 전처리(preprocessing)- korean 한글편  (0) 2021.11.24
    Text Analysis의 시작  (0) 2021.11.23

    댓글

Designed by Tistory.