ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Deep Learning] NLP - 통계적 트리밍(Trimming)
    Data Science/Machine Learning & Deep Learning 2021. 4. 15. 00:58

     

     

     

     

     

    자연어 처리에서 불용어 사전을 이용해서 불용어를 직접 제거해주는 방법도 있지만, 

    통계적인 방법을 이용해서 전체 말뭉치에서 너무 많이 쓰였거나 너무 적게 쓰인 토큰을 제거해주는 방법도 있습니다. 

     

     

     

     

    위 왼쪽 그래프는 토큰화 후 토큰의 누적 분포를 나타낸 그래프입니다. 

    그래프를 통해 소수의 단어들이 전체 텍스트 데이터의 약 90%를 차지하고 있음을 알 수 있습니다. 

    이는 전체 말뭉치에서 자주 나타나는 단어들(그래프의 왼쪽)이거나 자주 나타나지 않는 단어들(그래프의 오른쪽)로

    너무 많이 또는 너무 드물게 나타나기 때문에 텍스트 큰 의미를 가지지 못하고 통찰력을 제공하지 못할 확률이 높습니다. 

    따라서 통계적 트리밍으로 너무 많이 쓰인 토큰과 너무 적게 쓰인 토큰을 제거하여 우측 그래프와 같은 분포를 만들어 주겠습니다. 

     

     

     

     

     

    아래 Kaggle의 Women's E-Commerce Clothing Reviews 데이터를 사용하였습니다. 

     

    Women's E-Commerce Clothing Reviews

    23,000 Customer Reviews and Ratings

    www.kaggle.com

     

     

     

     

     

    데이터는 다음과 같이 구성되어 있습니다. 

    df.head(3)

     

     

     

     

     

    데이터에서 리뷰에 해당하는 'Review Text' 를 토큰화 하기 위해서 토큰화 함수 tokenize를 만들어 사용하겠습니다.

    import spacy
    from spacy.tokenizer import Tokenizer
    
    nlp = spacy.load("en_core_web_sm")
    tokenizer = Tokenizer(nlp.vocab)
    
    import re
    
    def tokenize(text):
        """
        토큰화 함수 : text 문자열을 의미있는 단어 단위로 list에 저장합니다.
        """
        tokens = str(text).lower() 
        tokens = re.sub(r"[^a-z0-9 ]", "", tokens)     
        return [token.text for token in tokenizer(x)]
    df['tokens'] = df['Review Text'].apply(lambda x : tokenize(x))
    df.head()

     

     

     

     

     

    통계적 전처리를 위해 말뭉치 전체의 토큰 카운트하고, 순위 등 정보를 담은 데이터 프레임을 리턴하는 함수를 만들어 주겠습니다.

    def word_count(docs):
        """ 토큰화된 문서들을 입력받아 토큰을 카운트 하고 관련된 속성을 가진 데이터프레임을 리턴합니다.
        Args:
            docs (series or list): 토큰화된 문서가 들어있는 list
        Returns:
            list: Dataframe
        """
        # 전체 코퍼스에서 단어 빈도 카운트
        word_counts = Counter()
    
        # 단어가 존재하는 문서의 빈도 카운트, 단어가 한 번 이상 존재하면 +1
        word_in_docs = Counter()
    
        # 전체 문서의 갯수
        total_docs = len(docs)
    
        for doc in docs:
            word_counts.update(doc)
            word_in_docs.update(set(doc))
    
        temp = zip(word_counts.keys(), word_counts.values())
    
        wc = pd.DataFrame(temp, columns = ['word', 'count'])
    
        # 단어의 순위
        # method='first': 같은 값의 경우 먼저나온 요소를 우선
        wc['rank'] = wc['count'].rank(method='first', ascending=False)
        total = wc['count'].sum()
    
        # 코퍼스 내 단어의 비율
        wc['percent'] = wc['count'].apply(lambda x: x / total)
    
        wc = wc.sort_values(by='rank')
    
        # 누적 비율
        # cumsum() : cumulative sum
        wc['cul_percent'] = wc['percent'].cumsum()
    
        temp2 = zip(word_in_docs.keys(), word_in_docs.values())
        ac = pd.DataFrame(temp2, columns=['word', 'word_in_docs'])
        wc = ac.merge(wc, on='word')
        
        # 전체 문서 중 존재하는 비율
        wc['word_in_docs_percent'] = wc['word_in_docs'].apply(lambda x: x / total_docs)
    
        return wc.sort_values(by='rank')

     

     

     

     

     

    많이 쓰인 토큰 상위 10개를 알아보고 토큰의 누적 분포, 빈도를 살펴보겠습니다. 

    wc = word_count(df['tokens'])
    
    # 상위 토큰 10개 단어
    wc.head(10)

     

    import seaborn as sns
    
    # 누적분포그래프
    sns.lineplot(x='rank', y='cul_percent', data=wc);

     

    # 문서에 나타나는 빈도
    sns.displot(wc['word_in_docs_percent'],kind='kde');

     

    상위 10 안에 랭크된 토큰은 대부분 the, i, and, a 등과 같이 해석에 큰 의미를 주지 못하는 불용어입니다. 

    토큰의 누적 분포를 그래프로 살펴보면 소수의 단어들이 전체 텍스트 데이터의 약 90%를 차지하고 있으며,

    많은 수의 토큰이 문서에 등장하는 빈도가 0.05 이하로 빈도가 낮은 것을 알 수 있습니다. 

     

     

     

     

     

    따라서 문서에 너무 많이 등장하는 토큰, 너무 드물게 쓰인 토큰을 제거하기 위해서 

    문서에 등장하는 비율이 10% 미만이고, 최소 2.5% 이상은 등장하는 토큰만을 선택고 다시 상위 10개 토큰을 살펴보겠습니다.

    # 문서 등장 비율이 10% 미만이고, 최소 2.5% 이상 등장하는 단어만 선택
    wc_trim = wc[(wc['word_in_docs_percent'] < 0.10)&(wc['word_in_docs_percent'] >= 0.025)]
    
    # 통계적 트리밍 후 상위 토큰 10개 단어
    wc_trim.head(10)

     

    # 통계적 트리밍 후 누적분포그래프
    sns.lineplot(x='rank', y='cul_percent', data=wc_trim);

     

     

    통계적 트리밍 이전 대부분 불용어가 차지하고 있었던 상위 10개의 토큰이

    통계적 트리밍 이후 불용어 보다 텍스트 분석에 의미를 가질 듯한 토큰들이 차지한 것을 볼 수 있습니다. 

    또한 누적 분포 그래프의 형태를 통해서 빈번하거나 드물게 나타나는 토큰이 제거된 것을 확인할 수 있습니다. 

     

     

     

    통계적 트리밍은 불용어 제거 대신 사용할 수도 있고, 불용어를 제거한 후 통계적 트리밍을 함께 사용할 수도 있습니다. 

     

     

     

     

     

Designed by Tistory.