Data Science/자연어 처리 (NLP)

[자연어 처리] 불용어(Stop Words) 처리하기 - Python3, Windows 10

 

아래 글에서 이어지는 내용이다.

foreverhappiness.tistory.com/30

 

[자연어 처리] KoNLPy를 사용하여 형태소 분석 및 DTM 만들기 - Python3, Windows 10 (feat. Okt, Pandas, Scikit-Le

아래 글에서 이어지는 내용이다. foreverhappiness.tistory.com/28 BeautifulSoup를 활용한 웹 크롤링(Web Crawling) - Python3, Windows 10 (2) 아래 글에서 이어지는 내용이다. https://foreverhappiness.me/27..

foreverhappiness.tistory.com

 

지난 시간까지 한 내용들을 전반적으로 정리해보자면

 

  • 특정 주소를 웹 크롤링하여 1차 필터링하며 데이터 획득

  • 형태소 분석 기술을 통해 명사 데이터만 추출

  • 추출한 데이터들을 기반으로 DTM (Document-Term Matrix, 문서 단어 행렬) 제작

 

다음과 같이 될 것이다.

 

하지만 중간에 한 가지 문제점이 있었다.

명사 데이터만 추출했지만 원하는 명사가 완벽하게 걸러내 지지 않아 선뜻 보기에 명사가 아닌 데이터까지 함께 들어가 있는 것이다.

 

이를 처리해주기 위해 불용어(Stop Words)를 걸러내주는 작업이 필요하다.

 

사실 불용어 처리는 상당히 노가다 작업이며 쓸만한 툴이 별로 없다.

 


 

우선 지금까지 작업했던 소스 코드를 보자.

 

import pandas as pd
from tqdm import tqdm
from konlpy.tag import Okt
from sklearn.feature_extraction.text import CountVectorizer
# DTM을 편리하게 만들어주기 위해 Scikit-Learn에서 제공하는 CountVectorizer를 import 한다.


# 자연어 처리(형태소 분석 - 명사) 및 각 단어에 대한 DTM 제작
def NLP_DTM():
    # 타이틀 리스트를 불러와서 title_list 변수에 저장한다.
    t_file_name = open('D:\crawling\Title_List.txt', 'r', encoding='utf-8')

    title_list = []
    for line in t_file_name.readlines():
        # txt파일을 readlines로 불러오면 개행 문자도 함께 읽어오기 때문에 인덱싱으로 처리해준다.
        title_list.append(line[:-1])

    t_file_name.close()

    # pandas의 read_csv 함수를 이용하여 csv 파일을 불러온다.
    dataset = pd.read_csv('D:\crawling\crawling_data.csv')

    # 각 형태소별로 분류(Tagging)해주는 Okt 객체를 불러온다.
    tagger = Okt()

    for title in tqdm(title_list, desc='타이틀 리스트 진행도'):  # title_list에 대해 반복문을 실행
        # 각 타이틀에 대한 6770개 문서의 DTM을 표현하기 위해
        # CountVectorizer 객체를 선언
        cv = CountVectorizer()

        # 각 문서들의 말뭉치(corpus)를 저장할 리스트 선언
        corpus = []

        # 각 타이틀에 대한 문서들의 말 뭉치를 저장한다. (데이터가 많으면 이 부분에서 장시간이 소요될 수 있다.)
        for doc_num in tqdm(range(6770), desc='문서 진행도'):
            # 각 말뭉치에서 명사 리스트를 만든다.
            noun_list = tagger.nouns(dataset[title].loc[doc_num])

            # 이를 문자열로 저장해야하기 때문에 join함수로 공백으로 구분해 corpus에 append한다.
            corpus.append(' '.join(noun_list))

        # CountVectorizer의 fit_transform 함수를 통해 DTM을 한번에 생성할 수 있다.
        DTM_Array = cv.fit_transform(corpus).toarray()

        # feature_names 함수를 사용하면 DTM의 각 열(column)이 어떤 단어에 해당하는지 알 수 있다.
        feature_names = cv.get_feature_names()

        # 추출해낸 데이터를 DataFrame 형식으로 변환한다.
        DTM_DataFrmae = pd.DataFrame(DTM_Array, columns=feature_names)

        # 최종적으로 DTM을 csv 파일로 저장한다.
        DTM_DataFrmae.to_csv('D:\crawling\DTM.csv', encoding='utf-8-sig')


if __name__ == '__main__':
    NLP_DTM()

 

앞전의 마지막 소스와 달라진 점이 있다.

바로 tqdm이라는 모듈이 추가되었다.

 

반복문의 진행도를 나타내주는 tqdm 모듈을 사용하면 프로그램이 어느 정도까지 진행되었는지 시각적으로 확인할 수 있다.

 

tqdm 라이브러리에 대해서는 아래 링크를 참고하면 된다.

foreverhappiness.tistory.com/31

 

반복문이 얼마나 진행되었는지 알고싶다면? Python, tqdm

코딩을 하다 보면 가끔 반복문이 얼마나 진행되었는지 알고 싶을 때가 있다. 마치 게임을 시작하기 전에 설치 과정에서 몇%만큼 설치되었는지 알 수 있는 것처럼. Python 언어에는 이미 그런 라이

foreverhappiness.tistory.com

 


 

위 코드에서 Title_List.txt에는 "화재 및 폭발 가능성" 하나만 들어가 있다.

그럼 DTM에는 6770개의 문서 데이터에 대해 "화재 및 폭발 가능성"에 해당하는 데이터만 추출한 다음 이를 명사로 나누어 각 빈도수가 저장되어 있을 것이다.

 

근데 이 중 걸러내야 할 것들이 보인다.

 

먼저 어떤 단어들이 추출해내었는지 봐야 하니 feature_names를 출력해보자.

 

 

그러면 이렇게 DTM에 어떠한 단어들이 들어있는지 확인할 수 있다.

그런데 중간중간에 필요 없는 단어들이 보인다.

화재 및 폭발 가능성과 전혀 관계없는 가끔, 거의, 더욱, 덕분 등등.. 또한 내적인, 덮어서와 같이 명사가 아닌 것들도 보인다.

 

이런 것들을 걸러주기 위해 약간의 노가다 작업이 필요하다.

 

우리는 이것을 조금이나마 용이하게 하기 위해 Title_List를 텍스트 파일에 저장했던 것처럼 StopWords.txt를 만들어 필요 없는 단어들을 골라낼 것이다.

 

 

물론 이것은 사람에 따라 생각하기 나름이라 필요에 따라 업데이트를 해주면서 작업하면 된다.

 

이제 이 불용어(Stop Words) 리스트에 있는 것들만 빼고 DTM을 만들어보자.

 

import pandas as pd
from tqdm import tqdm
from konlpy.tag import Okt
from sklearn.feature_extraction.text import CountVectorizer
# DTM을 편리하게 만들어주기 위해 Scikit-Learn에서 제공하는 CountVectorizer를 import 한다.


# 자연어 처리(형태소 분석 - 명사) 및 각 단어에 대한 DTM 제작
def NLP_DTM():
    # 타이틀 리스트를 불러와서 title_list 변수에 저장한다.
    t_file_name = open('D:\crawling\Title_List.txt', 'r', encoding='utf-8')

    title_list = []
    for line in t_file_name.readlines():
        # txt파일을 readlines로 불러오면 개행 문자도 함께 읽어오기 때문에 인덱싱으로 처리해준다.
        title_list.append(line[:-1])

    t_file_name.close()

    # 불용어 파일을 불러와서 stop_words_list 변수에 저장한다.
    s_file_name = open('D:\crawling\StopWords.txt', 'r', encoding='utf-8')

    stop_words_list = []
    for line in s_file_name.readlines():
        # 위에서는 인덱싱으로 처리했지만 rstrip 함수를 사용하여 공백을 제거할 수도 있다.
        stop_words_list.append(line.rstrip())

    s_file_name.close()

    # pandas의 read_csv 함수를 이용하여 csv 파일을 불러온다.
    dataset = pd.read_csv('D:\crawling\crawling_data.csv')

    # 각 형태소별로 분류(Tagging)해주는 Okt 객체를 불러온다.
    tagger = Okt()

    for title in tqdm(title_list, desc='타이틀 리스트 진행도'):  # title_list에 대해 반복문을 실행
        # 각 타이틀에 대한 6770개 문서의 DTM을 표현하기 위해
        # CountVectorizer 객체를 선언
        cv = CountVectorizer()

        # 각 문서들의 말뭉치(corpus)를 저장할 리스트 선언
        corpus = []

        # 각 타이틀에 대한 문서들의 말 뭉치를 저장한다. (데이터가 많으면 이 부분에서 장시간이 소요될 수 있다.)
        for doc_num in tqdm(range(6770), desc='문서 진행도'):
            # 각 말뭉치에서 명사 리스트를 만든다.
            noun_list = tagger.nouns(dataset[title].loc[doc_num])

            # 이를 문자열로 저장해야하기 때문에 join함수로 공백으로 구분해 corpus에 append한다.
            corpus.append(' '.join(noun_list))

        # CountVectorizer의 fit_transform 함수를 통해 DTM을 한번에 생성할 수 있다.
        DTM_Array = cv.fit_transform(corpus).toarray()

        # feature_names 함수를 사용하면 DTM의 각 열(column)이 어떤 단어에 해당하는지 알 수 있다.
        feature_names = cv.get_feature_names()

        # 추출해낸 데이터를 DataFrame 형식으로 변환한다.
        DTM_DataFrmae = pd.DataFrame(DTM_Array, columns=feature_names)

        # 열 제거는 drop 함수를 사용하며 axis 속성을 columns로 준 후 inplace를 True로 한다.
        DTM_DataFrmae.drop(stop_words_list, axis='columns', inplace=True)

        # 최종적으로 DTM을 csv 파일로 저장한다.
        DTM_DataFrmae.to_csv('D:\crawling\DTM.csv', encoding='utf-8-sig')


if __name__ == '__main__':
    NLP_DTM()

 

먼저 StopWords.txt에 있는 불용어들을 stop_words_list에 담아준다.

 

그리고 이것을 제거할 때는 데이터를 DataFrame 형식으로 변환한 후 drop 함수를 사용하여 편하게 할 수 있다.

이때 axis를 'columns'로 주어야 하며 inplace 속성을 True로 해줘야 한다.

 

여기서 주의해야 할 점이 있다.

stop_words_list의 각 단어들은 feature_names에 꼭 있어야 한다.

만약 없다면 Key Error가 발생하기 때문에 반복문을 돌려가며 단어마다 있는지 없는지 체크해줘야 한다.

 

그리고 이 drop 부분은 아래와 같이 쓸 수도 있다.

 

DTM_DataFrame = DTM_DataFrmae.drop(stop_words_list, axis=1)

 


 

불용어 처리 모듈로 nltk가 있기는 하지만 한국어는 제공을 하지 않으며 크게 사용도가 높지 않기 때문에 추후 업데이트가 된다면 그때 소개를 하겠다.

 

여기까지 불용어(Stop Words)를 처리하는 방법에 대해 알아보았고, 다음 포스팅부터는 이 유효한 데이터들을 어떻게 사용할 것인지 알아보도록 하겠다.