꾸준함이 중요한 Lion2me의 기술블로그

상대적 출현 비율을 통한 키워드 추출

03 Apr 2021
NLP

상대적 출현 비율을 통한 키워드 추출

이 내용은 김현중 박사님께 받은 2020 패스트캠퍼스 수업을 기반으로 작성했음을 알려드립니다.

키워드를 추출하는 방식에는 다양한 방식이 있습니다. 저는 그 중에서 간단한 방식이면서 직관적인 방식인 상대적 출현 비율을 통한 키워드 추출을 해보겠습니다.

상대적 출현 비율이란 말 그대로 특정 단어가 특정 군집에서 얼마나 사용되었는가에 대한 비율을 말합니다. 예를 들어 애완동물 커뮤니티와 직업 커뮤니티의 글을 분석할 때 강아지라는 단어는 직업 커뮤니티보다 애완동물 커뮤니티에서 등장 할 확률이 높을 것 입니다.

상대적 출현 비율을 구하는 방법을 말하자면 특정 군집에서 원하는 단어의 수를 계산 한 뒤 비교하고자 하는 군집의 단어 수와 합한 후 나누어 주면 됩니다. 식으로 표현하면 다음과 같습니다.

\[score = \frac {P('강아지'|D_{pet})} {P('강아지'|D_{pet}) + P('강아지'|D_{work})}\]

실제로 어떤 결과가 나오는지 직접 코드를 작성해보도록 하겠습니다.

1. 데이터 수집

https://github.com/lovit/petitions_dataset

저는 lovit님의 github 소스를 통해 국민청원 데이터를 수집하였습니다. 소스의 사용방법에 대해서는 위의 사이트로 접속하여 쉽게 사용할 수 있으니 설명하지 않겠습니다.

2. 데이터 전처리

이번 예제에서는 분류 및 임베딩 방식이 따로 들어가지 않고 그저 Frequency만을 이용하는 방식이므로 불필요한 텍스트를 삭제하는 정규표현식을 사용하여 데이터를 제거하였습니다.

mean_ful_reg = re.compile('[^가-힣a-zA-Z\s]+')

double_space_reg = re.compile('[\s]+')

3. Counter 작성

def LionCounter(*args):

    all_Count_Vector = defaultdict(int)

    word_set = sorted(' '.join(list(reduce(lambda x, y: x + y, args))).split(' '))

    dict_template = defaultdict(int, {key: 0 for key in word_set})

    args_dicts = [copy(dict_template) for idx in range(len(args))]

    all_Count_Vector = Counter(word_set)

    for idx in range(len(args)):
        args_dicts[idx].update(Counter(' '.join(args[idx]).split(' ')))

    return {'부분': args_dicts, '전체': all_Count_Vector}

LionCounter는 이러한 데이터 별 Count를 계산하는 알고리즘이 자주 등장할 것 같아서 전체 데이터에 대한 등장 빈도와 데이터 별 등장 빈도를 따로 계산해주는 방식으로 만들어 보았습니다.

사실 sklearn의 CounterVectorize를 사용하는 방식과 비슷하지만 직접 만들어보고 싶은 마음이 있어서 만들어보았습니다. 또한 이 방식에서는 여러 리스트를 넣으면 각각의 등장빈도를 따로따로 구해줌으로써 소스를 좀 짧게 해보자라는 생각으로 만들어보았습니다.

이후에 상대적 출현 비율을 계산할 때 이 Counter를 사용합니다.

결과는 다음과 같습니다.

tmp = LionCounter(dataset['일자리'],dataset['반려동물'])
tmp

ex_screenshot

4. 상대적 출현 비율 함수 작성

def LionRelativeAppearanceRatio(*args):
    Counters_ = LionCounter(*args)

    words = list(Counters_['전체'].keys())
    max_count = np.array(list(Counters_['전체'].values()))

    appearance_ratio = []

    for idx in range(len(args)):
        appearance_ratio.append(np.array(list(Counters_['부분'][idx].values())) / max_count)

    result = defaultdict(list)

    for idx,ratio in enumerate(get_elements_in_2D_list(appearance_ratio)):
        result[words[idx]] = ratio

    return result

LionRelativeAppearanceRatio 함수는 LionCounter를 사용하여 모든 리스트에서 해당 단어의 등장 빈도를 구해주는 함수입니다.

이 함수를 이용하여 강아지라는 단어의 점수를 각각 살펴보겠습니다

tmp = LionRelativeAppearanceRatio(dataset['일자리'],dataset['반려동물'])

print(tmp['강아지'])

'[0.0044004400440044, 0.9955995599559956]'

LionRelativeAppearanceRatio를 사용하면 2개 이상의 리스트에서도 점수를 추출할 수 있습니다. 3개의 데이터에서 강아지 단어의 점수를 살펴보겠습니다.


tmp = LionRelativeAppearanceRatio(dataset['일자리'],dataset['반려동물'],dataset['미래'])
print(tmp['강아지'])
'[0.0043859649122807015, 0.9923245614035088, 0.003289473684210526]'

역시나 예상했던대로 반려동물에 대한 토픽에서 강아지라는 단어가 가장 많이 쓰였다는 것을 알 수 있습니다. 동시에 반려동물에 대한 토픽에서 “강아지”는 높은 대표성을 가지고 있다. = 키워드일 가능성이 높다. 와 같은 추측을 할 수 있습니다.

참조

https://lovit.github.io/nlp/2018/04/12/proportion_keywords/