Tripadvisor(호텔), Edmunds.com(자동차), Amazon.com(전자제품) 사이트에서 가져온 리뷰 문서
각 문서는 100개 정도의 문장을 가짐
[In]
add check point ! 1. glob 함수 2. python에서 string 앞에 r을 표기해 주면 string literal → raw string으로 변경시켜줌(https://armin.tistory.com/279) 3. pd.set_option('max_colwidth', 500) : 표시되는 DataFrame의 셀 넓이 최대값 설정
import pandas as pd
import glob, os
path = r'C:\Users\norii\Documents\DataScience\source\DL\0731\OpinosisDataset\topics' #string literal -> raw literal
all_files = glob.glob(os.path.join(path, "*.data"))
filename_list = []
opinion_text = []
for file_ in all_files:
#개별 파일 읽어서 DataFrame으로 생성
#https://docs.python.org/3/library/codecs.html#standard-encodings
df = pd.read_table(file_, index_col=None, header=0, encoding='latin1')
#절대 경로로 주어진 file명을 가공, 맨 마지막 .data 확장자 제거
filename_ = file_.split('\\')[-1]
filename = filename_.split('.')[0]
filename_list.append(filename)
opinion_text.append(df.to_string()) #데이터 객체를 단순 string 형태로 변형하는 메서드
pd.set_option('max_colwidth',500) #판다스 셀 넓이 옵션
#파일 리스트, 리뷰에 대한 DataFrame
document_df = pd.DataFrame({'filename': filename_list, 'opinion_text': opinion_text})
document_df.head()
[Out]
filename
opinion_text
accuracy_garmin_nuvi_255W_gps
, and is very, very accurate .\n0 but for the most part, we find that t...
bathroom_bestwestern_hotel_sfo
The room was not overly big, but clean and very comfortable beds, a great shower and very clean bathrooms .\n0 ...
battery-life_amazon_kindle
After I plugged it in to my USB hub on my computer to charge the battery the charging cord design is very clever !\n0 After you have paged tru a 500, page book...
battery-life_ipod_nano_8gb
short battery life I moved up from an 8gb .\n0 ...
battery-life_netbook_1005ha
6GHz 533FSB cpu, glossy display, 3, Cell 23Wh Li, ion Battery , and a 1 .\n0 ...
2. Lemmatization(표제어 추출)을 위한 함수 생성
정규화 기법 중 코퍼스에 있는 단어의 개수를 줄일 수 있는 기법 표제어 추출(lemmatization)과 어간 추출(stemming)이 있음
NLTK에서는 표제어 추출을 위한 도구인 WordNetLemmatizer를 지원함 (참고사이트)
[In]
add check point ! 1. string.punctuation : string 패키지의 메소드 따옴표,마침표 물음표 등등 이런류의 문장부호(!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~) 2. dict() : 3. ord() :하나의 문자를 인자로 받고 해당 문자에 해당하는 유니코드 정수를 반환 4. translate() : 문자열에서 문자를 제거하는 하나의 방법 (예시) developer = 'Jessica Wilkins' print(developer.translate({ord('i'): None})) Jessca Wlkns
from nltk.stem import WordNetLemmatizer
import nltk
import string
remove_punct_dict = dict((ord(punct), None) for punct in string.punctuation)
print(remove_punct_dict)
#단어 원형 추출 함수
lemmar = WordNetLemmatizer()
def LemTokens(tokens):
return [lemmar.lemmatize(token) for token in tokens]
#텍스트 소문자로 변경 후 특수문자 제거
def LemNormalize(text):
return LemTokens(nltk.word_tokenize(text.lower().translate(remove_punct_dict)))
from sklearn.feature_extraction.text import TfidfVectorizer
#LemNormalize : 특수 문자 제거 및 단어 원형 추출
tfidf_vect = TfidfVectorizer(tokenizer = LemNormalize, stop_words ='english', ngram_range=(1,2), min_df=0.05, max_df=0.85)
#opinion_text 칼럼값으로 feature vectorization 수행
feature_vect = tfidf_vect.fit_transform(document_df['opinion_text'])
feature_vect.shape
[Out]
(51, 4611)
#51개 문서, 4611개 피처
4-1. 군집화 - try #1
[In] KMeans 군집화(5개)
from sklearn.cluster import KMeans
#5개 집합으로 군집화 수행, 예제를 위해 동일한 클러스터링 결과 도출용 random_state=0
km_cluster = KMeans(n_clusters=5, max_iter=10000, random_state=0)
km_cluster.fit(feature_vect) #51개 문서, 4611개 피처
cluster_label = km_cluster.labels_
cluster_centers = km_cluster.cluster_centers
print(km_cluster.labels_)
print(km_cluster.labels_.shape) # 51개 문서
[Out]
[2 0 1 1 1 2 4 4 2 2 2 2 2 3 3 3 4 4 4 1 3 3 4 2 3 4 1 3 3 4 0 0 0 2 2 2 2
4 3 3 3 1 1 2 1 3 3 4 2 2 2]
(51,)
#문서의 유형은 크게 전자제품, 자동차, 호텔로 구성됨
#전자 제품 - 네비게이션, 아이팟, 킨들, 랩탑 컴퓨터 등과 같은 세부 요소로 나뉨
#5개의 군집(Centroid) 으로 K-Means군집화
[In] 군집화된 그룹별로 데이터 확인
document_df['cluster_label'] = cluster_label
document_df.head()
#cluster #0은 호텔에 대한 리뷰로 군집화
#cluster #1은 킨들, 아이팟, 넷북 등의 포터블 전자기기에 대한 리뷰로 군집화
#cluster #2은 킨들, 아이팟, 넷북이 군집에 포함되어 있지만, 주로 차량용 네비게이션으로 군집이 구성
#cluster #3은 킨들 리뷰가 한개 섞여 있지만 #0과 같이 대부분 호텔에 대한 리뷰로 군집화되어 있음
#cluster #4은 토요타(Toyota)와 혼다(Honda) 등의 자동차에 대한 리뷰로 잘 군집화 되어 있음
[Out]
4-2. 군집화 - try #2
[In] KMeans 군집화(3개)
#3개 집합으로 군집화 수행
km_cluster = KMeans(n_clusters=3, max_iter=10000, random_state=0)
km_cluster.fit(feature_vect)
cluster_label = km_cluster.labels_
#소속 클러스터를 cluster_label 칼럼으로 할당하고 cluster_label값으로 정렬
document_df['cluster_label'] = cluster_label
document_df.sort_values(by='cluster_label').head()
# Cluster #0은 포터블 전자기기 리뷰로만 군집화
# Cluster #1 자동차 리뷰로만 군집
# Cluster #2 호텔 리뷰로만 군집이 잘 구성됨을 알 수 있다.
[Out]
5. 군집별 핵심단어 추출하기
각 군집을 구성하는 핵심 단어가 어떤 것인지 확인
KMeans객체의 cluster_centers_ 속성 : 개별 피처들의 클러스터 중심과의 상대 위치를 정규화된 숫자값으로 표시
[In] 군집별 top n 핵심단어, 그 단어의 중심 위치 상대값, 대상 파일명들을 반환하는 함수 생성
# 군집별 top n 핵심단어, 그 단어의 중심 위치 상대값, 대상 파일명들을 반환함.
def get_cluster_details(cluster_model, cluster_data, feature_names, clusters_num, top_n_features=10):
cluster_details = {}
# cluster_centers array 의 값이 큰 순으로 정렬된 index 값을 반환
centroid_feature_ordered_ind = cluster_model.cluster_centers_.argsort()[:,::-1]
#개별 군집별로 iteration하면서 핵심단어, 그 단어의 중심 위치 상대값, 대상 파일명 입력
for cluster_num in range(clusters_num):
# 개별 군집별 정보를 담을 데이터 초기화.
cluster_details[cluster_num] = {}
cluster_details[cluster_num]['cluster'] = cluster_num
# cluster_centers_.argsort()[:,::-1] 로 구한 index 를 이용하여 top n 피처 단어를 구함.
top_feature_indexes = centroid_feature_ordered_ind[cluster_num, :top_n_features]
top_features = [ feature_names[ind] for ind in top_feature_indexes ]
# top_feature_indexes를 이용해 해당 피처 단어의 중심 위치 상댓값 구함
top_feature_values = cluster_model.cluster_centers_[cluster_num, top_feature_indexes].tolist()
# cluster_details 딕셔너리 객체에 개별 군집별 핵심 단어와 중심위치 상대값, 그리고 해당 파일명 입력
cluster_details[cluster_num]['top_features'] = top_features
cluster_details[cluster_num]['top_features_value'] = top_feature_values
filenames = cluster_data[cluster_data['cluster_label'] == cluster_num]['filename']
filenames = filenames.values.tolist()
cluster_details[cluster_num]['filenames'] = filenames
return cluster_details