[6/6] 파이썬 고객 리뷰 분석: 배달앱 데이터로 배우는 텍스트 마이닝

맛집 리뷰 데이터 분석
맛집 리뷰 데이터 분석
맛집 리뷰 데이터 분석

장사가 너무 잘 되어서 리뷰 1억개가 쌓였다고 가정해 보겠습니다.

그리고 이 리뷰를 각각 어떤 내용인지 분류해야 하는 상황이라고 상상해 보겠습니다.


사람이 1억개의 리뷰를 일일이 분류 하는 게 가능할까요?

아마 어려울 겁니다. 할 수 있다고 한들, 매우 비효율적인 일일겁니다.


이런 비효율적인 일은 컴퓨터에 맡기면 됩니다.

파이썬 scikit-learnd에 있는 KMeans 알고리즘을 이용하면, 1억개의 리뷰를 손쉽게 분류할 수 있습니다. 심지어 원하는 분류 개수도 지정할 수 있습니다.

1억개를 4개 주제로 분류해달라고 하면, 그렇게 요청하면 됩니다. 5개, 6개 역시 마찬가지입니다.


어떻게 하면 이런 요청을 파이썬에서 할 수 있을까요?

이번 글에서는 "비슷한 리뷰 내용은 어떤 게 있을까?"라는 질문에 답하기 위해서 KMeans 알고리즘과 TSNE를 활용한 방법을 소개하겠습니다.

장사가 너무 잘 되어서 리뷰 1억개가 쌓였다고 가정해 보겠습니다.

그리고 이 리뷰를 각각 어떤 내용인지 분류해야 하는 상황이라고 상상해 보겠습니다.


사람이 1억개의 리뷰를 일일이 분류 하는 게 가능할까요?

아마 어려울 겁니다. 할 수 있다고 한들, 매우 비효율적인 일일겁니다.


이런 비효율적인 일은 컴퓨터에 맡기면 됩니다.

파이썬 scikit-learnd에 있는 KMeans 알고리즘을 이용하면, 1억개의 리뷰를 손쉽게 분류할 수 있습니다. 심지어 원하는 분류 개수도 지정할 수 있습니다.

1억개를 4개 주제로 분류해달라고 하면, 그렇게 요청하면 됩니다. 5개, 6개 역시 마찬가지입니다.


어떻게 하면 이런 요청을 파이썬에서 할 수 있을까요?

이번 글에서는 "비슷한 리뷰 내용은 어떤 게 있을까?"라는 질문에 답하기 위해서 KMeans 알고리즘과 TSNE를 활용한 방법을 소개하겠습니다.

비슷한 리뷰 내용은 어떤 게 있을까?


1. 파이썬으로 앱 리뷰 데이터 불러오기 및 확인하기

먼저 판다스(pandas)를 사용해 데이터를 불러옵니다.


import pandas as pd

df = pd.read_excel('92년생김치찜.xlsx')

df.head()


이 코드는 '92년생김치찜.xlsx' 파일을 읽어와 df라는 변수에 저장합니다. df.head()로 데이터의 첫 5행을 확인할 수 있습니다.


2. 결측치 확인 및 제거하기

결측치는 비어있는 데이터를 말합니다. 이는 분석 결과를 왜곡시킬 수 있으므로 처리해야 합니다.


# 결측치 확인

print(df.isnull().sum())

# 결측치 제거

df = df.dropna()


첫 번째 줄은 각 열의 결측치 개수를 보여주고, 두 번째 줄은 모든 결측치를 제거합니다.

3. 텍스트 데이터 전처리하기

이제 텍스트 데이터를 정제해야 합니다. 이를 위해 정규표현식을 사용합니다.


import re

def clean_text(text):

    # 한글, 영문, 숫자만 남기고 나머지는 제거

    cleaned_text = re.sub(r'[^가-힣a-zA-Z0-9\s]', '', text)

    # 여러 개의 공백을 하나의 공백으로 변경

    cleaned_text = re.sub(r'\s+', ' ', cleaned_text)

    # 앞뒤 공백 제거

    cleaned_text = cleaned_text.strip()

    return cleaned_text

# 모든 리뷰에 대해 정제 작업 수행

cleaned_CONTENT_list = []

for sentence in df['CONTENT']:

    cleaned_sentence = clean_text(sentence)

    cleaned_CONTENT_list.append(cleaned_sentence)


리뷰 텍스트에는 특수문자나 이모티콘 등이 많이 사용 되기 때문에, 정규표현식이 자주 사용 됩니다.

정규표현식을 일일이 작성하기 어려우니 함수로 지정해 둡니다.


4. 파이썬을 이용해 고객 리뷰 텍스트 벡터화하기

이제 AI가 텍스트를 이해할 수 있도록 숫자로 변환하는 과정을 거칩니다. 이를 위해 TfidfVectorizer를 사용합니다.


from sklearn.feature_extraction.text import TfidfVectorizer

tfidf_vectorizer = TfidfVectorizer()

review_dtm = tfidf_vectorizer.fit_transform(cleaned_CONTENT_list)

df_review_dtm = pd.DataFrame(review_dtm.toarray(), columns=tfidf_vectorizer.get_feature_names_out())


이 과정은 각 단어에 중요도를 부여하는 과정입니다. TF-IDF에 관한 자세한 수식은 공식 문서에서 확인할 수 있습니다.

5. 파이썬으로 앱 리뷰 군집화하기: 비슷한 내용 분류

이제 KMeans 알고리즘을 사용해 비슷한 리뷰들을 그룹화합니다.


from sklearn.cluster import KMeans

kmeans = KMeans(n_clusters=10, n_init='auto', random_state=42)

kmeans.fit(df_review_dtm)

clusters = kmeans.labels_

df_review = pd.DataFrame({'review': cleaned_CONTENT_list, 'label': clusters})

print(df_review['label'].value_counts())


'n_clusters=10'는 '10개 바구니를 지정할게. 이 바구니 안에 비슷한 단어를 넣어봐'라고 지정하는 거라고 생각 하면 됩니다.

'n_init='auto''는 '컴퓨터야, 군집화 할 때 너가 알아서 해'라고 신호를 주는 것과 같습니다. 해당 코드가 없어도 코드 실행은 되지만, 오류 문구가 뜹니다. 원활한 분석을 위해서는 n_init='auto'을 적용해 주는 게 좋습니다.


'random_state=42'는 제가 출력한 결과와 여러분이 출력한 결과 값을 동일하게 보고 싶을 때 사용 하는 겁니다. (코드를 변경 없이 그대로 사용할 경우)

여기서 '42'라는 숫자는 큰 의미는 없습니다. 1로 적어도 되고, 3으로 적어도 됩니다. 아무 거나 적어도 되지만, 프로그래머들은 관례적으로 42를 입력합니다.


덧붙이자면, 42라는 숫자는 '은하수를 여행하는 히치하이커를 위한 안내서'라는 소설에서 나온 숫자입니다.

해당 소설에는 엄청난 컴퓨터(?)가 등장하는데, 그 컴퓨터가 750만 년 동안 계산한 끝에 '생명, 우주, 그리고 모든 것에 대한 궁극적인 질문의 답 개수가 42개'라는 답을 냈다고 합니다.

프로그래머가 왜 이 42라는 숫자를 선호 하게 됐는지 그 이유에 관해서는 명확히 알기 어렵습니다만, 그냥 42는 관례적으로 사용한다고 아시면 됩니다.

6. 차원 축소 및 시각화

마지막으로 열 개수가 많았기 때문에 차원 축소(열 개수를 줄이는 과정)를 합니다.

차원 축소를 하면 시각화 하기에 더 용이하고, 군집화 또한 더 나은 결과를 확인할 수 있습니다.


from sklearn.manifold import TSNE

import matplotlib.pyplot as plt

import seaborn as sns

tsne = TSNE(n_components=2, perplexity=20, random_state=42)

tsne_result = tsne.fit_transform(df_review_dtm)

df_tsne = pd.DataFrame(tsne_result, columns=['x', 'y'])

df_tsne['review'] = cleaned_CONTENT_list

df_tsne['label'] = clusters

plt.figure(figsize=(18, 10))

sns.scatterplot(data=df_tsne, x='x', y='y', hue='label', palette='Set1');

for i in df_tsne.index:

    plt.text(x=df_tsne.loc[i, 'x'], y=df_tsne.loc[i, 'y'], s=df_tsne.loc[i, 'review'])

df_tsne.to_excel('tsne_results.xlsx', index=False)


'n_components=2'는 '열 개수를 2개로 축소할게'라고 선언 하는 것과 같습니다.

'perplexity=20'은 '데이터포인트(여기서는 리뷰 데이터)가 군집화 할 때 범위를 고려하는 값'이라고 생각하면 됩니다. 수가 더 높아지면 군집화 시 고려하는 범위가 넓어지고, 수가 적어지면 범위가 더 줄어듭니다.


참고로 10~50이 적은 숫자 범위에 해당하며, 그 이상은 비교적 높은 숫자 범위에 해당한다고 보면 됩니다. 딱 정해진 값은 없기 때문에, 데이터 크기에 따라 해당 값을 조절 하면 됩니다.

'df_tsne.index'는 행 인덱스가 0부터 시작합니다. 해당 코드를 이용해서 반복문을 작성합니다. 반복문을 이용하면, 데이터포인트 옆에 텍스트를 보이게 할 수 있습니다.

plt.text()는 데이터포인트에 텍스트를 보이게 만드는 매서드입니다. 인자로 사용한 x와 y는 말 그대로 x축과 y축을 뜻합니다.


그리고 s에는 텍스트 데이터를 포함해 줍니다. 'review'에 텍스트 데이터가 담겨 있기 때문에, 위와 같이 코드를 작성했습니다.

'df_tsne.to_excel('tsne_results.xlsx', index=False)'는 'df_tsne' 결과 값을 엑셀 파일로 만드는 코드입니다.

엑셀 파일로 변환하면, 외부 데이터 시각화 툴을 이용해서 보다 나은 데이터 시각화를 진행해 볼 수도 있습니다.


7. 파이썬을 활용한 고객 리뷰 분석 결론

  • 비슷한 텍스트에는 어떤 게 있는지 확인할 수 있습니다.

  • 패턴으로 인식 되지 않은 텍스트는 어떤 게 있는지 확인할 수 있습니다.


각 패턴에 맞게끔 리뷰가 적절히 군집화 되었습니다.

만약 군집화가 제대로 되어지지 않았다고 생각 들면, perplexity 값을 조절해 보는 것도 방법입니다.

정봉준

Jung Bong Jun

mgz.less@gamil.com

© Copyright 2024

정봉준

Jung Bong Jun

mgz.less@gamil.com

© Copyright 2024

정봉준

Jung Bong Jun

mgz.less@gamil.com

© Copyright 2024